From 848193074a10d9799ffbc27918a8b264a2e101bb Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 16 Nov 2018 15:21:04 -0800 Subject: feat: close and open instant based on history changes --- packages/instant/src/index.umd.ts | 51 +++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 13 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 0274db30c..81b7aebe3 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -5,6 +5,7 @@ import * as ReactDOM from 'react-dom'; import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID } from './constants'; import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { assert } from './util/assert'; +import { util } from './util/util'; export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { assert.isValidOrderSource('orderSource', props.orderSource); @@ -36,21 +37,45 @@ export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFA assert.isWeb3Provider('props.provider', props.provider); } assert.isString('selector', selector); - const appendToIfExists = document.querySelector(selector); - assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`); - const appendTo = appendToIfExists as Element; - const injectedDiv = document.createElement('div'); - injectedDiv.setAttribute('id', INJECTED_DIV_ID); - injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); - appendTo.appendChild(injectedDiv); - const instantOverlayProps = { - ...props, - onClose: () => { - appendTo.removeChild(injectedDiv); + // Render instant and return a callback that allows you to close it. + const renderInstant = () => { + const appendToIfExists = document.querySelector(selector); + assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`); + const appendTo = appendToIfExists as Element; + const injectedDiv = document.createElement('div'); + injectedDiv.setAttribute('id', INJECTED_DIV_ID); + injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); + appendTo.appendChild(injectedDiv); + const instantOverlayProps = { + ...props, + onClose: () => window.history.back(), + }; + ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); + const close = () => appendTo.removeChild(injectedDiv); + return close; + }; + // Before we render, push to history saying that instant is showing for this part of the history. + window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); + let closeInstant = renderInstant(); + + let prevOnPopState = util.boundNoop; + if (window.onpopstate) { + prevOnPopState = window.onpopstate.bind(window); + } + window.onpopstate = (e: PopStateEvent) => { + // Don't override integrators handler. + prevOnPopState(e); + // e.state represents the new state + if (e.state && e.state.zeroExInstantShowing) { + // The user pressed fowards, so re-render instant. + closeInstant = renderInstant(); + } else { + // User pressed back, so close instant. + closeInstant(); + delete window.onpopstate; if (!_.isUndefined(props.onClose)) { props.onClose(); } - }, + } }; - ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); }; -- cgit v1.2.3 From f7914af9c564d4521e375fb3dd5825da763df7d6 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 16 Nov 2018 15:23:44 -0800 Subject: feat: rename props to config --- packages/instant/src/index.umd.ts | 50 +++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 81b7aebe3..fda21478f 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -7,34 +7,38 @@ import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { assert } from './util/assert'; import { util } from './util/util'; -export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { - assert.isValidOrderSource('orderSource', props.orderSource); - if (!_.isUndefined(props.defaultSelectedAssetData)) { - assert.isHexString('defaultSelectedAssetData', props.defaultSelectedAssetData); +export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { + shouldUseHistoryApi?: boolean; +} + +export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { + assert.isValidOrderSource('orderSource', config.orderSource); + if (!_.isUndefined(config.defaultSelectedAssetData)) { + assert.isHexString('defaultSelectedAssetData', config.defaultSelectedAssetData); } - if (!_.isUndefined(props.additionalAssetMetaDataMap)) { - assert.isValidAssetMetaDataMap('props.additionalAssetMetaDataMap', props.additionalAssetMetaDataMap); + if (!_.isUndefined(config.additionalAssetMetaDataMap)) { + assert.isValidAssetMetaDataMap('props.additionalAssetMetaDataMap', config.additionalAssetMetaDataMap); } - if (!_.isUndefined(props.defaultAssetBuyAmount)) { - assert.isNumber('props.defaultAssetBuyAmount', props.defaultAssetBuyAmount); + if (!_.isUndefined(config.defaultAssetBuyAmount)) { + assert.isNumber('props.defaultAssetBuyAmount', config.defaultAssetBuyAmount); } - if (!_.isUndefined(props.networkId)) { - assert.isNumber('props.networkId', props.networkId); + if (!_.isUndefined(config.networkId)) { + assert.isNumber('props.networkId', config.networkId); } - if (!_.isUndefined(props.availableAssetDatas)) { - assert.areValidAssetDatas('availableAssetDatas', props.availableAssetDatas); + if (!_.isUndefined(config.availableAssetDatas)) { + assert.areValidAssetDatas('availableAssetDatas', config.availableAssetDatas); } - if (!_.isUndefined(props.onClose)) { - assert.isFunction('props.onClose', props.onClose); + if (!_.isUndefined(config.onClose)) { + assert.isFunction('props.onClose', config.onClose); } - if (!_.isUndefined(props.zIndex)) { - assert.isNumber('props.zIndex', props.zIndex); + if (!_.isUndefined(config.zIndex)) { + assert.isNumber('props.zIndex', config.zIndex); } - if (!_.isUndefined(props.affiliateInfo)) { - assert.isValidAffiliateInfo('props.affiliateInfo', props.affiliateInfo); + if (!_.isUndefined(config.affiliateInfo)) { + assert.isValidAffiliateInfo('props.affiliateInfo', config.affiliateInfo); } - if (!_.isUndefined(props.provider)) { - assert.isWeb3Provider('props.provider', props.provider); + if (!_.isUndefined(config.provider)) { + assert.isWeb3Provider('props.provider', config.provider); } assert.isString('selector', selector); // Render instant and return a callback that allows you to close it. @@ -47,7 +51,7 @@ export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFA injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); appendTo.appendChild(injectedDiv); const instantOverlayProps = { - ...props, + ...config, onClose: () => window.history.back(), }; ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); @@ -73,8 +77,8 @@ export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFA // User pressed back, so close instant. closeInstant(); delete window.onpopstate; - if (!_.isUndefined(props.onClose)) { - props.onClose(); + if (!_.isUndefined(config.onClose)) { + config.onClose(); } } }; -- cgit v1.2.3 From 9a53a29b1f421cdea190b6175dec437ec6d76a39 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 16 Nov 2018 15:41:21 -0800 Subject: feat: allow integrator to disable pushstate logic --- packages/instant/src/index.umd.ts | 54 +++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index fda21478f..381c9094b 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -8,7 +8,7 @@ import { assert } from './util/assert'; import { util } from './util/util'; export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { - shouldUseHistoryApi?: boolean; + shouldDisablePushToHistory?: boolean; } export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { @@ -50,36 +50,40 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z injectedDiv.setAttribute('id', INJECTED_DIV_ID); injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); appendTo.appendChild(injectedDiv); + const close = () => appendTo.removeChild(injectedDiv); const instantOverlayProps = { ...config, - onClose: () => window.history.back(), + // If we are using the history API, just go back to close + onClose: () => (config.shouldDisablePushToHistory ? close() : window.history.back()), }; ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); - const close = () => appendTo.removeChild(injectedDiv); return close; }; - // Before we render, push to history saying that instant is showing for this part of the history. - window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); - let closeInstant = renderInstant(); + if (config.shouldDisablePushToHistory) { + renderInstant(); + } else { + // Before we render, push to history saying that instant is showing for this part of the history. + window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); + let closeInstant = renderInstant(); - let prevOnPopState = util.boundNoop; - if (window.onpopstate) { - prevOnPopState = window.onpopstate.bind(window); - } - window.onpopstate = (e: PopStateEvent) => { - // Don't override integrators handler. - prevOnPopState(e); - // e.state represents the new state - if (e.state && e.state.zeroExInstantShowing) { - // The user pressed fowards, so re-render instant. - closeInstant = renderInstant(); - } else { - // User pressed back, so close instant. - closeInstant(); - delete window.onpopstate; - if (!_.isUndefined(config.onClose)) { - config.onClose(); - } + let prevOnPopState = util.boundNoop; + if (window.onpopstate) { + prevOnPopState = window.onpopstate.bind(window); } - }; + window.onpopstate = (e: PopStateEvent) => { + // Don't override integrators handler. + prevOnPopState(e); + // e.state represents the new state + if (e.state && e.state.zeroExInstantShowing) { + // The user pressed fowards, so re-render instant. + closeInstant = renderInstant(); + } else { + // User pressed back, so close instant. + closeInstant(); + if (!_.isUndefined(config.onClose)) { + config.onClose(); + } + } + }; + } }; -- cgit v1.2.3 From a4f6cd21bd289eb2baaee8b6b7d09cbb9e0955dc Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 16 Nov 2018 15:45:02 -0800 Subject: feat: be more specific with callback name --- packages/instant/src/index.umd.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 381c9094b..298b7733f 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -41,7 +41,7 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z assert.isWeb3Provider('props.provider', config.provider); } assert.isString('selector', selector); - // Render instant and return a callback that allows you to close it. + // Render instant and return a callback that allows you to remove it from the DOM. const renderInstant = () => { const appendToIfExists = document.querySelector(selector); assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`); @@ -50,21 +50,21 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z injectedDiv.setAttribute('id', INJECTED_DIV_ID); injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); appendTo.appendChild(injectedDiv); - const close = () => appendTo.removeChild(injectedDiv); + const removeFromDom = () => appendTo.removeChild(injectedDiv); const instantOverlayProps = { ...config, // If we are using the history API, just go back to close - onClose: () => (config.shouldDisablePushToHistory ? close() : window.history.back()), + onClose: () => (config.shouldDisablePushToHistory ? removeFromDom() : window.history.back()), }; ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); - return close; + return removeFromDom; }; if (config.shouldDisablePushToHistory) { renderInstant(); } else { // Before we render, push to history saying that instant is showing for this part of the history. window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); - let closeInstant = renderInstant(); + let removeInstant = renderInstant(); let prevOnPopState = util.boundNoop; if (window.onpopstate) { @@ -76,10 +76,10 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z // e.state represents the new state if (e.state && e.state.zeroExInstantShowing) { // The user pressed fowards, so re-render instant. - closeInstant = renderInstant(); + removeInstant = renderInstant(); } else { // User pressed back, so close instant. - closeInstant(); + removeInstant(); if (!_.isUndefined(config.onClose)) { config.onClose(); } -- cgit v1.2.3 From 51dce3008841b7bdc9080212f8b5e12a90f6cce9 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 16 Nov 2018 15:48:55 -0800 Subject: feat: add assert for shouldDisablePushToHistory --- packages/instant/src/index.umd.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 298b7733f..9703c6fc0 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -17,28 +17,31 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z assert.isHexString('defaultSelectedAssetData', config.defaultSelectedAssetData); } if (!_.isUndefined(config.additionalAssetMetaDataMap)) { - assert.isValidAssetMetaDataMap('props.additionalAssetMetaDataMap', config.additionalAssetMetaDataMap); + assert.isValidAssetMetaDataMap('additionalAssetMetaDataMap', config.additionalAssetMetaDataMap); } if (!_.isUndefined(config.defaultAssetBuyAmount)) { - assert.isNumber('props.defaultAssetBuyAmount', config.defaultAssetBuyAmount); + assert.isNumber('defaultAssetBuyAmount', config.defaultAssetBuyAmount); } if (!_.isUndefined(config.networkId)) { - assert.isNumber('props.networkId', config.networkId); + assert.isNumber('networkId', config.networkId); } if (!_.isUndefined(config.availableAssetDatas)) { assert.areValidAssetDatas('availableAssetDatas', config.availableAssetDatas); } if (!_.isUndefined(config.onClose)) { - assert.isFunction('props.onClose', config.onClose); + assert.isFunction('onClose', config.onClose); } if (!_.isUndefined(config.zIndex)) { - assert.isNumber('props.zIndex', config.zIndex); + assert.isNumber('zIndex', config.zIndex); } if (!_.isUndefined(config.affiliateInfo)) { - assert.isValidAffiliateInfo('props.affiliateInfo', config.affiliateInfo); + assert.isValidAffiliateInfo('affiliateInfo', config.affiliateInfo); } if (!_.isUndefined(config.provider)) { - assert.isWeb3Provider('props.provider', config.provider); + assert.isWeb3Provider('provider', config.provider); + } + if (!_.isUndefined(config.shouldDisablePushToHistory)) { + assert.isBoolean('shouldDisablePushToHistory', config.shouldDisablePushToHistory); } assert.isString('selector', selector); // Render instant and return a callback that allows you to remove it from the DOM. -- cgit v1.2.3 From 654c13df8aee2e43992c6629d2249d56667fec67 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 16 Nov 2018 16:07:37 -0800 Subject: fix: bug where we did not call onClose config --- packages/instant/src/index.umd.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 9703c6fc0..518326e21 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -53,14 +53,19 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z injectedDiv.setAttribute('id', INJECTED_DIV_ID); injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); appendTo.appendChild(injectedDiv); - const removeFromDom = () => appendTo.removeChild(injectedDiv); + const closeInstant = () => { + if (config.onClose) { + config.onClose(); + } + appendTo.removeChild(injectedDiv); + }; const instantOverlayProps = { ...config, // If we are using the history API, just go back to close - onClose: () => (config.shouldDisablePushToHistory ? removeFromDom() : window.history.back()), + onClose: () => (config.shouldDisablePushToHistory ? closeInstant() : window.history.back()), }; ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); - return removeFromDom; + return closeInstant; }; if (config.shouldDisablePushToHistory) { renderInstant(); @@ -83,9 +88,6 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z } else { // User pressed back, so close instant. removeInstant(); - if (!_.isUndefined(config.onClose)) { - config.onClose(); - } } }; } -- cgit v1.2.3 From ac942faa258f604f4f6171759f6bcdf786317d29 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 16 Nov 2018 16:14:10 -0800 Subject: chore: use lodash where relevant --- packages/instant/src/index.umd.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 518326e21..34d893ad7 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -54,7 +54,7 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); appendTo.appendChild(injectedDiv); const closeInstant = () => { - if (config.onClose) { + if (!_.isUndefined(config.onClose)) { config.onClose(); } appendTo.removeChild(injectedDiv); -- cgit v1.2.3 From 9384c507ac29043d0d2f68bef3dde94a43282d09 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 16 Nov 2018 16:33:02 -0800 Subject: feat: add isInstantRendered check to safeguard against double renders and double removes --- packages/instant/src/index.umd.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 34d893ad7..64f888e00 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -68,7 +68,9 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z return closeInstant; }; if (config.shouldDisablePushToHistory) { - renderInstant(); + if (!isInstantRendered()) { + renderInstant(); + } } else { // Before we render, push to history saying that instant is showing for this part of the history. window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); @@ -83,12 +85,18 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z prevOnPopState(e); // e.state represents the new state if (e.state && e.state.zeroExInstantShowing) { - // The user pressed fowards, so re-render instant. - removeInstant = renderInstant(); + // We have returned to a history state that expects instant to be rendered. + if (!isInstantRendered()) { + removeInstant = renderInstant(); + } } else { - // User pressed back, so close instant. - removeInstant(); + // History has changed to a different state. + if (isInstantRendered()) { + removeInstant(); + } } }; } }; + +const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); -- cgit v1.2.3 From 6de499459cb29f74cabd91c441f85e4c2325a6d7 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 19 Nov 2018 17:10:47 -0800 Subject: fix: do not use document on import --- packages/instant/src/components/zero_ex_instant_provider.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 8be53ee20..ac246128c 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -19,8 +19,6 @@ import { Heartbeater } from '../util/heartbeater'; import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory'; import { providerStateFactory } from '../util/provider_state_factory'; -fonts.include(); - export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps & Partial; @@ -86,6 +84,7 @@ export class ZeroExInstantProvider extends React.Component Date: Tue, 20 Nov 2018 10:19:59 -0800 Subject: fix(instant): Autofocus text amount input --- packages/instant/src/components/erc20_asset_amount_input.tsx | 1 + packages/instant/src/components/scaling_amount_input.tsx | 3 +++ packages/instant/src/components/scaling_input.tsx | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index 520ac33d5..8b4494022 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -62,6 +62,7 @@ export class ERC20AssetAmountInput extends React.Component void; onFontSizeChange: (fontSizePx: number) => void; + autofocus: boolean; } interface ScalingAmountInputState { stringValue: string; @@ -29,6 +30,7 @@ export class ScalingAmountInput extends React.Component ); } diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index e1599a316..c379b76cd 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -28,6 +28,7 @@ export interface ScalingInputProps { maxLength?: number; scalingSettings: ScalingSettings; isDisabled: boolean; + autofocus: boolean; } export interface ScalingInputState { @@ -51,6 +52,7 @@ export class ScalingInput extends React.Component ); } -- cgit v1.2.3 From cd4600b081b9ee467471174fe6736efab6247759 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 20 Nov 2018 10:20:16 -0800 Subject: fix(instant): Right align amounts --- packages/instant/src/components/instant_heading.tsx | 4 ++-- packages/instant/src/components/ui/text.tsx | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 002695269..ace577824 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -107,7 +107,7 @@ export class InstantHeading extends React.Component { private readonly _renderEthAmount = (): React.ReactNode => { return ( - + {format.ethBaseUnitAmount( this.props.totalEthBaseUnitAmount, 4, @@ -119,7 +119,7 @@ export class InstantHeading extends React.Component { private readonly _renderDollarAmount = (): React.ReactNode => { return ( - + {format.ethBaseUnitAmountInUsd( this.props.totalEthBaseUnitAmount, this.props.ethUsdPrice, diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx index fd14cc4d1..8e573d7b9 100644 --- a/packages/instant/src/components/ui/text.tsx +++ b/packages/instant/src/components/ui/text.tsx @@ -11,6 +11,7 @@ export interface TextProps { fontSize?: string; opacity?: number; letterSpacing?: string; + textAlign?: string; textTransform?: string; lineHeight?: string; className?: string; @@ -22,6 +23,7 @@ export interface TextProps { noWrap?: boolean; display?: string; href?: string; + width?: string; } export const Text: React.StatelessComponent = ({ href, onClick, ...rest }) => { @@ -51,6 +53,8 @@ export const StyledText = ${props => (props.display ? `display: ${props.display}` : '')}; ${props => (props.letterSpacing ? `letter-spacing: ${props.letterSpacing}` : '')}; ${props => (props.textTransform ? `text-transform: ${props.textTransform}` : '')}; + ${props => (props.textAlign ? `text-align: ${props.textAlign}` : '')}; + ${props => (props.width ? `width: ${props.width}` : '')}; &:hover { ${props => props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''}; -- cgit v1.2.3 From 2bda6dd719d748a4bfa5ff8e23e97924e0258af1 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 20 Nov 2018 10:36:23 -0800 Subject: autofocus -> hasAutoFocus --- packages/instant/src/components/erc20_asset_amount_input.tsx | 2 +- packages/instant/src/components/scaling_amount_input.tsx | 6 +++--- packages/instant/src/components/scaling_input.tsx | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index 8b4494022..ab8c019c7 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -62,7 +62,7 @@ export class ERC20AssetAmountInput extends React.Component void; onFontSizeChange: (fontSizePx: number) => void; - autofocus: boolean; + hasAutofocus: boolean; } interface ScalingAmountInputState { stringValue: string; @@ -30,7 +30,7 @@ export class ScalingAmountInput extends React.Component ); } diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index c379b76cd..129162a74 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -28,7 +28,7 @@ export interface ScalingInputProps { maxLength?: number; scalingSettings: ScalingSettings; isDisabled: boolean; - autofocus: boolean; + hasAutofocus: boolean; } export interface ScalingInputState { @@ -52,7 +52,7 @@ export class ScalingInput extends React.Component ); } -- cgit v1.2.3 From 728617fed2fee99b2accdcf6d2ddc9036c9ad266 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 20 Nov 2018 12:06:10 -0800 Subject: feat(instant): Report errors to rollbar --- .../src/components/zero_ex_instant_container.tsx | 3 + packages/instant/src/constants.ts | 7 +++ packages/instant/src/util/error_reporter.ts | 68 ++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 packages/instant/src/util/error_reporter.ts (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 47c938472..6d7cef7fd 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -12,12 +12,15 @@ import { SelectedAssetInstantHeading } from '../containers/selected_asset_instan import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; import { OrderProcessState, SlideAnimationState } from '../types'; +import { setupRollbar } from '../util/error_reporter'; import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; +setupRollbar(); + export interface ZeroExInstantContainerProps { orderProcessState: OrderProcessState; } diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index be6077ca9..23660360d 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -20,6 +20,13 @@ export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; +export const ROLLBAR_CLIENT_TOKEN = process.env.ROLLBAR_CLIENT_TOKEN; +export const ROLLBAR_ENVIRONMENT = process.env.ROLLBAR_ENVIRONMENT as + | 'dogfood' + | 'staging' + | 'development' + | 'production' + | undefined; export const COINBASE_WALLET_IOS_APP_STORE_URL = 'https://itunes.apple.com/us/app/coinbase-wallet/id1278383455?mt=8'; export const COINBASE_WALLET_ANDROID_APP_STORE_URL = 'https://play.google.com/store/apps/details?id=org.toshi&hl=en'; export const COINBASE_WALLET_SITE_URL = 'https://wallet.coinbase.com/'; diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts new file mode 100644 index 000000000..81a90e7f5 --- /dev/null +++ b/packages/instant/src/util/error_reporter.ts @@ -0,0 +1,68 @@ +import { logUtils } from '@0x/utils'; + +import { ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENVIRONMENT } from '../constants'; + +// Import version of Rollbar designed for embedded components +// See https://docs.rollbar.com/docs/using-rollbarjs-inside-an-embedded-component +// tslint:disable-next-line:no-var-requires +const Rollbar = require('rollbar/dist/rollbar.noconflict.umd'); + +const shouldAllowRollbar = () => { + if (ROLLBAR_ENVIRONMENT === 'development') { + return process.env.ROLLBAR_FORCE_DEVELOPMENT_REPORT ? true : false; + } + return true; +}; + +let rollbar: any; +if (ROLLBAR_CLIENT_TOKEN && ROLLBAR_ENVIRONMENT && shouldAllowRollbar()) { + rollbar = new Rollbar({ + accessToken: ROLLBAR_CLIENT_TOKEN, + captureUncaught: true, + captureUnhandledRejections: true, + enabled: true, + itemsPerMinute: 10, + maxItems: 500, + payload: { + environment: ROLLBAR_ENVIRONMENT, + client: { + javascript: { + source_map_enabled: true, + code_version: process.env.GIT_SHA, + guess_uncaught_frames: true, + }, + }, + }, + uncaughtErrorLevel: 'error', + ignoredMessages: [ + // Errors from the third-party scripts + 'Script error', + // Network errors or ad-blockers + 'TypeError: Failed to fetch', + 'Exchange has not been deployed to detected network (network/artifact mismatch)', + // Source: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/7VU0_VvC7mE + "undefined is not an object (evaluating '__gCrWeb.autofill.extractForms')", + // Source: http://stackoverflow.com/questions/43399818/securityerror-from-facebook-and-cross-domain-messaging + 'SecurityError (DOM Exception 18)', + ], + }); +} + +export const setupRollbar = (): any => { + return rollbar as any; +}; + +export const errorReporter = { + report(err: Error): void { + if (!rollbar) { + logUtils.log('Not reporting to rollbar because not configured', err); + return; + } + + rollbar.error(err, (rollbarErr: Error) => { + if (rollbarErr) { + logUtils.log(`Error reporting to rollbar, ignoring: ${rollbarErr}`); + } + }); + }, +}; -- cgit v1.2.3 From 934570d12fae9c67ae18fc914577f02a51af3bca Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 20 Nov 2018 13:18:47 -0800 Subject: Explicit error reporting --- packages/instant/src/redux/async_data.ts | 3 +++ packages/instant/src/util/buy_quote_updater.ts | 4 +++- packages/instant/src/util/gas_price_estimator.ts | 5 ++++- packages/instant/src/util/heap.ts | 3 ++- 4 files changed, 12 insertions(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 5d30388b8..29d441c75 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -9,6 +9,7 @@ import { assetUtils } from '../util/asset'; import { buyQuoteUpdater } from '../util/buy_quote_updater'; import { coinbaseApi } from '../util/coinbase_api'; import { errorFlasher } from '../util/error_flasher'; +import { errorReporter } from '../util/error_reporter'; import { actions } from './actions'; import { State } from './reducer'; @@ -22,6 +23,7 @@ export const asyncData = { const errorMessage = 'Error fetching ETH/USD price'; errorFlasher.flashNewErrorMessage(dispatch, errorMessage); dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO)); + errorReporter.report(e); } }, fetchAvailableAssetDatasAndDispatchToStore: async (state: State, dispatch: Dispatch) => { @@ -36,6 +38,7 @@ export const asyncData = { errorFlasher.flashNewErrorMessage(dispatch, errorMessage); // On error, just specify that none are available dispatch(actions.setAvailableAssets([])); + errorReporter.report(e); } }, fetchAccountInfoAndDispatchToStore: async ( diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 2fd16d781..6cb5e41b6 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -9,6 +9,7 @@ import { Action, actions } from '../redux/actions'; import { AffiliateInfo, ERC20Asset } from '../types'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; +import { errorReporter } from '../util/error_reporter'; export const buyQuoteUpdater = { updateBuyQuoteAsync: async ( @@ -49,8 +50,9 @@ export const buyQuoteUpdater = { } else { throw error; } + } else { + errorReporter.report(error); } - // TODO: report to error reporter on else return; } diff --git a/packages/instant/src/util/gas_price_estimator.ts b/packages/instant/src/util/gas_price_estimator.ts index 6b15809a3..332c8d00a 100644 --- a/packages/instant/src/util/gas_price_estimator.ts +++ b/packages/instant/src/util/gas_price_estimator.ts @@ -7,6 +7,8 @@ import { GWEI_IN_WEI, } from '../constants'; +import { errorReporter } from './error_reporter'; + interface EthGasStationResult { average: number; fastestWait: number; @@ -42,8 +44,9 @@ export class GasPriceEstimator { let fetchedAmount: GasInfo | undefined; try { fetchedAmount = await fetchFastAmountInWeiAsync(); - } catch { + } catch (e) { fetchedAmount = undefined; + errorReporter.report(e); } if (fetchedAmount) { diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 78ec3b3cc..10670b278 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -5,6 +5,7 @@ import * as _ from 'lodash'; import { HEAP_ANALYTICS_ID } from '../constants'; import { AnalyticsEventOptions, AnalyticsUserOptions } from './analytics'; +import { errorReporter } from './error_reporter'; export interface HeapAnalytics { loaded: boolean; @@ -105,8 +106,8 @@ export const heapUtil = { heapFunctionCall(curHeap); } catch (e) { // We never want analytics to crash our React component - // TODO(sk): error reporter here logUtils.log('Analytics error', e); + errorReporter.report(e); } } }, -- cgit v1.2.3 From 094aabfcee8828eb5c5ba452edda306ef04757ce Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 20 Nov 2018 13:28:28 -0800 Subject: Linting --- packages/instant/src/util/error_reporter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts index 81a90e7f5..a03b5e65e 100644 --- a/packages/instant/src/util/error_reporter.ts +++ b/packages/instant/src/util/error_reporter.ts @@ -49,7 +49,7 @@ if (ROLLBAR_CLIENT_TOKEN && ROLLBAR_ENVIRONMENT && shouldAllowRollbar()) { } export const setupRollbar = (): any => { - return rollbar as any; + return rollbar; }; export const errorReporter = { -- cgit v1.2.3 From 6124d80c89e7c8e4b1d00a934f2389d2b4461c44 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 20 Nov 2018 14:59:23 -0800 Subject: Move out generating of event properties, and send in orderSource --- .../src/components/zero_ex_instant_provider.tsx | 9 +-------- packages/instant/src/util/analytics.ts | 23 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 9435d8c7c..37ed3dc94 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -126,14 +126,7 @@ export class ZeroExInstantProvider extends React.Component { @@ -59,6 +63,25 @@ export const analytics = { heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); }); }, + generateEventProperties: (state: State, window: Window): AnalyticsEventOptions => { + let orderSource = 'unknown'; + const orderProvider = state.providerState.assetBuyer.orderProvider; + if (orderProvider instanceof StandardRelayerAPIOrderProvider) { + orderSource = orderProvider.apiUrl; + } else if (orderProvider instanceof BasicOrderProvider) { + orderSource = 'provided'; + } + + return { + embeddedHost: window.location.host, + embeddedUrl: window.location.href, + networkId: state.network, + providerName: state.providerState.name, + gitSha: process.env.GIT_SHA, + npmVersion: process.env.NPM_PACKAGE_VERSION, + orderSource, + }; + }, trackWalletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), }; -- cgit v1.2.3 From 1593b94aacd69a9c48c04a13d696c4c0bede4d58 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 20 Nov 2018 15:07:37 -0800 Subject: feat(instant): Add more event properties to heap --- packages/instant/src/util/analytics.ts | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index d790ec1e7..a18532bfa 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -51,6 +51,8 @@ export interface AnalyticsEventOptions { gitSha?: string; npmVersion?: string; orderSource?: string; + affiliateAddress?: string; + affiliateFeePercent?: number; } export const analytics = { addUserProperties: (properties: AnalyticsUserOptions): void => { @@ -72,6 +74,8 @@ export const analytics = { orderSource = 'provided'; } + const affiliateAddress = state.affiliateInfo ? state.affiliateInfo.feeRecipient : 'none'; + const affiliateFeePercent = state.affiliateInfo ? parseFloat(state.affiliateInfo.feePercentage.toFixed(4)) : 0; return { embeddedHost: window.location.host, embeddedUrl: window.location.href, @@ -80,6 +84,8 @@ export const analytics = { gitSha: process.env.GIT_SHA, npmVersion: process.env.NPM_PACKAGE_VERSION, orderSource, + affiliateAddress, + affiliateFeePercent, }; }, trackWalletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), -- cgit v1.2.3 From 351e0e6f5f2add25c4d779356a8cfd4aefb305cb Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 20 Nov 2018 22:34:57 -0800 Subject: feat(instant): implement account related events --- .../containers/connected_account_payment_method.ts | 8 +++-- packages/instant/src/redux/analytics_middleware.ts | 34 ++++++++++++---------- packages/instant/src/redux/async_data.ts | 2 ++ packages/instant/src/util/analytics.ts | 13 +++++++-- 4 files changed, 37 insertions(+), 20 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/containers/connected_account_payment_method.ts b/packages/instant/src/containers/connected_account_payment_method.ts index eacbadfca..cdeb49a25 100644 --- a/packages/instant/src/containers/connected_account_payment_method.ts +++ b/packages/instant/src/containers/connected_account_payment_method.ts @@ -12,6 +12,7 @@ import { Action, actions } from '../redux/actions'; import { asyncData } from '../redux/async_data'; import { State } from '../redux/reducer'; import { Network, Omit, OperatingSystem, ProviderState, StandardSlidingPanelContent } from '../types'; +import { analytics } from '../util/analytics'; import { envUtil } from '../util/env'; export interface ConnectedAccountPaymentMethodProps {} @@ -40,8 +41,11 @@ const mapDispatchToProps = ( ownProps: ConnectedAccountPaymentMethodProps, ): ConnectedDispatch => ({ openInstallWalletPanel: () => dispatch(actions.openStandardSlidingPanel(StandardSlidingPanelContent.InstallWallet)), - unlockWalletAndDispatchToStore: async (providerState: ProviderState) => - asyncData.fetchAccountInfoAndDispatchToStore(providerState, dispatch, true), + unlockWalletAndDispatchToStore: (providerState: ProviderState) => { + analytics.trackAccountUnlockRequested(); + // tslint:disable-next-line:no-floating-promises + asyncData.fetchAccountInfoAndDispatchToStore(providerState, dispatch, true); + }, }); const mergeProps = ( diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index f971dbd33..893844f5d 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -10,20 +10,6 @@ import { Action, ActionTypes } from './actions'; import { State } from './reducer'; -const shouldTriggerWalletReady = (prevAccount: Account, curAccount: Account): boolean => { - const didJustTurnReady = curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready; - if (didJustTurnReady) { - return true; - } - - if (curAccount.state === AccountState.Ready && prevAccount.state === AccountState.Ready) { - // Account was ready, and is now ready again, but address has changed - return curAccount.address !== prevAccount.address; - } - - return false; -}; - export const analyticsMiddleware: Middleware = store => next => middlewareAction => { const prevState = store.getState() as State; const prevAccount = prevState.providerState.account; @@ -35,10 +21,26 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction switch (nextAction.type) { case ActionTypes.SET_ACCOUNT_STATE_READY: - if (curAccount.state === AccountState.Ready && shouldTriggerWalletReady(prevAccount, curAccount)) { + if (prevAccount.state !== AccountState.Ready && curAccount.state === AccountState.Ready) { + // if we are moving from account not ready to account ready, update the current address and track `Account - Ready` const ethAddress = curAccount.address; analytics.addUserProperties({ ethAddress }); - analytics.trackWalletReady(); + analytics.trackAccountReady(ethAddress); + } else if (prevAccount.state === AccountState.Ready && curAccount.state === AccountState.Ready) { + if (prevAccount.address !== curAccount.address) { + // if our account state was already ready and our address has changed, update the current address and track `Account - Address Changed` + const ethAddress = curAccount.address; + analytics.addUserProperties({ ethAddress }); + analytics.trackAccountAddressChanged(ethAddress); + } + } + break; + case ActionTypes.SET_ACCOUNT_STATE_LOCKED: + if (prevAccount.state !== AccountState.Locked && curAccount.state === AccountState.Locked) { + // if we are moving from account not locked to account locked, update the current address to undefined and track `Account - Locked` + const ethAddress = undefined; + analytics.addUserProperties({ ethAddress }); + analytics.trackAccountLocked(); } break; case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 5d30388b8..6feb760e7 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -5,6 +5,7 @@ import { Dispatch } from 'redux'; import { BIG_NUMBER_ZERO } from '../constants'; import { AccountState, ERC20Asset, OrderProcessState, ProviderState } from '../types'; +import { analytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { buyQuoteUpdater } from '../util/buy_quote_updater'; import { coinbaseApi } from '../util/coinbase_api'; @@ -58,6 +59,7 @@ export const asyncData = { ? await (provider as any).enable() : await web3Wrapper.getAvailableAddressesAsync(); } catch (e) { + analytics.trackAccountUnlockDenied(); dispatch(actions.setAccountStateLocked()); return; } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 2ffaac1dd..d36bf8fc3 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -15,7 +15,11 @@ export const evaluateIfEnabled = (fnCall: () => void) => { enum EventNames { INSTANT_OPENED = 'Instant - Opened', - WALLET_READY = 'Wallet - Ready', + ACCOUNT_LOCKED = 'Account - Locked', + ACCOUNT_READY = 'Account - Ready', + ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested', + ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', + ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', } const track = (eventName: EventNames, eventData: ObjectMap = {}): void => { evaluateIfEnabled(() => { @@ -59,6 +63,11 @@ export const analytics = { heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); }); }, - trackWalletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), + trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED), + trackAccountReady: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ address }), + trackAccountUnlockRequested: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_REQUESTED), + trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), + trackAccountAddressChanged: (address: string) => + trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), }; -- cgit v1.2.3 From e0beb7fb380e50e4566db4787092f5549a2d6db1 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 21 Nov 2018 11:42:07 -0500 Subject: feat: add more to instant dev env --- packages/instant/src/index.umd.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 59f658b33..1d62084b5 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -7,6 +7,7 @@ import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { assert } from './util/assert'; import { util } from './util/util'; +const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { shouldDisablePushToHistory?: boolean; } @@ -43,8 +44,8 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z if (!_.isUndefined(config.shouldDisablePushToHistory)) { assert.isBoolean('shouldDisablePushToHistory', config.shouldDisablePushToHistory); } - if (!_.isUndefined(props.shouldDisableAnalyticsTracking)) { - assert.isBoolean('props.shouldDisableAnalyticsTracking', props.shouldDisableAnalyticsTracking); + if (!_.isUndefined(config.shouldDisableAnalyticsTracking)) { + assert.isBoolean('shouldDisableAnalyticsTracking', config.shouldDisableAnalyticsTracking); } assert.isString('selector', selector); // Render instant and return a callback that allows you to remove it from the DOM. @@ -101,5 +102,3 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z }; } }; - -const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); -- cgit v1.2.3 From b494a4a4dba6c781667b690f38387f03a22fe141 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 21 Nov 2018 11:55:32 -0500 Subject: chore: clean up index.umd.ts a bit --- packages/instant/src/index.umd.ts | 70 +++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 32 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 1d62084b5..15ca59323 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -8,11 +8,8 @@ import { assert } from './util/assert'; import { util } from './util/util'; const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); -export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { - shouldDisablePushToHistory?: boolean; -} -export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { +const validateInstantRenderConfig = (config: ZeroExInstantConfig, selector: string) => { assert.isValidOrderSource('orderSource', config.orderSource); if (!_.isUndefined(config.defaultSelectedAssetData)) { assert.isHexString('defaultSelectedAssetData', config.defaultSelectedAssetData); @@ -48,37 +45,46 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z assert.isBoolean('shouldDisableAnalyticsTracking', config.shouldDisableAnalyticsTracking); } assert.isString('selector', selector); - // Render instant and return a callback that allows you to remove it from the DOM. - const renderInstant = () => { - const appendToIfExists = document.querySelector(selector); - assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`); - const appendTo = appendToIfExists as Element; - const injectedDiv = document.createElement('div'); - injectedDiv.setAttribute('id', INJECTED_DIV_ID); - injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); - appendTo.appendChild(injectedDiv); - const closeInstant = () => { - if (!_.isUndefined(config.onClose)) { - config.onClose(); - } - appendTo.removeChild(injectedDiv); - }; - const instantOverlayProps = { - ...config, - // If we are using the history API, just go back to close - onClose: () => (config.shouldDisablePushToHistory ? closeInstant() : window.history.back()), - }; - ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); - return closeInstant; +}; + +// Render instant and return a callback that allows you to remove it from the DOM. +const renderInstant = (config: ZeroExInstantConfig, selector: string) => { + const appendToIfExists = document.querySelector(selector); + assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`); + const appendTo = appendToIfExists as Element; + const injectedDiv = document.createElement('div'); + injectedDiv.setAttribute('id', INJECTED_DIV_ID); + injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); + appendTo.appendChild(injectedDiv); + const closeInstant = () => { + if (!_.isUndefined(config.onClose)) { + config.onClose(); + } + appendTo.removeChild(injectedDiv); + }; + const instantOverlayProps = { + ...config, + // If we are using the history API, just go back to close + onClose: () => (config.shouldDisablePushToHistory ? closeInstant() : window.history.back()), }; + ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); + return closeInstant; +}; + +export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { + shouldDisablePushToHistory?: boolean; +} + +export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { + validateInstantRenderConfig(config, selector); if (config.shouldDisablePushToHistory) { if (!isInstantRendered()) { - renderInstant(); + renderInstant(config, selector); } } else { // Before we render, push to history saying that instant is showing for this part of the history. window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); - let removeInstant = renderInstant(); + let removeInstant = renderInstant(config, selector); let prevOnPopState = util.boundNoop; if (window.onpopstate) { @@ -86,12 +92,12 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z } window.onpopstate = (e: PopStateEvent) => { // Don't override integrators handler. - prevOnPopState(e); - // e.state represents the new state - if (e.state && e.state.zeroExInstantShowing) { + // prevOnPopState(e); + const newState = e.state; + if (newState && newState.zeroExInstantShowing) { // We have returned to a history state that expects instant to be rendered. if (!isInstantRendered()) { - removeInstant = renderInstant(); + removeInstant = renderInstant(config, selector); } } else { // History has changed to a different state. -- cgit v1.2.3 From 35b505114842b8c8eac838fff8588adf17f54b45 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 21 Nov 2018 09:23:19 -0800 Subject: Always report unexpected errors. Move error message generation into helper function, and add tests --- packages/instant/src/util/asset.ts | 17 +++++++++++++++ packages/instant/src/util/buy_quote_updater.ts | 29 +++++++------------------- 2 files changed, 25 insertions(+), 21 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 40560d3eb..08f3642e3 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -1,3 +1,4 @@ +import { AssetBuyerError } from '@0x/asset-buyer'; import { AssetProxyId, ObjectMap } from '@0x/types'; import * as _ from 'lodash'; @@ -106,4 +107,20 @@ export const assetUtils = { ); return _.compact(erc20sOrUndefined); }, + assetBuyerErrorMessage: (asset: ERC20Asset, error: Error): string | undefined => { + if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { + const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); + return `Not enough ${assetName} available`; + } else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) { + return 'Not enough ZRX available'; + } else if ( + error.message === AssetBuyerError.StandardRelayerApiError || + error.message.startsWith(AssetBuyerError.AssetUnavailable) + ) { + const assetName = assetUtils.bestNameForAsset(asset, 'This asset'); + return `${assetName} is currently unavailable`; + } + + return undefined; + }, }; diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 6cb5e41b6..4f97622e1 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -30,30 +30,17 @@ export const buyQuoteUpdater = { try { newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage }); } catch (error) { - if (options.dispatchErrors) { - dispatch(actions.setQuoteRequestStateFailure()); - let errorMessage; - if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { - const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); - errorMessage = `Not enough ${assetName} available`; - } else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) { - errorMessage = 'Not enough ZRX available'; - } else if ( - error.message === AssetBuyerError.StandardRelayerApiError || - error.message.startsWith(AssetBuyerError.AssetUnavailable) - ) { - const assetName = assetUtils.bestNameForAsset(asset, 'This asset'); - errorMessage = `${assetName} is currently unavailable`; - } - if (!_.isUndefined(errorMessage)) { - errorFlasher.flashNewErrorMessage(dispatch, errorMessage); - } else { - throw error; - } - } else { + const errorMessage = assetUtils.assetBuyerErrorMessage(asset, error); + + if (_.isUndefined(errorMessage)) { + // This is an unknown error, report it to rollbar errorReporter.report(error); } + if (options.dispatchErrors) { + dispatch(actions.setQuoteRequestStateFailure()); + errorFlasher.flashNewErrorMessage(dispatch, errorMessage || 'Error fetching price, please try again'); + } return; } // We have a successful new buy quote -- cgit v1.2.3 From 22a31246622e7139185d080cae9bef275087e245 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 21 Nov 2018 09:35:24 -0800 Subject: Move rollbar setup into function, move setting up into provider --- .../src/components/zero_ex_instant_container.tsx | 3 - .../src/components/zero_ex_instant_provider.tsx | 2 + packages/instant/src/util/error_reporter.ts | 66 +++++++++++----------- 3 files changed, 35 insertions(+), 36 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 6d7cef7fd..47c938472 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -12,15 +12,12 @@ import { SelectedAssetInstantHeading } from '../containers/selected_asset_instan import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; import { OrderProcessState, SlideAnimationState } from '../types'; -import { setupRollbar } from '../util/error_reporter'; import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; -setupRollbar(); - export interface ZeroExInstantContainerProps { orderProcessState: OrderProcessState; } diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 9435d8c7c..00d3e95b2 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -15,11 +15,13 @@ import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from import { analytics, disableAnalytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; +import { setupRollbar } from '../util/error_reporter'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { Heartbeater } from '../util/heartbeater'; import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory'; import { providerStateFactory } from '../util/provider_state_factory'; +setupRollbar(); fonts.include(); export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps & diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts index a03b5e65e..c5766b469 100644 --- a/packages/instant/src/util/error_reporter.ts +++ b/packages/instant/src/util/error_reporter.ts @@ -1,4 +1,5 @@ import { logUtils } from '@0x/utils'; +import * as _ from 'lodash'; import { ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENVIRONMENT } from '../constants'; @@ -15,41 +16,40 @@ const shouldAllowRollbar = () => { }; let rollbar: any; -if (ROLLBAR_CLIENT_TOKEN && ROLLBAR_ENVIRONMENT && shouldAllowRollbar()) { - rollbar = new Rollbar({ - accessToken: ROLLBAR_CLIENT_TOKEN, - captureUncaught: true, - captureUnhandledRejections: true, - enabled: true, - itemsPerMinute: 10, - maxItems: 500, - payload: { - environment: ROLLBAR_ENVIRONMENT, - client: { - javascript: { - source_map_enabled: true, - code_version: process.env.GIT_SHA, - guess_uncaught_frames: true, +// Configures rollbar and sets up error catching +export const setupRollbar = (): any => { + if (_.isUndefined(rollbar) && ROLLBAR_CLIENT_TOKEN && ROLLBAR_ENVIRONMENT && shouldAllowRollbar()) { + rollbar = new Rollbar({ + accessToken: ROLLBAR_CLIENT_TOKEN, + captureUncaught: true, + captureUnhandledRejections: true, + enabled: true, + itemsPerMinute: 10, + maxItems: 500, + payload: { + environment: ROLLBAR_ENVIRONMENT, + client: { + javascript: { + source_map_enabled: true, + code_version: process.env.GIT_SHA, + guess_uncaught_frames: true, + }, }, }, - }, - uncaughtErrorLevel: 'error', - ignoredMessages: [ - // Errors from the third-party scripts - 'Script error', - // Network errors or ad-blockers - 'TypeError: Failed to fetch', - 'Exchange has not been deployed to detected network (network/artifact mismatch)', - // Source: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/7VU0_VvC7mE - "undefined is not an object (evaluating '__gCrWeb.autofill.extractForms')", - // Source: http://stackoverflow.com/questions/43399818/securityerror-from-facebook-and-cross-domain-messaging - 'SecurityError (DOM Exception 18)', - ], - }); -} - -export const setupRollbar = (): any => { - return rollbar; + uncaughtErrorLevel: 'error', + ignoredMessages: [ + // Errors from the third-party scripts + 'Script error', + // Network errors or ad-blockers + 'TypeError: Failed to fetch', + 'Exchange has not been deployed to detected network (network/artifact mismatch)', + // Source: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/7VU0_VvC7mE + "undefined is not an object (evaluating '__gCrWeb.autofill.extractForms')", + // Source: http://stackoverflow.com/questions/43399818/securityerror-from-facebook-and-cross-domain-messaging + 'SecurityError (DOM Exception 18)', + ], + }); + } }; export const errorReporter = { -- cgit v1.2.3 From 70c99082496bbaed5b5ccc37bb259c0a9f02fab5 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 21 Nov 2018 09:43:01 -0800 Subject: Report when cant update balance --- packages/instant/src/redux/async_data.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 29d441c75..5382494f2 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -78,6 +78,7 @@ export const asyncData = { const ethBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(address); dispatch(actions.updateAccountEthBalance({ address, ethBalanceInWei })); } catch (e) { + errorReporter.report(e); // leave balance as is return; } -- cgit v1.2.3 From ed91c6c874282ab069a72784b8e563b634a236bf Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 21 Nov 2018 12:44:28 -0500 Subject: fix: multiple render and closes edge case for onpopstate render --- packages/instant/src/index.umd.ts | 52 ++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 25 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 15ca59323..3a8694d6a 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -81,30 +81,32 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z if (!isInstantRendered()) { renderInstant(config, selector); } - } else { - // Before we render, push to history saying that instant is showing for this part of the history. - window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); - let removeInstant = renderInstant(config, selector); - - let prevOnPopState = util.boundNoop; - if (window.onpopstate) { - prevOnPopState = window.onpopstate.bind(window); - } - window.onpopstate = (e: PopStateEvent) => { - // Don't override integrators handler. - // prevOnPopState(e); - const newState = e.state; - if (newState && newState.zeroExInstantShowing) { - // We have returned to a history state that expects instant to be rendered. - if (!isInstantRendered()) { - removeInstant = renderInstant(config, selector); - } - } else { - // History has changed to a different state. - if (isInstantRendered()) { - removeInstant(); - } - } - }; + return; + } + // Before we render, push to history saying that instant is showing for this part of the history. + window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); + let removeInstant = renderInstant(config, selector); + // If the integrator defined a popstate handler, save it to __zeroExInstantIntegratorsPopStateHandler + // unless we have already done so on a previous render. + const anyWindow = window as any; + if (window.onpopstate && !anyWindow.__zeroExInstantIntegratorsPopStateHandler) { + anyWindow.__zeroExInstantIntegratorsPopStateHandler = window.onpopstate.bind(window); } + const integratorsOnPopStateHandler = anyWindow.__zeroExInstantIntegratorsPopStateHandler || util.boundNoop; + const onPopStateHandler = (e: PopStateEvent) => { + integratorsOnPopStateHandler(e); + const newState = e.state; + if (newState && newState.zeroExInstantShowing) { + // We have returned to a history state that expects instant to be rendered. + if (!isInstantRendered()) { + removeInstant = renderInstant(config, selector); + } + } else { + // History has changed to a different state. + if (isInstantRendered()) { + removeInstant(); + } + } + }; + window.onpopstate = onPopStateHandler; }; -- cgit v1.2.3 From e2a16f3f336c6787501c6a2366e7793a135009f8 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 21 Nov 2018 10:25:10 -0800 Subject: Use ROLLBAR_ENABLED constant, and change ROLLBAR_ENVIRONMENT to INSTANT_ENVIRONMENT --- packages/instant/src/constants.ts | 3 ++- packages/instant/src/util/error_reporter.ts | 13 +++---------- 2 files changed, 5 insertions(+), 11 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 23660360d..dfa7520f8 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -21,12 +21,13 @@ export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; export const ROLLBAR_CLIENT_TOKEN = process.env.ROLLBAR_CLIENT_TOKEN; -export const ROLLBAR_ENVIRONMENT = process.env.ROLLBAR_ENVIRONMENT as +export const INSTANT_ENVIRONMENT = process.env.INSTANT_ENVIRONMENT as | 'dogfood' | 'staging' | 'development' | 'production' | undefined; +export const ROLLBAR_ENABLED = process.env.ROLLBAR_ENABLED; export const COINBASE_WALLET_IOS_APP_STORE_URL = 'https://itunes.apple.com/us/app/coinbase-wallet/id1278383455?mt=8'; export const COINBASE_WALLET_ANDROID_APP_STORE_URL = 'https://play.google.com/store/apps/details?id=org.toshi&hl=en'; export const COINBASE_WALLET_SITE_URL = 'https://wallet.coinbase.com/'; diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts index c5766b469..89c5b6bd3 100644 --- a/packages/instant/src/util/error_reporter.ts +++ b/packages/instant/src/util/error_reporter.ts @@ -1,24 +1,17 @@ import { logUtils } from '@0x/utils'; import * as _ from 'lodash'; -import { ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENVIRONMENT } from '../constants'; +import { INSTANT_ENVIRONMENT, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants'; // Import version of Rollbar designed for embedded components // See https://docs.rollbar.com/docs/using-rollbarjs-inside-an-embedded-component // tslint:disable-next-line:no-var-requires const Rollbar = require('rollbar/dist/rollbar.noconflict.umd'); -const shouldAllowRollbar = () => { - if (ROLLBAR_ENVIRONMENT === 'development') { - return process.env.ROLLBAR_FORCE_DEVELOPMENT_REPORT ? true : false; - } - return true; -}; - let rollbar: any; // Configures rollbar and sets up error catching export const setupRollbar = (): any => { - if (_.isUndefined(rollbar) && ROLLBAR_CLIENT_TOKEN && ROLLBAR_ENVIRONMENT && shouldAllowRollbar()) { + if (_.isUndefined(rollbar) && ROLLBAR_CLIENT_TOKEN && INSTANT_ENVIRONMENT && ROLLBAR_ENABLED) { rollbar = new Rollbar({ accessToken: ROLLBAR_CLIENT_TOKEN, captureUncaught: true, @@ -27,7 +20,7 @@ export const setupRollbar = (): any => { itemsPerMinute: 10, maxItems: 500, payload: { - environment: ROLLBAR_ENVIRONMENT, + environment: INSTANT_ENVIRONMENT, client: { javascript: { source_map_enabled: true, -- cgit v1.2.3 From 93672c01afd19f07daa89934fc8d29caefbec2f6 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 21 Nov 2018 10:54:10 -0800 Subject: Linting --- packages/instant/src/util/buy_quote_updater.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 4f97622e1..172b50d2a 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -1,4 +1,4 @@ -import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer'; +import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; -- cgit v1.2.3 From d750225554a0c4c317863cf11a7db5b1570e5b41 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 21 Nov 2018 08:20:09 -0800 Subject: Send in explicit props --- .../src/components/zero_ex_instant_provider.tsx | 10 +++++++- packages/instant/src/util/analytics.ts | 30 ++++++++++------------ 2 files changed, 23 insertions(+), 17 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 37ed3dc94..dc6a45a23 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -126,7 +126,15 @@ export class ZeroExInstantProvider extends React.Component heap.addEventProperties(properties)); }); }, - generateEventProperties: (state: State, window: Window): AnalyticsEventOptions => { - let orderSource = 'unknown'; - const orderProvider = state.providerState.assetBuyer.orderProvider; - if (orderProvider instanceof StandardRelayerAPIOrderProvider) { - orderSource = orderProvider.apiUrl; - } else if (orderProvider instanceof BasicOrderProvider) { - orderSource = 'provided'; - } - - const affiliateAddress = state.affiliateInfo ? state.affiliateInfo.feeRecipient : 'none'; - const affiliateFeePercent = state.affiliateInfo ? parseFloat(state.affiliateInfo.feePercentage.toFixed(4)) : 0; + generateEventProperties: ( + network: Network, + orderSource: OrderSource, + providerState: ProviderState, + window: Window, + affiliateInfo?: AffiliateInfo, + ): AnalyticsEventOptions => { + const affiliateAddress = affiliateInfo ? affiliateInfo.feeRecipient : 'none'; + const affiliateFeePercent = affiliateInfo ? parseFloat(affiliateInfo.feePercentage.toFixed(4)) : 0; + const orderSourceName = typeof orderSource === 'string' ? orderSource : 'provided'; return { embeddedHost: window.location.host, embeddedUrl: window.location.href, - networkId: state.network, - providerName: state.providerState.name, + networkId: network, + providerName: providerState.name, gitSha: process.env.GIT_SHA, npmVersion: process.env.NPM_PACKAGE_VERSION, - orderSource, + orderSource: orderSourceName, affiliateAddress, affiliateFeePercent, }; -- cgit v1.2.3 From 31d1b4ba670d25c4cd4ed93d32d12718b4804e5d Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 21 Nov 2018 12:30:52 -0800 Subject: chore(instant): refactor account tracking logic in middleware to be more readable --- packages/instant/src/redux/analytics_middleware.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 893844f5d..889cc875e 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -21,17 +21,17 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction switch (nextAction.type) { case ActionTypes.SET_ACCOUNT_STATE_READY: - if (prevAccount.state !== AccountState.Ready && curAccount.state === AccountState.Ready) { - // if we are moving from account not ready to account ready, update the current address and track `Account - Ready` + if (curAccount.state === AccountState.Ready) { + const didJustTurnReady = prevAccount.state !== AccountState.Ready; + const didJustUpdateAddress = + prevAccount.state === AccountState.Ready && prevAccount.address !== curAccount.address; const ethAddress = curAccount.address; - analytics.addUserProperties({ ethAddress }); - analytics.trackAccountReady(ethAddress); - } else if (prevAccount.state === AccountState.Ready && curAccount.state === AccountState.Ready) { - if (prevAccount.address !== curAccount.address) { - // if our account state was already ready and our address has changed, update the current address and track `Account - Address Changed` - const ethAddress = curAccount.address; + if (didJustTurnReady) { + analytics.trackAccountReady(ethAddress); analytics.addUserProperties({ ethAddress }); + } else if (didJustUpdateAddress) { analytics.trackAccountAddressChanged(ethAddress); + analytics.addUserProperties({ ethAddress }); } } break; -- cgit v1.2.3 From 6604e2db20d6263e05b00cf5d36b56788e42d9c2 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 21 Nov 2018 12:44:28 -0800 Subject: chore(instant): refactor usage of event properties in heap --- packages/instant/src/redux/analytics_middleware.ts | 12 ++++---- packages/instant/src/util/analytics.ts | 32 ++++++++++++---------- packages/instant/src/util/heap.ts | 4 ++- 3 files changed, 26 insertions(+), 22 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 889cc875e..931902187 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -27,19 +27,17 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction prevAccount.state === AccountState.Ready && prevAccount.address !== curAccount.address; const ethAddress = curAccount.address; if (didJustTurnReady) { - analytics.trackAccountReady(ethAddress); - analytics.addUserProperties({ ethAddress }); + analytics.trackAccountReady({ address: ethAddress }); + analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); } else if (didJustUpdateAddress) { - analytics.trackAccountAddressChanged(ethAddress); - analytics.addUserProperties({ ethAddress }); + analytics.trackAccountAddressChanged({ address: ethAddress }); + analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); } } break; case ActionTypes.SET_ACCOUNT_STATE_LOCKED: if (prevAccount.state !== AccountState.Locked && curAccount.state === AccountState.Locked) { - // if we are moving from account not locked to account locked, update the current address to undefined and track `Account - Locked` - const ethAddress = undefined; - analytics.addUserProperties({ ethAddress }); + // if we are moving from account not locked to account locked, track `Account - Locked` analytics.trackAccountLocked(); } break; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index d36bf8fc3..31233fe7a 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,6 +1,4 @@ -import { ObjectMap } from '@0x/types'; - -import { heapUtil } from './heap'; +import { EventProperties, heapUtil } from './heap'; let isDisabled = false; export const disableAnalytics = (shouldDisableAnalytics: boolean) => { @@ -21,9 +19,9 @@ enum EventNames { ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', } -const track = (eventName: EventNames, eventData: ObjectMap = {}): void => { +const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { evaluateIfEnabled(() => { - heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventData)); + heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventProperties)); }); }; function trackingEventFnWithoutPayload(eventName: EventNames): () => void { @@ -32,16 +30,14 @@ function trackingEventFnWithoutPayload(eventName: EventNames): () => void { }; } // tslint:disable-next-line:no-unused-variable -function trackingEventFnWithPayload>( - eventName: EventNames, -): (eventDataProperties: T) => void { - return (eventDataProperties: T) => { - track(eventName, eventDataProperties); +function trackingEventFnWithPayload(eventName: EventNames): (eventProperties: EventProperties) => void { + return (eventProperties: EventProperties) => { + track(eventName, eventProperties); }; } export interface AnalyticsUserOptions { - ethAddress?: string; + lastKnownEthAddress?: string; ethBalanceInUnitAmount?: string; } export interface AnalyticsEventOptions { @@ -52,6 +48,13 @@ export interface AnalyticsEventOptions { gitSha?: string; npmVersion?: string; } +export interface AccountReadyEventProperties { + address: string; +} +export interface AccountAddressChangedEventProperties { + address: string; +} + export const analytics = { addUserProperties: (properties: AnalyticsUserOptions): void => { evaluateIfEnabled(() => { @@ -65,9 +68,10 @@ export const analytics = { }, trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED), - trackAccountReady: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ address }), + trackAccountReady: (eventProperties: AccountReadyEventProperties) => + trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ ...eventProperties }), trackAccountUnlockRequested: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_REQUESTED), trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), - trackAccountAddressChanged: (address: string) => - trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), + trackAccountAddressChanged: (eventProperties: AccountAddressChangedEventProperties) => + trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ ...eventProperties }), }; diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 78ec3b3cc..7c53c9918 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -6,11 +6,13 @@ import { HEAP_ANALYTICS_ID } from '../constants'; import { AnalyticsEventOptions, AnalyticsUserOptions } from './analytics'; +export type EventProperties = ObjectMap; + export interface HeapAnalytics { loaded: boolean; appid: string; identify(id: string, idType: string): void; - track(eventName: string, eventProperties?: ObjectMap): void; + track(eventName: string, eventProperties?: EventProperties): void; resetIdentity(): void; addUserProperties(properties: AnalyticsUserOptions): void; addEventProperties(properties: AnalyticsEventOptions): void; -- cgit v1.2.3 From c6ae7b8d3f720f637db2d5ec9abee14cc00fb7a7 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 21 Nov 2018 13:19:26 -0800 Subject: Host whitelist so we don't get errors from embedded site --- packages/instant/src/constants.ts | 9 +++++++++ packages/instant/src/util/error_reporter.ts | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index dfa7520f8..eb785bc2b 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -20,6 +20,15 @@ export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; +export const EMBEDDED_DOMAINS = [ + '0x-instant-staging.s3-website-us-east-1.amazonaws.com', + '0x-instant-dogfood.s3-website-us-east-1.amazonaws.com', + 'localhost', + '127.0.0.1', + '0.0.0.0', + 'unpkg.com', + 'jsdelivr.com', +]; export const ROLLBAR_CLIENT_TOKEN = process.env.ROLLBAR_CLIENT_TOKEN; export const INSTANT_ENVIRONMENT = process.env.INSTANT_ENVIRONMENT as | 'dogfood' diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts index 89c5b6bd3..c0ef3e30e 100644 --- a/packages/instant/src/util/error_reporter.ts +++ b/packages/instant/src/util/error_reporter.ts @@ -1,7 +1,7 @@ import { logUtils } from '@0x/utils'; import * as _ from 'lodash'; -import { INSTANT_ENVIRONMENT, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants'; +import { EMBEDDED_DOMAINS, INSTANT_ENVIRONMENT, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants'; // Import version of Rollbar designed for embedded components // See https://docs.rollbar.com/docs/using-rollbarjs-inside-an-embedded-component @@ -29,6 +29,7 @@ export const setupRollbar = (): any => { }, }, }, + hostWhiteList: EMBEDDED_DOMAINS, uncaughtErrorLevel: 'error', ignoredMessages: [ // Errors from the third-party scripts -- cgit v1.2.3 From 804de89796de047fe43dbb736b5e8b82bb30ee3a Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 21 Nov 2018 13:40:23 -0800 Subject: chore(instant): revert usage of event properties --- packages/instant/src/redux/analytics_middleware.ts | 4 ++-- packages/instant/src/util/analytics.ts | 13 +++---------- 2 files changed, 5 insertions(+), 12 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 931902187..299c2560e 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -27,10 +27,10 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction prevAccount.state === AccountState.Ready && prevAccount.address !== curAccount.address; const ethAddress = curAccount.address; if (didJustTurnReady) { - analytics.trackAccountReady({ address: ethAddress }); + analytics.trackAccountReady(ethAddress); analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); } else if (didJustUpdateAddress) { - analytics.trackAccountAddressChanged({ address: ethAddress }); + analytics.trackAccountAddressChanged(ethAddress); analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); } } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 31233fe7a..e389e1530 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -48,12 +48,6 @@ export interface AnalyticsEventOptions { gitSha?: string; npmVersion?: string; } -export interface AccountReadyEventProperties { - address: string; -} -export interface AccountAddressChangedEventProperties { - address: string; -} export const analytics = { addUserProperties: (properties: AnalyticsUserOptions): void => { @@ -68,10 +62,9 @@ export const analytics = { }, trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED), - trackAccountReady: (eventProperties: AccountReadyEventProperties) => - trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ ...eventProperties }), + trackAccountReady: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ address }), trackAccountUnlockRequested: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_REQUESTED), trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), - trackAccountAddressChanged: (eventProperties: AccountAddressChangedEventProperties) => - trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ ...eventProperties }), + trackAccountAddressChanged: (address: string) => + trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), }; -- cgit v1.2.3 From 10c9d0b723ba190a7f1c4df112ae0c5b37887bb9 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 21 Nov 2018 14:24:13 -0800 Subject: Force scaling input component to rerender when a different asset is chosen --- packages/instant/src/components/erc20_asset_amount_input.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index 0706833d2..b734af61a 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -65,6 +65,7 @@ export class ERC20AssetAmountInput extends React.Component Date: Wed, 21 Nov 2018 14:33:12 -0800 Subject: Add comment --- packages/instant/src/components/erc20_asset_amount_input.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index b734af61a..ff900842a 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -65,6 +65,7 @@ export class ERC20AssetAmountInput extends React.Component -- cgit v1.2.3 From 717a3bce8cd0d4cb782918b3ad806f6c1bdb825e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 09:12:51 -0800 Subject: EMBEDDED_DOMAINS -> HOST_DOMAINS --- packages/instant/src/constants.ts | 2 +- packages/instant/src/util/error_reporter.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index eb785bc2b..677510a8b 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -20,7 +20,7 @@ export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; -export const EMBEDDED_DOMAINS = [ +export const HOST_DOMAINS = [ '0x-instant-staging.s3-website-us-east-1.amazonaws.com', '0x-instant-dogfood.s3-website-us-east-1.amazonaws.com', 'localhost', diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts index c0ef3e30e..8e21c8881 100644 --- a/packages/instant/src/util/error_reporter.ts +++ b/packages/instant/src/util/error_reporter.ts @@ -1,7 +1,7 @@ import { logUtils } from '@0x/utils'; import * as _ from 'lodash'; -import { EMBEDDED_DOMAINS, INSTANT_ENVIRONMENT, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants'; +import { HOST_DOMAINS, INSTANT_ENVIRONMENT, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants'; // Import version of Rollbar designed for embedded components // See https://docs.rollbar.com/docs/using-rollbarjs-inside-an-embedded-component @@ -29,7 +29,7 @@ export const setupRollbar = (): any => { }, }, }, - hostWhiteList: EMBEDDED_DOMAINS, + hostWhiteList: HOST_DOMAINS, uncaughtErrorLevel: 'error', ignoredMessages: [ // Errors from the third-party scripts -- cgit v1.2.3 From 2fec7613c408a046c130f4c5817696ab3b5e3928 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 13:20:16 -0800 Subject: Token Selector open, closed, chose --- packages/instant/src/components/zero_ex_instant_container.tsx | 3 +++ packages/instant/src/redux/analytics_middleware.ts | 9 +++++++++ packages/instant/src/util/analytics.ts | 7 +++++++ 3 files changed, 19 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 47c938472..f30bda6ed 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -12,6 +12,7 @@ import { SelectedAssetInstantHeading } from '../containers/selected_asset_instan import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; import { OrderProcessState, SlideAnimationState } from '../types'; +import { analytics } from '../util/analytics'; import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; @@ -82,11 +83,13 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon ); } private readonly _handleSymbolClick = (): void => { + analytics.trackTokenSelectorOpened(); this.setState({ tokenSelectionPanelAnimationState: 'slidIn', }); }; private readonly _handlePanelClose = (): void => { + analytics.trackTokenSelectorClosed(); this.setState({ tokenSelectionPanelAnimationState: 'slidOut', }); diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 299c2560e..1a8aefb38 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -53,6 +53,15 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction ).toString(); analytics.addUserProperties({ ethBalanceInUnitAmount }); } + break; + case ActionTypes.UPDATE_SELECTED_ASSET: + if (curState.selectedAsset) { + analytics.trackTokenSelectorChose({ + assetName: curState.selectedAsset.metaData.name, + assetData: curState.selectedAsset.assetData, + }); + } + break; } return nextAction; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e389e1530..50bab174f 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -18,6 +18,9 @@ enum EventNames { ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested', ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', + TOKEN_SELECTOR_OPENED = 'Token Selector - Opened', + TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed', + TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose', } const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { evaluateIfEnabled(() => { @@ -67,4 +70,8 @@ export const analytics = { trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), trackAccountAddressChanged: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), + trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED), + trackTokenSelectorClosed: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_CLOSED), + trackTokenSelectorChose: (payload: { assetName: string; assetData: string }) => + trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload), }; -- cgit v1.2.3 From 9206f2d288f33367877d2d557d50f1d485d4b92e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 13:26:29 -0800 Subject: Token selector searched --- packages/instant/src/components/erc20_token_selector.tsx | 2 ++ packages/instant/src/util/analytics.ts | 3 +++ 2 files changed, 5 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 1b1921acb..0a3d4427a 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import { ColorOption } from '../style/theme'; import { ERC20Asset } from '../types'; +import { analytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { SearchInput } from './search_input'; @@ -57,6 +58,7 @@ export class ERC20TokenSelector extends React.Component this.setState({ searchQuery, }); + analytics.trackTokenSelectorSearched(searchQuery); }; private readonly _isTokenQueryMatch = (token: ERC20Asset): boolean => { const { searchQuery } = this.state; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 50bab174f..cd1074cba 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -21,6 +21,7 @@ enum EventNames { TOKEN_SELECTOR_OPENED = 'Token Selector - Opened', TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed', TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose', + TOKEN_SELECTOR_SEARCHED = 'Token Selector - Searched', } const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { evaluateIfEnabled(() => { @@ -74,4 +75,6 @@ export const analytics = { trackTokenSelectorClosed: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_CLOSED), trackTokenSelectorChose: (payload: { assetName: string; assetData: string }) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload), + trackTokenSelectorSearched: (searchText: string) => + trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }), }; -- cgit v1.2.3 From 685d83d6d0dc7998ce231e5106d74c0e16b17f34 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 21 Nov 2018 10:22:43 -0800 Subject: feat(instant): implement buy events without associated properties --- packages/instant/src/components/buy_button.tsx | 8 ++++++++ packages/instant/src/util/analytics.ts | 14 ++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 8b6121e43..6db71852e 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -8,6 +8,7 @@ import { oc } from 'ts-optchain'; import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants'; import { ColorOption } from '../style/theme'; import { AffiliateInfo, ZeroExInstantError } from '../types'; +import { analytics } from '../util/analytics'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { util } from '../util/util'; @@ -59,6 +60,7 @@ export class BuyButton extends React.Component { // if we don't have a balance for the user, let the transaction through, it will be handled by the wallet const hasSufficientEth = _.isUndefined(accountEthBalanceInWei) || accountEthBalanceInWei.gte(ethNeededForBuy); if (!hasSufficientEth) { + analytics.trackBuyNotEnoughEth(); this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH); return; } @@ -66,17 +68,21 @@ export class BuyButton extends React.Component { const gasInfo = await gasPriceEstimator.getGasInfoAsync(); const feeRecipient = oc(affiliateInfo).feeRecipient(); try { + analytics.trackBuyStarted(); txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { feeRecipient, takerAddress: accountAddress, gasPrice: gasInfo.gasPriceInWei, }); + analytics.trackBuyTxSubmitted(); } catch (e) { if (e instanceof Error) { if (e.message === AssetBuyerError.SignatureRequestDenied) { + analytics.trackBuySignatureDenied(); this.props.onSignatureDenied(buyQuote); return; } else if (e.message === AssetBuyerError.TransactionValueTooLow) { + analytics.trackBuySimulationFailed(); this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow); return; } @@ -89,12 +95,14 @@ export class BuyButton extends React.Component { try { await web3Wrapper.awaitTransactionSuccessAsync(txHash); } catch (e) { + analytics.trackBuyTxFailed(); if (e instanceof Error && e.message.startsWith(WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX)) { this.props.onBuyFailure(buyQuote, txHash); return; } throw e; } + analytics.trackBuyTxSucceeded(); this.props.onBuySuccess(buyQuote, txHash); }; } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e389e1530..bd3a62ef8 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -18,6 +18,13 @@ enum EventNames { ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested', ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', + BUY_NOT_ENOUGH_ETH = 'Buy - Not Enough Eth', + BUY_STARTED = 'Buy - Started', + BUY_SIGNATURE_DENIED = 'Buy - Signature Denied', + BUY_SIMULATION_FAILED = 'Buy - Simulation Failed', + BUY_TX_SUBMITTED = 'Buy - Tx Submitted', + BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded', + BUY_TX_FAILED = 'Buy - Tx Failed', } const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { evaluateIfEnabled(() => { @@ -67,4 +74,11 @@ export const analytics = { trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), trackAccountAddressChanged: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), + trackBuyNotEnoughEth: trackingEventFnWithoutPayload(EventNames.BUY_NOT_ENOUGH_ETH), + trackBuyStarted: trackingEventFnWithoutPayload(EventNames.BUY_STARTED), + trackBuySignatureDenied: trackingEventFnWithoutPayload(EventNames.BUY_SIGNATURE_DENIED), + trackBuySimulationFailed: trackingEventFnWithoutPayload(EventNames.BUY_SIMULATION_FAILED), + trackBuyTxSubmitted: trackingEventFnWithoutPayload(EventNames.BUY_TX_SUBMITTED), + trackBuyTxSucceeded: trackingEventFnWithoutPayload(EventNames.BUY_TX_SUCCEEDED), + trackBuyTxFailed: trackingEventFnWithoutPayload(EventNames.BUY_TX_FAILED), }; -- cgit v1.2.3 From fad48b8b6c5299b2fd3b8490779a538e1158f2dd Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 21 Nov 2018 15:18:31 -0800 Subject: feat(instant): add txHash to relevant buy events --- packages/instant/src/components/buy_button.tsx | 6 +++--- packages/instant/src/util/analytics.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 6db71852e..9a6785862 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -74,7 +74,7 @@ export class BuyButton extends React.Component { takerAddress: accountAddress, gasPrice: gasInfo.gasPriceInWei, }); - analytics.trackBuyTxSubmitted(); + analytics.trackBuyTxSubmitted(txHash); } catch (e) { if (e instanceof Error) { if (e.message === AssetBuyerError.SignatureRequestDenied) { @@ -95,14 +95,14 @@ export class BuyButton extends React.Component { try { await web3Wrapper.awaitTransactionSuccessAsync(txHash); } catch (e) { - analytics.trackBuyTxFailed(); + analytics.trackBuyTxFailed(txHash); if (e instanceof Error && e.message.startsWith(WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX)) { this.props.onBuyFailure(buyQuote, txHash); return; } throw e; } - analytics.trackBuyTxSucceeded(); + analytics.trackBuyTxSucceeded(txHash); this.props.onBuySuccess(buyQuote, txHash); }; } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index bd3a62ef8..5e55c8af3 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -78,7 +78,7 @@ export const analytics = { trackBuyStarted: trackingEventFnWithoutPayload(EventNames.BUY_STARTED), trackBuySignatureDenied: trackingEventFnWithoutPayload(EventNames.BUY_SIGNATURE_DENIED), trackBuySimulationFailed: trackingEventFnWithoutPayload(EventNames.BUY_SIMULATION_FAILED), - trackBuyTxSubmitted: trackingEventFnWithoutPayload(EventNames.BUY_TX_SUBMITTED), - trackBuyTxSucceeded: trackingEventFnWithoutPayload(EventNames.BUY_TX_SUCCEEDED), - trackBuyTxFailed: trackingEventFnWithoutPayload(EventNames.BUY_TX_FAILED), + trackBuyTxSubmitted: (txHash: string) => trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ txHash }), + trackBuyTxSucceeded: (txHash: string) => trackingEventFnWithPayload(EventNames.BUY_TX_SUCCEEDED)({ txHash }), + trackBuyTxFailed: (txHash: string) => trackingEventFnWithPayload(EventNames.BUY_TX_FAILED)({ txHash }), }; -- cgit v1.2.3 From 2795849dd3170542d3120a4e8c2493d29fa76a26 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 26 Nov 2018 14:47:46 -0800 Subject: feat(instant): add buyQuote properties to buy events --- packages/instant/src/components/buy_button.tsx | 14 ++++----- packages/instant/src/util/analytics.ts | 43 +++++++++++++++++++++----- 2 files changed, 43 insertions(+), 14 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 9a6785862..118e3c92f 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -60,7 +60,7 @@ export class BuyButton extends React.Component { // if we don't have a balance for the user, let the transaction through, it will be handled by the wallet const hasSufficientEth = _.isUndefined(accountEthBalanceInWei) || accountEthBalanceInWei.gte(ethNeededForBuy); if (!hasSufficientEth) { - analytics.trackBuyNotEnoughEth(); + analytics.trackBuyNotEnoughEth(buyQuote); this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH); return; } @@ -68,21 +68,21 @@ export class BuyButton extends React.Component { const gasInfo = await gasPriceEstimator.getGasInfoAsync(); const feeRecipient = oc(affiliateInfo).feeRecipient(); try { - analytics.trackBuyStarted(); + analytics.trackBuyStarted(buyQuote); txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { feeRecipient, takerAddress: accountAddress, gasPrice: gasInfo.gasPriceInWei, }); - analytics.trackBuyTxSubmitted(txHash); + analytics.trackBuyTxSubmitted(buyQuote, txHash); } catch (e) { if (e instanceof Error) { if (e.message === AssetBuyerError.SignatureRequestDenied) { - analytics.trackBuySignatureDenied(); + analytics.trackBuySignatureDenied(buyQuote); this.props.onSignatureDenied(buyQuote); return; } else if (e.message === AssetBuyerError.TransactionValueTooLow) { - analytics.trackBuySimulationFailed(); + analytics.trackBuySimulationFailed(buyQuote); this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow); return; } @@ -95,14 +95,14 @@ export class BuyButton extends React.Component { try { await web3Wrapper.awaitTransactionSuccessAsync(txHash); } catch (e) { - analytics.trackBuyTxFailed(txHash); + analytics.trackBuyTxFailed(buyQuote, txHash); if (e instanceof Error && e.message.startsWith(WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX)) { this.props.onBuyFailure(buyQuote, txHash); return; } throw e; } - analytics.trackBuyTxSucceeded(txHash); + analytics.trackBuyTxSucceeded(buyQuote, txHash); this.props.onBuySuccess(buyQuote, txHash); }; } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 5e55c8af3..0fe7be705 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,3 +1,6 @@ +import { BuyQuote } from '@0x/asset-buyer'; +import * as _ from 'lodash'; + import { EventProperties, heapUtil } from './heap'; let isDisabled = false; @@ -43,6 +46,25 @@ function trackingEventFnWithPayload(eventName: EventNames): (eventProperties: Ev }; } +const buyQuoteEventProperties = (buyQuote: BuyQuote) => { + const assetData = buyQuote.assetData.toString(); + const assetBuyAmount = buyQuote.assetBuyAmount.toString(); + const assetEthAmount = buyQuote.worstCaseQuoteInfo.assetEthAmount.toString(); + const feeEthAmount = buyQuote.worstCaseQuoteInfo.feeEthAmount.toString(); + const totalEthAmount = buyQuote.worstCaseQuoteInfo.totalEthAmount.toString(); + const feePercentage = !_.isUndefined(buyQuote.feePercentage) ? buyQuote.feePercentage.toString() : 0; + const hasFeeOrders = !_.isEmpty(buyQuote.feeOrders) ? 'true' : 'false'; + return { + assetData, + assetBuyAmount, + assetEthAmount, + feeEthAmount, + totalEthAmount, + feePercentage, + hasFeeOrders, + }; +}; + export interface AnalyticsUserOptions { lastKnownEthAddress?: string; ethBalanceInUnitAmount?: string; @@ -74,11 +96,18 @@ export const analytics = { trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), trackAccountAddressChanged: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), - trackBuyNotEnoughEth: trackingEventFnWithoutPayload(EventNames.BUY_NOT_ENOUGH_ETH), - trackBuyStarted: trackingEventFnWithoutPayload(EventNames.BUY_STARTED), - trackBuySignatureDenied: trackingEventFnWithoutPayload(EventNames.BUY_SIGNATURE_DENIED), - trackBuySimulationFailed: trackingEventFnWithoutPayload(EventNames.BUY_SIMULATION_FAILED), - trackBuyTxSubmitted: (txHash: string) => trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ txHash }), - trackBuyTxSucceeded: (txHash: string) => trackingEventFnWithPayload(EventNames.BUY_TX_SUCCEEDED)({ txHash }), - trackBuyTxFailed: (txHash: string) => trackingEventFnWithPayload(EventNames.BUY_TX_FAILED)({ txHash }), + trackBuyNotEnoughEth: (buyQuote: BuyQuote) => + trackingEventFnWithPayload(EventNames.BUY_NOT_ENOUGH_ETH)(buyQuoteEventProperties(buyQuote)), + trackBuyStarted: (buyQuote: BuyQuote) => + trackingEventFnWithPayload(EventNames.BUY_STARTED)(buyQuoteEventProperties(buyQuote)), + trackBuySignatureDenied: (buyQuote: BuyQuote) => + trackingEventFnWithPayload(EventNames.BUY_SIGNATURE_DENIED)(buyQuoteEventProperties(buyQuote)), + trackBuySimulationFailed: (buyQuote: BuyQuote) => + trackingEventFnWithPayload(EventNames.BUY_SIMULATION_FAILED)(buyQuoteEventProperties(buyQuote)), + trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string) => + trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ ...buyQuoteEventProperties(buyQuote), txHash }), + trackBuyTxSucceeded: (buyQuote: BuyQuote, txHash: string) => + trackingEventFnWithPayload(EventNames.BUY_TX_SUCCEEDED)({ ...buyQuoteEventProperties(buyQuote), txHash }), + trackBuyTxFailed: (buyQuote: BuyQuote, txHash: string) => + trackingEventFnWithPayload(EventNames.BUY_TX_FAILED)({ ...buyQuoteEventProperties(buyQuote), txHash }), }; -- cgit v1.2.3 From ae570dba05cfc0d696c616d05804152791d29677 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 15:04:02 -0800 Subject: feat(instant): Event tracking for token selector --- .../src/components/zero_ex_instant_container.tsx | 17 ++++++++++++----- packages/instant/src/util/analytics.ts | 7 ++++++- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index f30bda6ed..b72493ce6 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -12,7 +12,7 @@ import { SelectedAssetInstantHeading } from '../containers/selected_asset_instan import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; import { OrderProcessState, SlideAnimationState } from '../types'; -import { analytics } from '../util/analytics'; +import { analytics, TokenSelectorClosedVia } from '../util/analytics'; import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; @@ -30,6 +30,13 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon public state = { tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; + private _handlePanelCloseClickedX: () => void; + private _handlePanelCloseAfterChose: () => void; + public constructor(props: {}) { + super(props); + this._handlePanelCloseClickedX = this._handlePanelClose.bind(this, TokenSelectorClosedVia.ClickedX); + this._handlePanelCloseAfterChose = this._handlePanelClose.bind(this, TokenSelectorClosedVia.TokenChose); + } public render(): React.ReactNode { return ( @@ -61,9 +68,9 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon - + @@ -88,8 +95,8 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon tokenSelectionPanelAnimationState: 'slidIn', }); }; - private readonly _handlePanelClose = (): void => { - analytics.trackTokenSelectorClosed(); + private readonly _handlePanelClose = (closedVia: TokenSelectorClosedVia): void => { + analytics.trackTokenSelectorClosed(closedVia); this.setState({ tokenSelectionPanelAnimationState: 'slidOut', }); diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index cd1074cba..8f8cec284 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -52,7 +52,10 @@ export interface AnalyticsEventOptions { gitSha?: string; npmVersion?: string; } - +export enum TokenSelectorClosedVia { + ClickedX = 'Clicked X', + TokenChose = 'Token Chose', +} export const analytics = { addUserProperties: (properties: AnalyticsUserOptions): void => { evaluateIfEnabled(() => { @@ -73,6 +76,8 @@ export const analytics = { trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED), trackTokenSelectorClosed: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_CLOSED), + trackTokenSelectorClosed: (closedVia: TokenSelectorClosedVia) => + trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CLOSED)({ closedVia }), trackTokenSelectorChose: (payload: { assetName: string; assetData: string }) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload), trackTokenSelectorSearched: (searchText: string) => -- cgit v1.2.3 From d5898a3a050a8c97e516dba62ba040140fd74c62 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 15:12:51 -0800 Subject: Fix dupe merge issue --- packages/instant/src/util/analytics.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 1dda649b3..51be63da2 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -102,7 +102,6 @@ export const analytics = { trackAccountAddressChanged: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED), - trackTokenSelectorClosed: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_CLOSED), trackTokenSelectorClosed: (closedVia: TokenSelectorClosedVia) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CLOSED)({ closedVia }), trackTokenSelectorChose: (payload: { assetName: string; assetData: string }) => -- cgit v1.2.3 From 7610130f7353ea6134fae441a8fe23e0fd0ddb2f Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 15:51:40 -0800 Subject: Track numberAvailableAssets, selectedAssetName, selectedAssetData event properties --- .../src/components/zero_ex_instant_provider.tsx | 1 + packages/instant/src/redux/analytics_middleware.ts | 21 ++++++++++++++++++--- packages/instant/src/util/analytics.ts | 16 ++++++++++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index fe34c4466..e006a5a5f 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -131,6 +131,7 @@ export class ZeroExInstantProvider extends React.Component next => middlewareAction } break; case ActionTypes.UPDATE_SELECTED_ASSET: - if (curState.selectedAsset) { + const selectedAsset = curState.selectedAsset; + if (selectedAsset) { + const assetName = selectedAsset.metaData.name; + const assetData = selectedAsset.assetData; analytics.trackTokenSelectorChose({ - assetName: curState.selectedAsset.metaData.name, - assetData: curState.selectedAsset.assetData, + assetName, + assetData, + }); + analytics.addEventProperties({ + selectedAssetName: assetName, + selectedAssetData: assetData, + }); + } + break; + case ActionTypes.SET_AVAILABLE_ASSETS: + const availableAssets = curState.availableAssets; + if (availableAssets) { + analytics.addEventProperties({ + numberAvailableAssets: availableAssets.length, }); } break; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 51be63da2..331cd86e8 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,4 +1,4 @@ -import { AffiliateInfo, Network, OrderSource, ProviderState } from '../types'; +import { AffiliateInfo, Asset, Network, OrderSource, ProviderState } from '../types'; import { EventProperties, heapUtil } from './heap'; @@ -25,6 +25,7 @@ enum EventNames { TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose', TOKEN_SELECTOR_SEARCHED = 'Token Selector - Searched', } + const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { evaluateIfEnabled(() => { heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventProperties)); @@ -56,6 +57,9 @@ export interface AnalyticsEventOptions { orderSource?: string; affiliateAddress?: string; affiliateFeePercent?: number; + numberAvailableAssets?: number; + selectedAssetName?: string; + selectedAssetData?: string; } export enum TokenSelectorClosedVia { ClickedX = 'Clicked X', @@ -77,12 +81,13 @@ export const analytics = { orderSource: OrderSource, providerState: ProviderState, window: Window, + selectedAsset?: Asset, affiliateInfo?: AffiliateInfo, ): AnalyticsEventOptions => { const affiliateAddress = affiliateInfo ? affiliateInfo.feeRecipient : 'none'; const affiliateFeePercent = affiliateInfo ? parseFloat(affiliateInfo.feePercentage.toFixed(4)) : 0; const orderSourceName = typeof orderSource === 'string' ? orderSource : 'provided'; - return { + const eventOptions: AnalyticsEventOptions = { embeddedHost: window.location.host, embeddedUrl: window.location.href, networkId: network, @@ -93,6 +98,13 @@ export const analytics = { affiliateAddress, affiliateFeePercent, }; + + if (selectedAsset) { + eventOptions.selectedAssetName = selectedAsset.metaData.name; + eventOptions.selectedAssetData = selectedAsset.assetData; + } + + return eventOptions; }, trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED), -- cgit v1.2.3 From 0192127e5d20222698673d5c63c1025a10d5011f Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 15:53:39 -0800 Subject: Set selected asset to none --- packages/instant/src/util/analytics.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 331cd86e8..aa0f37194 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -97,13 +97,9 @@ export const analytics = { orderSource: orderSourceName, affiliateAddress, affiliateFeePercent, + selectedAssetName: selectedAsset ? selectedAsset.metaData.name : 'none', + selectedAssetData: selectedAsset ? selectedAsset.assetData : 'none', }; - - if (selectedAsset) { - eventOptions.selectedAssetName = selectedAsset.metaData.name; - eventOptions.selectedAssetData = selectedAsset.assetData; - } - return eventOptions; }, trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), -- cgit v1.2.3 From 80a53aedf220948675a938dc4ae5227381fb96e5 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 16:53:50 -0800 Subject: Fix props --- packages/instant/src/components/zero_ex_instant_container.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index b72493ce6..72a3cde2f 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -19,20 +19,18 @@ import { SlidingPanel } from './sliding_panel'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; -export interface ZeroExInstantContainerProps { - orderProcessState: OrderProcessState; -} +export interface ZeroExInstantContainerProps {} export interface ZeroExInstantContainerState { tokenSelectionPanelAnimationState: SlideAnimationState; } -export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantContainerState> { +export class ZeroExInstantContainer extends React.Component { public state = { tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; private _handlePanelCloseClickedX: () => void; private _handlePanelCloseAfterChose: () => void; - public constructor(props: {}) { + public constructor(props: ZeroExInstantContainerProps) { super(props); this._handlePanelCloseClickedX = this._handlePanelClose.bind(this, TokenSelectorClosedVia.ClickedX); this._handlePanelCloseAfterChose = this._handlePanelClose.bind(this, TokenSelectorClosedVia.TokenChose); -- cgit v1.2.3 From f3d08c13ebf337f4f5e174dd003cd436a6ad5417 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 26 Nov 2018 17:13:35 -0800 Subject: Add stable CSS classes --- packages/instant/src/components/zero_ex_instant_overlay.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index 2856ea3e3..7fbac7475 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -18,7 +18,7 @@ export const ZeroExInstantOverlay: React.StatelessComponent - + - + -- cgit v1.2.3 From d3b0162dc979ccdc4b4ddff62199929c714ad3ca Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 26 Nov 2018 23:08:20 -0800 Subject: feat(instant): add expectedEndTimeUnix and actualEndTimeUnix to buy events --- packages/instant/src/components/buy_button.tsx | 6 ++--- packages/instant/src/util/analytics.ts | 31 +++++++++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 118e3c92f..eeb42d6fc 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -74,7 +74,6 @@ export class BuyButton extends React.Component { takerAddress: accountAddress, gasPrice: gasInfo.gasPriceInWei, }); - analytics.trackBuyTxSubmitted(buyQuote, txHash); } catch (e) { if (e instanceof Error) { if (e.message === AssetBuyerError.SignatureRequestDenied) { @@ -93,16 +92,17 @@ export class BuyButton extends React.Component { const expectedEndTimeUnix = startTimeUnix + gasInfo.estimatedTimeMs; this.props.onBuyProcessing(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); try { + analytics.trackBuyTxSubmitted(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); await web3Wrapper.awaitTransactionSuccessAsync(txHash); } catch (e) { - analytics.trackBuyTxFailed(buyQuote, txHash); if (e instanceof Error && e.message.startsWith(WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX)) { + analytics.trackBuyTxFailed(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); this.props.onBuyFailure(buyQuote, txHash); return; } throw e; } - analytics.trackBuyTxSucceeded(buyQuote, txHash); + analytics.trackBuyTxSucceeded(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); this.props.onBuySuccess(buyQuote, txHash); }; } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 0fe7be705..283695ef8 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -47,7 +47,6 @@ function trackingEventFnWithPayload(eventName: EventNames): (eventProperties: Ev } const buyQuoteEventProperties = (buyQuote: BuyQuote) => { - const assetData = buyQuote.assetData.toString(); const assetBuyAmount = buyQuote.assetBuyAmount.toString(); const assetEthAmount = buyQuote.worstCaseQuoteInfo.assetEthAmount.toString(); const feeEthAmount = buyQuote.worstCaseQuoteInfo.feeEthAmount.toString(); @@ -55,7 +54,6 @@ const buyQuoteEventProperties = (buyQuote: BuyQuote) => { const feePercentage = !_.isUndefined(buyQuote.feePercentage) ? buyQuote.feePercentage.toString() : 0; const hasFeeOrders = !_.isEmpty(buyQuote.feeOrders) ? 'true' : 'false'; return { - assetData, assetBuyAmount, assetEthAmount, feeEthAmount, @@ -104,10 +102,27 @@ export const analytics = { trackingEventFnWithPayload(EventNames.BUY_SIGNATURE_DENIED)(buyQuoteEventProperties(buyQuote)), trackBuySimulationFailed: (buyQuote: BuyQuote) => trackingEventFnWithPayload(EventNames.BUY_SIMULATION_FAILED)(buyQuoteEventProperties(buyQuote)), - trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string) => - trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ ...buyQuoteEventProperties(buyQuote), txHash }), - trackBuyTxSucceeded: (buyQuote: BuyQuote, txHash: string) => - trackingEventFnWithPayload(EventNames.BUY_TX_SUCCEEDED)({ ...buyQuoteEventProperties(buyQuote), txHash }), - trackBuyTxFailed: (buyQuote: BuyQuote, txHash: string) => - trackingEventFnWithPayload(EventNames.BUY_TX_FAILED)({ ...buyQuoteEventProperties(buyQuote), txHash }), + trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ + ...buyQuoteEventProperties(buyQuote), + txHash, + startTimeUnix, + expectedEndTimeUnix, + }), + trackBuyTxSucceeded: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + trackingEventFnWithPayload(EventNames.BUY_TX_SUCCEEDED)({ + ...buyQuoteEventProperties(buyQuote), + txHash, + startTimeUnix, + expectedEndTimeUnix, + actualEndTimeUnix: new Date().getTime(), + }), + trackBuyTxFailed: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + trackingEventFnWithPayload(EventNames.BUY_TX_FAILED)({ + ...buyQuoteEventProperties(buyQuote), + txHash, + startTimeUnix, + expectedEndTimeUnix, + actualEndTimeUnix: new Date().getTime(), + }), }; -- cgit v1.2.3 From e08fb72cf10f5260966e4dfd84873c326ff4ea61 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 09:01:49 -0800 Subject: Use constants --- packages/instant/src/components/zero_ex_instant_overlay.tsx | 5 +++-- packages/instant/src/constants.ts | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index 7fbac7475..b3fb57dd6 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { ZeroExInstantContainer } from '../components/zero_ex_instant_container'; +import { MAIN_CONTAINER_DIV_CLASS, OVERLAY_DIV_CLASS } from '../constants'; import { ColorOption } from '../style/theme'; import { Container } from './ui/container'; @@ -18,7 +19,7 @@ export const ZeroExInstantOverlay: React.StatelessComponent - + diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index be6077ca9..163be40b3 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -7,6 +7,8 @@ export const ETH_DECIMALS = 18; export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer'; export const INJECTED_DIV_CLASS = 'zeroExInstantResetRoot'; export const INJECTED_DIV_ID = 'zeroExInstant'; +export const OVERLAY_DIV_CLASS = 'zeroExInstantOverlay'; +export const MAIN_CONTAINER_DIV_CLASS = 'zeroExInstantMainContainer'; export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed'; export const GWEI_IN_WEI = new BigNumber(1000000000); export const ONE_SECOND_MS = 1000; -- cgit v1.2.3 From ee5b6ad77ffac9aca00035a6bc50cdbf25caf348 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 09:16:26 -0800 Subject: Linting --- packages/instant/src/components/zero_ex_instant_container.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 72a3cde2f..1e74cf41c 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -11,7 +11,7 @@ import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_ import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; -import { OrderProcessState, SlideAnimationState } from '../types'; +import { SlideAnimationState } from '../types'; import { analytics, TokenSelectorClosedVia } from '../util/analytics'; import { CSSReset } from './css_reset'; @@ -28,8 +28,8 @@ export class ZeroExInstantContainer extends React.Component void; - private _handlePanelCloseAfterChose: () => void; + private readonly _handlePanelCloseClickedX: () => void; + private readonly _handlePanelCloseAfterChose: () => void; public constructor(props: ZeroExInstantContainerProps) { super(props); this._handlePanelCloseClickedX = this._handlePanelClose.bind(this, TokenSelectorClosedVia.ClickedX); -- cgit v1.2.3 From be787a0fd19a658cbf21eb90140c76779647dfbc Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 09:50:56 -0800 Subject: feat(instant): Add analytics events for payment dropdown --- .../instant/src/components/payment_method_dropdown.tsx | 14 +++++++++++++- packages/instant/src/components/ui/dropdown.tsx | 8 +++++++- packages/instant/src/util/analytics.ts | 6 ++++++ 3 files changed, 26 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx index b330dbcd6..7d7fecbc2 100644 --- a/packages/instant/src/components/payment_method_dropdown.tsx +++ b/packages/instant/src/components/payment_method_dropdown.tsx @@ -3,6 +3,7 @@ import copy from 'copy-to-clipboard'; import * as React from 'react'; import { Network } from '../types'; +import { analytics } from '../util/analytics'; import { envUtil } from '../util/env'; import { etherscanUtil } from '../util/etherscan'; import { format } from '../util/format'; @@ -20,7 +21,14 @@ export class PaymentMethodDropdown extends React.Component; + return ( + + ); } private readonly _getDropdownItemConfigs = (): DropdownItemConfig[] => { if (envUtil.isMobileOperatingSystem()) { @@ -37,11 +45,15 @@ export class PaymentMethodDropdown extends React.Component { + analytics.trackPaymentMethodOpenedEtherscan(); + const { accountAddress, network } = this.props; const etherscanUrl = etherscanUtil.getEtherScanEthAddressIfExists(accountAddress, network); window.open(etherscanUrl, '_blank'); }; private readonly _handleCopyToClipboardClick = (): void => { + analytics.trackPaymentMethodCopiedAddress(); + const { accountAddress } = this.props; copy(accountAddress); }; diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index 3a23f456d..02e87d639 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -19,6 +19,7 @@ export interface DropdownProps { value: string; label?: string; items: DropdownItemConfig[]; + onOpen?: () => void; } export interface DropdownState { @@ -97,9 +98,14 @@ export class Dropdown extends React.Component { if (_.isEmpty(this.props.items)) { return; } + const isOpen = !this.state.isOpen; this.setState({ - isOpen: !this.state.isOpen, + isOpen, }); + + if (isOpen && this.props.onOpen) { + this.props.onOpen(); + } }; private readonly _closeDropdown = (): void => { this.setState({ diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index cec99dd1b..1c7774b73 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -20,6 +20,9 @@ enum EventNames { ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested', ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', + PAYMENT_METHOD_DROPDOWN_OPENED = 'Payment Method - Dropdown Opened', + PAYMENT_METHOD_OPENED_ETHERSCAN = 'Payment Method - Opened Etherscan', + PAYMENT_METHOD_COPIED_ADDRESS = 'Payment Method - Copied Address', } const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { evaluateIfEnabled(() => { @@ -94,4 +97,7 @@ export const analytics = { trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), trackAccountAddressChanged: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), + trackPaymentMethodDropdownOpened: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_DROPDOWN_OPENED), + trackPaymentMethodOpenedEtherscan: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_OPENED_ETHERSCAN), + trackPaymentMethodCopiedAddress: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_COPIED_ADDRESS), }; -- cgit v1.2.3 From 9c27feeff61ab38771709b3f4ccd1fb1ff29e1d2 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 10:00:21 -0800 Subject: Make explicit functions --- .../instant/src/components/zero_ex_instant_container.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 1e74cf41c..8a809ee31 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -28,13 +28,6 @@ export class ZeroExInstantContainer extends React.Component void; - private readonly _handlePanelCloseAfterChose: () => void; - public constructor(props: ZeroExInstantContainerProps) { - super(props); - this._handlePanelCloseClickedX = this._handlePanelClose.bind(this, TokenSelectorClosedVia.ClickedX); - this._handlePanelCloseAfterChose = this._handlePanelClose.bind(this, TokenSelectorClosedVia.TokenChose); - } public render(): React.ReactNode { return ( @@ -93,6 +86,12 @@ export class ZeroExInstantContainer extends React.Component { + this._handlePanelClose(TokenSelectorClosedVia.ClickedX); + }; + private readonly _handlePanelCloseAfterChose = (): void => { + this._handlePanelClose(TokenSelectorClosedVia.TokenChose); + }; private readonly _handlePanelClose = (closedVia: TokenSelectorClosedVia): void => { analytics.trackTokenSelectorClosed(closedVia); this.setState({ -- cgit v1.2.3 From 6e2523625f6a29bfcf58bf032d0cd3a468053247 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 27 Nov 2018 10:17:59 -0800 Subject: feat(instant): change event properties to ms times instead of unix timestamps --- packages/instant/src/util/analytics.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index d45d37b3b..c2fe7b0e7 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -133,23 +133,20 @@ export const analytics = { trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ ...buyQuoteEventProperties(buyQuote), txHash, - startTimeUnix, - expectedEndTimeUnix, + expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix, }), trackBuyTxSucceeded: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => trackingEventFnWithPayload(EventNames.BUY_TX_SUCCEEDED)({ ...buyQuoteEventProperties(buyQuote), txHash, - startTimeUnix, - expectedEndTimeUnix, - actualEndTimeUnix: new Date().getTime(), + expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix, + actualTxTimeMs: new Date().getTime() - startTimeUnix, }), trackBuyTxFailed: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => trackingEventFnWithPayload(EventNames.BUY_TX_FAILED)({ ...buyQuoteEventProperties(buyQuote), txHash, - startTimeUnix, - expectedEndTimeUnix, - actualEndTimeUnix: new Date().getTime(), + expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix, + actualTxTimeMs: new Date().getTime() - startTimeUnix, }), }; -- cgit v1.2.3 From 435e62a94df3d98e8321f5ecc3a984b495313f92 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 10:32:54 -0800 Subject: fix(instant): Fix copy to clipboard --- packages/instant/src/components/payment_method_dropdown.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx index b330dbcd6..0226d1f01 100644 --- a/packages/instant/src/components/payment_method_dropdown.tsx +++ b/packages/instant/src/components/payment_method_dropdown.tsx @@ -1,5 +1,5 @@ import { BigNumber } from '@0x/utils'; -import copy from 'copy-to-clipboard'; +import * as copy from 'copy-to-clipboard'; import * as React from 'react'; import { Network } from '../types'; -- cgit v1.2.3 From b50187f59c09d4ecf7a840fd22f96bcecd14bb1b Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 11:25:51 -0800 Subject: Track install wallet clicked --- .../containers/connected_account_payment_method.ts | 37 ++++++++++++---------- packages/instant/src/types.ts | 5 +++ packages/instant/src/util/analytics.ts | 5 ++- 3 files changed, 30 insertions(+), 17 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/containers/connected_account_payment_method.ts b/packages/instant/src/containers/connected_account_payment_method.ts index cdeb49a25..e9327a288 100644 --- a/packages/instant/src/containers/connected_account_payment_method.ts +++ b/packages/instant/src/containers/connected_account_payment_method.ts @@ -11,7 +11,7 @@ import { import { Action, actions } from '../redux/actions'; import { asyncData } from '../redux/async_data'; import { State } from '../redux/reducer'; -import { Network, Omit, OperatingSystem, ProviderState, StandardSlidingPanelContent } from '../types'; +import { Network, Omit, OperatingSystem, ProviderState, StandardSlidingPanelContent, WalletSuggestion } from '../types'; import { analytics } from '../util/analytics'; import { envUtil } from '../util/env'; @@ -60,23 +60,28 @@ const mergeProps = ( onUnlockWalletClick: () => connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState), onInstallWalletClick: () => { const isMobile = envUtil.isMobileOperatingSystem(); - if (!isMobile) { + const walletSuggestion: WalletSuggestion = isMobile + ? WalletSuggestion.CoinbaseWallet + : WalletSuggestion.MetaMask; + + analytics.trackInstallWalletClicked(walletSuggestion); + if (walletSuggestion === WalletSuggestion.MetaMask) { connectedDispatch.openInstallWalletPanel(); - return; - } - const operatingSystem = envUtil.getOperatingSystem(); - let url = COINBASE_WALLET_SITE_URL; - switch (operatingSystem) { - case OperatingSystem.Android: - url = COINBASE_WALLET_ANDROID_APP_STORE_URL; - break; - case OperatingSystem.iOS: - url = COINBASE_WALLET_IOS_APP_STORE_URL; - break; - default: - break; + } else { + const operatingSystem = envUtil.getOperatingSystem(); + let url = COINBASE_WALLET_SITE_URL; + switch (operatingSystem) { + case OperatingSystem.Android: + url = COINBASE_WALLET_ANDROID_APP_STORE_URL; + break; + case OperatingSystem.iOS: + url = COINBASE_WALLET_IOS_APP_STORE_URL; + break; + default: + break; + } + window.open(url, '_blank'); } - window.open(url, '_blank'); }, }); diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 999d50fed..4ad9c9d4f 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -149,6 +149,11 @@ export enum Browser { Other = 'OTHER', } +export enum WalletSuggestion { + CoinbaseWallet = 'Coinbase Wallet', + MetaMask = 'MetaMask', +} + export enum OperatingSystem { Android = 'ANDROID', iOS = 'IOS', diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 2bb974254..e35a9e13f 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,7 +1,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import * as _ from 'lodash'; -import { AffiliateInfo, Asset, Network, OrderSource, ProviderState } from '../types'; +import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, WalletSuggestion } from '../types'; import { EventProperties, heapUtil } from './heap'; @@ -30,6 +30,7 @@ enum EventNames { BUY_TX_SUBMITTED = 'Buy - Tx Submitted', BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded', BUY_TX_FAILED = 'Buy - Tx Failed', + INSTALL_WALLET_CLICKED = 'Install Wallet - Clicked', TOKEN_SELECTOR_OPENED = 'Token Selector - Opened', TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed', TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose', @@ -164,6 +165,8 @@ export const analytics = { expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix, actualTxTimeMs: new Date().getTime() - startTimeUnix, }), + trackInstallWalletClicked: (walletSuggestion: WalletSuggestion) => + trackingEventFnWithPayload(EventNames.INSTALL_WALLET_CLICKED)({ walletSuggestion }), trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED), trackTokenSelectorClosed: (closedVia: TokenSelectorClosedVia) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CLOSED)({ closedVia }), -- cgit v1.2.3 From 462a5face9b2b24c1e9d20a6b894809faa512232 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 13:30:28 -0800 Subject: feat(instant): Install Wallet analytics --- .../src/components/install_wallet_panel_content.tsx | 9 ++++++++- packages/instant/src/components/standard_panel_content.tsx | 13 ++++++++++++- packages/instant/src/redux/analytics_middleware.ts | 14 +++++++++++++- packages/instant/src/util/analytics.ts | 10 ++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/install_wallet_panel_content.tsx b/packages/instant/src/components/install_wallet_panel_content.tsx index 88c26f59c..481d82da0 100644 --- a/packages/instant/src/components/install_wallet_panel_content.tsx +++ b/packages/instant/src/components/install_wallet_panel_content.tsx @@ -8,7 +8,9 @@ import { } from '../constants'; import { ColorOption } from '../style/theme'; import { Browser } from '../types'; +import { analytics } from '../util/analytics'; import { envUtil } from '../util/env'; +import { util } from '../util/util'; import { MetaMaskLogo } from './meta_mask_logo'; import { StandardPanelContent, StandardPanelContentProps } from './standard_panel_content'; @@ -45,6 +47,10 @@ export class InstallWalletPanelContent extends React.Component { + analytics.trackInstallWalletModalClickedGet(); + util.createOpenUrlInNewWindow(actionUrl)(); + }; return { image: , title: 'Install MetaMask', @@ -52,10 +58,11 @@ export class InstallWalletPanelContent extends React.Component void; } export interface StandardPanelContentProps { @@ -21,6 +23,15 @@ export interface StandardPanelContentProps { const SPACING_BETWEEN_PX = '20px'; +const onMoreInfoClick = (href: string, onClick?: () => void) => { + return () => { + if (onClick) { + onClick(); + } + util.createOpenUrlInNewWindow(href)(); + }; +}; + export const StandardPanelContent: React.StatelessComponent = ({ image, title, @@ -50,7 +61,7 @@ export const StandardPanelContent: React.StatelessComponent {moreInfoSettings.text} diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 8aa76eb77..3dc5fe924 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -3,7 +3,7 @@ import * as _ from 'lodash'; import { Middleware } from 'redux'; import { ETH_DECIMALS } from '../constants'; -import { Account, AccountState } from '../types'; +import { Account, AccountState, StandardSlidingPanelContent } from '../types'; import { analytics } from '../util/analytics'; import { Action, ActionTypes } from './actions'; @@ -77,6 +77,18 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction }); } break; + case ActionTypes.OPEN_STANDARD_SLIDING_PANEL: + const openSlidingContent = curState.standardSlidingPanelSettings.content; + if (openSlidingContent === StandardSlidingPanelContent.InstallWallet) { + analytics.trackInstallWalletModalOpened(); + } + break; + case ActionTypes.CLOSE_STANDARD_SLIDING_PANEL: + const closeSlidingContent = curState.standardSlidingPanelSettings.content; + if (closeSlidingContent === StandardSlidingPanelContent.InstallWallet) { + analytics.trackInstallWalletModalClosed(); + } + break; } return nextAction; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e35a9e13f..f1ce15805 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -31,6 +31,10 @@ enum EventNames { BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded', BUY_TX_FAILED = 'Buy - Tx Failed', INSTALL_WALLET_CLICKED = 'Install Wallet - Clicked', + INSTALL_WALLET_MODAL_OPENED = 'Install Wallet - Modal - Opened', + INSTALL_WALLET_MODAL_CLICKED_EXPLANATION = 'Install Wallet - Modal - Clicked Explanation', + INSTALL_WALLET_MODAL_CLICKED_GET = 'Install Wallet - Modal - Clicked Get', + INSTALL_WALLET_MODAL_CLOSED = 'Install Wallet - Modal - Closed', TOKEN_SELECTOR_OPENED = 'Token Selector - Opened', TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed', TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose', @@ -167,6 +171,12 @@ export const analytics = { }), trackInstallWalletClicked: (walletSuggestion: WalletSuggestion) => trackingEventFnWithPayload(EventNames.INSTALL_WALLET_CLICKED)({ walletSuggestion }), + trackInstallWalletModalClickedExplanation: trackingEventFnWithoutPayload( + EventNames.INSTALL_WALLET_MODAL_CLICKED_EXPLANATION, + ), + trackInstallWalletModalClickedGet: trackingEventFnWithoutPayload(EventNames.INSTALL_WALLET_MODAL_CLICKED_GET), + trackInstallWalletModalOpened: trackingEventFnWithoutPayload(EventNames.INSTALL_WALLET_MODAL_OPENED), + trackInstallWalletModalClosed: trackingEventFnWithoutPayload(EventNames.INSTALL_WALLET_MODAL_CLOSED), trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED), trackTokenSelectorClosed: (closedVia: TokenSelectorClosedVia) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CLOSED)({ closedVia }), -- cgit v1.2.3 From 856f4b473b54ecb3dc707ea334890397c98606bf Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 14:14:30 -0800 Subject: feat(instant): Close and View Transaction analytics events --- .../src/containers/selected_asset_buy_order_state_buttons.ts | 3 +++ packages/instant/src/index.umd.ts | 2 ++ packages/instant/src/util/analytics.ts | 7 ++++++- 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts index 610335243..0d49edc57 100644 --- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts +++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts @@ -10,6 +10,7 @@ import { BuyOrderStateButtons } from '../components/buy_order_state_buttons'; import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; import { AccountState, AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types'; +import { analytics } from '../util/analytics'; import { errorFlasher } from '../util/error_flasher'; import { etherscanUtil } from '../util/etherscan'; @@ -59,6 +60,8 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButt assetBuyer.networkId, ); if (etherscanUrl) { + analytics.trackTransactionViewed(state.buyOrderState.processState); + window.open(etherscanUrl, '_blank'); return; } diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 3a8694d6a..667daf441 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -4,6 +4,7 @@ import * as ReactDOM from 'react-dom'; import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID } from './constants'; import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; +import { analytics } from './util/analytics'; import { assert } from './util/assert'; import { util } from './util/util'; @@ -57,6 +58,7 @@ const renderInstant = (config: ZeroExInstantConfig, selector: string) => { injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); appendTo.appendChild(injectedDiv); const closeInstant = () => { + analytics.trackInstantClosed(); if (!_.isUndefined(config.onClose)) { config.onClose(); } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 5bc9bb385..b1a2d2b63 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,7 +1,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import * as _ from 'lodash'; -import { AffiliateInfo, Asset, Network, OrderSource, ProviderState } from '../types'; +import { AffiliateInfo, Asset, Network, OrderProcessState, OrderSource, ProviderState } from '../types'; import { EventProperties, heapUtil } from './heap'; @@ -18,6 +18,7 @@ export const evaluateIfEnabled = (fnCall: () => void) => { enum EventNames { INSTANT_OPENED = 'Instant - Opened', + INSTANT_CLOSED = 'Instant - Closed', ACCOUNT_LOCKED = 'Account - Locked', ACCOUNT_READY = 'Account - Ready', ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested', @@ -37,6 +38,7 @@ enum EventNames { TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed', TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose', TOKEN_SELECTOR_SEARCHED = 'Token Selector - Searched', + TRANSACTION_VIEWED = 'Transaction - Viewed', } const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { @@ -133,6 +135,7 @@ export const analytics = { return eventOptions; }, trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), + trackInstantClosed: trackingEventFnWithoutPayload(EventNames.INSTANT_CLOSED), trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED), trackAccountReady: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ address }), trackAccountUnlockRequested: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_REQUESTED), @@ -177,4 +180,6 @@ export const analytics = { trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload), trackTokenSelectorSearched: (searchText: string) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }), + trackTransactionViewed: (orderProcesState: OrderProcessState) => + trackingEventFnWithPayload(EventNames.TRANSACTION_VIEWED)({ orderState: orderProcesState }), }; -- cgit v1.2.3 From c5d6b925e4e04d5b6cfd0623d0a1449ba69d3a30 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 15:10:40 -0800 Subject: feat(instant): Quote fetch tracking --- packages/instant/src/components/zero_ex_instant_provider.tsx | 7 +++++-- .../src/containers/selected_erc20_asset_amount_input.ts | 3 ++- packages/instant/src/redux/async_data.ts | 11 ++++++++--- packages/instant/src/types.ts | 5 +++++ packages/instant/src/util/analytics.ts | 9 ++++++++- packages/instant/src/util/buy_quote_updater.ts | 11 +++++++++-- packages/instant/src/util/heartbeater_factory.ts | 2 ++ 7 files changed, 39 insertions(+), 9 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index e006a5a5f..9f2c95e36 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -11,7 +11,7 @@ import { asyncData } from '../redux/async_data'; import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; -import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; +import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource, QuoteFetchedVia } from '../types'; import { analytics, disableAnalytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; @@ -115,7 +115,10 @@ export class ZeroExInstantProvider extends React.Component { const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state; const assetBuyer = providerState.assetBuyer; @@ -99,7 +99,12 @@ export const asyncData = { dispatch, selectedAsset as ERC20Asset, selectedAssetUnitAmount, - { setPending: !options.updateSilently, dispatchErrors: !options.updateSilently, affiliateInfo }, + { + setPending: !options.updateSilently, + dispatchErrors: !options.updateSilently, + fetchedVia: options.fetchedVia, + affiliateInfo, + }, ); } }, diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 999d50fed..a8139c185 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -21,6 +21,11 @@ export enum OrderProcessState { Failure = 'FAILURE', } +export enum QuoteFetchedVia { + Manual = 'Manual', + Heartbeat = 'Heartbeat', +} + export interface SimulatedProgress { startTimeUnix: number; expectedEndTimeUnix: number; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 5bc9bb385..204b6921d 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,7 +1,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import * as _ from 'lodash'; -import { AffiliateInfo, Asset, Network, OrderSource, ProviderState } from '../types'; +import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, QuoteFetchedVia } from '../types'; import { EventProperties, heapUtil } from './heap'; @@ -37,6 +37,8 @@ enum EventNames { TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed', TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose', TOKEN_SELECTOR_SEARCHED = 'Token Selector - Searched', + QUOTE_FETCHED = 'Quote - Fetched', + QUOTE_ERROR = 'Quote - Error', } const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { @@ -177,4 +179,9 @@ export const analytics = { trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload), trackTokenSelectorSearched: (searchText: string) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }), + trackQuoteFetched: (buyQuote: BuyQuote, fetchedVia: QuoteFetchedVia) => + trackingEventFnWithPayload(EventNames.QUOTE_FETCHED)({ + ...buyQuoteEventProperties(buyQuote), + fetchedVia, + }), }; diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 2fd16d781..59d3a85af 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -6,7 +6,8 @@ import { Dispatch } from 'redux'; import { oc } from 'ts-optchain'; import { Action, actions } from '../redux/actions'; -import { AffiliateInfo, ERC20Asset } from '../types'; +import { AffiliateInfo, ERC20Asset, QuoteFetchedVia } from '../types'; +import { analytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; @@ -16,7 +17,12 @@ export const buyQuoteUpdater = { dispatch: Dispatch, asset: ERC20Asset, assetUnitAmount: BigNumber, - options: { setPending: boolean; dispatchErrors: boolean; affiliateInfo?: AffiliateInfo }, + options: { + setPending: boolean; + dispatchErrors: boolean; + fetchedVia: QuoteFetchedVia; + affiliateInfo?: AffiliateInfo; + }, ): Promise => { // get a new buy quote. const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetUnitAmount, asset.metaData.decimals); @@ -58,5 +64,6 @@ export const buyQuoteUpdater = { errorFlasher.clearError(dispatch); // invalidate the last buy quote. dispatch(actions.updateLatestBuyQuote(newBuyQuote)); + analytics.trackQuoteFetched(newBuyQuote, options.fetchedVia); }, }; diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts index 2b852fb0d..bf9e4291f 100644 --- a/packages/instant/src/util/heartbeater_factory.ts +++ b/packages/instant/src/util/heartbeater_factory.ts @@ -1,5 +1,6 @@ import { asyncData } from '../redux/async_data'; import { Store } from '../redux/store'; +import { QuoteFetchedVia } from '../types'; import { Heartbeater } from './heartbeater'; @@ -19,6 +20,7 @@ export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): H return new Heartbeater(async () => { await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, { updateSilently: true, + fetchedVia: QuoteFetchedVia.Heartbeat, }); }, shouldPerformImmediatelyOnStart); }; -- cgit v1.2.3 From d3739488aed89ce98e805d48ec14a0d2608f85d7 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 27 Nov 2018 15:28:38 -0800 Subject: Tracking quote errors --- packages/instant/src/util/analytics.ts | 16 ++++++++++++++++ packages/instant/src/util/buy_quote_updater.ts | 7 +++++++ 2 files changed, 23 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 204b6921d..dd6021453 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,4 +1,5 @@ import { BuyQuote } from '@0x/asset-buyer'; +import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, QuoteFetchedVia } from '../types'; @@ -184,4 +185,19 @@ export const analytics = { ...buyQuoteEventProperties(buyQuote), fetchedVia, }), + trackQuoteError: ( + errorMessage: string, + assetName: string, + assetData: string, + assetAmount: BigNumber, + fetchedVia: QuoteFetchedVia, + ) => { + trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({ + errorMessage, + assetName, + assetData, + assetAmount: assetAmount.toString(), + fetchedVia, + }); + }, }; diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 59d3a85af..3c982ed1f 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -37,6 +37,13 @@ export const buyQuoteUpdater = { } catch (error) { if (options.dispatchErrors) { dispatch(actions.setQuoteRequestStateFailure()); + analytics.trackQuoteError( + error.message ? error.message : 'other', + asset.metaData.name, + asset.assetData, + assetUnitAmount, + options.fetchedVia, + ); let errorMessage; if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); -- cgit v1.2.3 From ca894935f269a385f28e5d3a51720282ab403697 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 28 Nov 2018 10:07:11 -0800 Subject: Take out asset name and data as we can use the selected event properties --- packages/instant/src/util/analytics.ts | 10 +--------- packages/instant/src/util/buy_quote_updater.ts | 8 +------- 2 files changed, 2 insertions(+), 16 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index dd6021453..b85c6cee2 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -185,17 +185,9 @@ export const analytics = { ...buyQuoteEventProperties(buyQuote), fetchedVia, }), - trackQuoteError: ( - errorMessage: string, - assetName: string, - assetData: string, - assetAmount: BigNumber, - fetchedVia: QuoteFetchedVia, - ) => { + trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchedVia: QuoteFetchedVia) => { trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({ errorMessage, - assetName, - assetData, assetAmount: assetAmount.toString(), fetchedVia, }); diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 3c982ed1f..d6c4bd71b 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -37,13 +37,7 @@ export const buyQuoteUpdater = { } catch (error) { if (options.dispatchErrors) { dispatch(actions.setQuoteRequestStateFailure()); - analytics.trackQuoteError( - error.message ? error.message : 'other', - asset.metaData.name, - asset.assetData, - assetUnitAmount, - options.fetchedVia, - ); + analytics.trackQuoteError(error.message ? error.message : 'other', assetUnitAmount, options.fetchedVia); let errorMessage; if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); -- cgit v1.2.3 From 1b23c430fcb6e4e816b60f85343b5fe009ab4754 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 28 Nov 2018 10:25:04 -0800 Subject: fix(instant): Half opacity instead of darkening on hover for clickable text --- packages/instant/src/components/ui/text.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx index 8e573d7b9..e149e2d8e 100644 --- a/packages/instant/src/components/ui/text.tsx +++ b/packages/instant/src/components/ui/text.tsx @@ -31,7 +31,7 @@ export const Text: React.StatelessComponent = ({ href, onClick, ...re return ; }; -const darkenOnHoverAmount = 0.3; +const opacityOnHoverAmount = 0.5; export const StyledText = styled.div < TextProps > @@ -56,8 +56,7 @@ export const StyledText = ${props => (props.textAlign ? `text-align: ${props.textAlign}` : '')}; ${props => (props.width ? `width: ${props.width}` : '')}; &:hover { - ${props => - props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''}; + ${props => (props.onClick ? `opacity: ${opacityOnHoverAmount};` : '')}; } } `; -- cgit v1.2.3 From 06b2f12b10c6c2030b326b3e817d497415862299 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 28 Nov 2018 10:38:24 -0800 Subject: fix(instant): Fix uncontrolled input warning for token selector --- packages/instant/src/components/erc20_token_selector.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 0a3d4427a..f7d5a4fe4 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -19,12 +19,12 @@ export interface ERC20TokenSelectorProps { } export interface ERC20TokenSelectorState { - searchQuery?: string; + searchQuery: string; } export class ERC20TokenSelector extends React.Component { public state: ERC20TokenSelectorState = { - searchQuery: undefined, + searchQuery: '', }; public render(): React.ReactNode { const { tokens, onTokenSelect } = this.props; @@ -62,10 +62,10 @@ export class ERC20TokenSelector extends React.Component }; private readonly _isTokenQueryMatch = (token: ERC20Asset): boolean => { const { searchQuery } = this.state; - if (_.isUndefined(searchQuery)) { + const searchQueryLowerCase = searchQuery.toLowerCase().trim(); + if (searchQueryLowerCase === '') { return true; } - const searchQueryLowerCase = searchQuery.toLowerCase(); const tokenName = token.metaData.name.toLowerCase(); const tokenSymbol = token.metaData.symbol.toLowerCase(); return _.startsWith(tokenSymbol, searchQueryLowerCase) || _.startsWith(tokenName, searchQueryLowerCase); -- cgit v1.2.3 From 3c000e70e3fe507b199871879dde54bcefe01e1e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 28 Nov 2018 10:48:38 -0800 Subject: Linting --- packages/instant/src/components/ui/text.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx index e149e2d8e..282477758 100644 --- a/packages/instant/src/components/ui/text.tsx +++ b/packages/instant/src/components/ui/text.tsx @@ -1,4 +1,3 @@ -import { darken } from 'polished'; import * as React from 'react'; import { ColorOption, styled } from '../../style/theme'; -- cgit v1.2.3 From 5415d1589e922dc689eaa9ec64ab830f3fd46af4 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 28 Nov 2018 10:58:41 -0800 Subject: feat: write version info to window --- packages/instant/src/index.umd.ts | 3 +++ packages/instant/src/util/version.ts | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 packages/instant/src/util/version.ts (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 3a8694d6a..063874d36 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -6,6 +6,9 @@ import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { assert } from './util/assert'; import { util } from './util/util'; +import { versionUtil } from './util/version'; + +versionUtil.writeVersionInfoToWindow(); const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); diff --git a/packages/instant/src/util/version.ts b/packages/instant/src/util/version.ts new file mode 100644 index 000000000..5264cd659 --- /dev/null +++ b/packages/instant/src/util/version.ts @@ -0,0 +1,8 @@ +const anyWindow = window as any; + +export const versionUtil = { + writeVersionInfoToWindow: () => { + anyWindow.__zeroExInstantGitSha = process.env.GIT_SHA; + anyWindow.__zeroExInstantNpmVersion = process.env.NPM_PACKAGE_VERSION; + }, +}; -- cgit v1.2.3 From 1375d694ac2026ff8fe553f2b7bc9daa4d5f6d7d Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 28 Nov 2018 12:58:11 -0800 Subject: fix: instant error no longer makes instant move --- packages/instant/src/components/ui/container.tsx | 2 ++ packages/instant/src/containers/latest_error.tsx | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 4dafe1386..2143b0503 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -28,6 +28,7 @@ export interface ContainerProps { className?: string; backgroundColor?: ColorOption; hasBoxShadow?: boolean; + isHidden?: boolean; zIndex?: number; whiteSpace?: string; opacity?: number; @@ -70,6 +71,7 @@ export const Container = ${props => props.width && stylesForMedia('width', props.width)} ${props => props.height && stylesForMedia('height', props.height)} ${props => props.borderRadius && stylesForMedia('border-radius', props.borderRadius)} + ${props => (props.isHidden ? 'visibility: hidden;' : '')} background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')}; &:hover { diff --git a/packages/instant/src/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx index b7cfdb504..0d4349124 100644 --- a/packages/instant/src/containers/latest_error.tsx +++ b/packages/instant/src/containers/latest_error.tsx @@ -4,6 +4,7 @@ import { connect } from 'react-redux'; import { Dispatch } from 'redux'; import { SlidingError } from '../components/sliding_error'; +import { Container } from '../components/ui/container'; import { Overlay } from '../components/ui/overlay'; import { Action } from '../redux/actions'; import { State } from '../redux/reducer'; @@ -23,7 +24,12 @@ export interface LatestErrorComponentProps { export const LatestErrorComponent: React.StatelessComponent = props => { if (!props.latestErrorMessage) { - return
; + // Render a hidden SlidingError such that instant does not move when a real error is rendered. + return ( + + + + ); } return ( -- cgit v1.2.3 From 6e3378d79f3edf46a24cacbe2ec920e0caaf5a93 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 28 Nov 2018 13:09:19 -0800 Subject: fix: instant height change on loading state change --- packages/instant/src/components/payment_method.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index ebcd62f35..c23b43267 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -26,7 +26,7 @@ export interface PaymentMethodProps { export class PaymentMethod extends React.Component { public render(): React.ReactNode { return ( - + { const colors = { primaryColor, secondaryColor }; switch (account.state) { case AccountState.Loading: - // Just take up the same amount of space as the other states. - return ; + return null; case AccountState.Locked: return ( Date: Wed, 28 Nov 2018 13:16:09 -0800 Subject: fix: dont allow price labels to wrap --- packages/instant/src/components/instant_heading.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index ace577824..808c6dc7f 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -107,7 +107,14 @@ export class InstantHeading extends React.Component { private readonly _renderEthAmount = (): React.ReactNode => { return ( - + {format.ethBaseUnitAmount( this.props.totalEthBaseUnitAmount, 4, @@ -119,7 +126,7 @@ export class InstantHeading extends React.Component { private readonly _renderDollarAmount = (): React.ReactNode => { return ( - + {format.ethBaseUnitAmountInUsd( this.props.totalEthBaseUnitAmount, this.props.ethUsdPrice, -- cgit v1.2.3 From 85d1dba1ef5ba4d34de46cb7eb54bfdc7acae380 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 28 Nov 2018 13:35:38 -0800 Subject: fix: notify of the used font size for re-renders of scaling input --- packages/instant/src/components/scaling_input.tsx | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 129162a74..791692257 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -98,6 +98,12 @@ export class ScalingInput extends React.Component Date: Tue, 27 Nov 2018 16:19:50 -0800 Subject: fix(instant): Progress bar background color should be 10% primary color --- packages/instant/src/components/timed_progress_bar.tsx | 17 +++++++++++++---- packages/instant/src/components/ui/container.tsx | 13 ++++++++++++- packages/instant/src/style/theme.ts | 12 ++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index 8465b9cd0..fb3927088 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -1,8 +1,9 @@ import * as _ from 'lodash'; +import { transparentize } from 'polished'; import * as React from 'react'; import { PROGRESS_FINISH_ANIMATION_TIME_MS, PROGRESS_STALL_AT_WIDTH } from '../constants'; -import { ColorOption, css, keyframes, styled } from '../style/theme'; +import { ColorOption, css, keyframes, styled, ThemeConsumer } from '../style/theme'; import { Container } from './ui/container'; @@ -93,8 +94,16 @@ export interface ProgressBarProps extends ProgressProps {} export const ProgressBar: React.ComponentType> = React.forwardRef( (props, ref) => ( - - - + + {theme => ( + + + + )} + ), ); diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 4dafe1386..a015ab5bc 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -27,6 +27,7 @@ export interface ContainerProps { borderBottom?: string; className?: string; backgroundColor?: ColorOption; + rawBackgroundColor?: string; hasBoxShadow?: boolean; zIndex?: number; whiteSpace?: string; @@ -38,6 +39,16 @@ export interface ContainerProps { flexGrow?: string | number; } +const getBackgroundColor = (theme: any, backgroundColor?: ColorOption, rawBackgroundColor?: string): string => { + if (backgroundColor) { + return theme[backgroundColor] as string; + } + if (rawBackgroundColor) { + return rawBackgroundColor; + } + return 'none'; +}; + export const Container = styled.div < ContainerProps > @@ -70,7 +81,7 @@ export const Container = ${props => props.width && stylesForMedia('width', props.width)} ${props => props.height && stylesForMedia('height', props.height)} ${props => props.borderRadius && stylesForMedia('border-radius', props.borderRadius)} - background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; + background-color: ${props => getBackgroundColor(props.theme, props.backgroundColor, props.rawBackgroundColor)}; border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')}; &:hover { ${props => diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index a0751286b..71e4b7052 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -1,6 +1,14 @@ import * as styledComponents from 'styled-components'; -const { default: styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider } = styledComponents; +const { + default: styled, + css, + keyframes, + withTheme, + createGlobalStyle, + ThemeConsumer, + ThemeProvider, +} = styledComponents; export type Theme = { [key in ColorOption]: string }; @@ -45,4 +53,4 @@ export const generateOverlayBlack = (opacity = 0.6) => { return `rgba(0, 0, 0, ${opacity})`; }; -export { styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider }; +export { styled, css, keyframes, withTheme, createGlobalStyle, ThemeConsumer, ThemeProvider }; -- cgit v1.2.3 From f4cc14f43862c639d2cf9f6e5359e4822f1bcacf Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 28 Nov 2018 14:11:06 -0800 Subject: QuoteFetchedVia -> QuoteFetchOrigin --- packages/instant/src/components/zero_ex_instant_provider.tsx | 4 ++-- .../instant/src/containers/selected_erc20_asset_amount_input.ts | 4 ++-- packages/instant/src/redux/async_data.ts | 4 ++-- packages/instant/src/types.ts | 2 +- packages/instant/src/util/analytics.ts | 6 +++--- packages/instant/src/util/buy_quote_updater.ts | 4 ++-- packages/instant/src/util/heartbeater_factory.ts | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 9f2c95e36..7841f5bf7 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -11,7 +11,7 @@ import { asyncData } from '../redux/async_data'; import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; -import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource, QuoteFetchedVia } from '../types'; +import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource, QuoteFetchOrigin } from '../types'; import { analytics, disableAnalytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; @@ -117,7 +117,7 @@ export class ZeroExInstantProvider extends React.Component { const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state; const assetBuyer = providerState.assetBuyer; diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index a8139c185..ea2bcbc2f 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -21,7 +21,7 @@ export enum OrderProcessState { Failure = 'FAILURE', } -export enum QuoteFetchedVia { +export enum QuoteFetchOrigin { Manual = 'Manual', Heartbeat = 'Heartbeat', } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index b85c6cee2..c0ed8c638 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; -import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, QuoteFetchedVia } from '../types'; +import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, QuoteFetchOrigin } from '../types'; import { EventProperties, heapUtil } from './heap'; @@ -180,12 +180,12 @@ export const analytics = { trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload), trackTokenSelectorSearched: (searchText: string) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }), - trackQuoteFetched: (buyQuote: BuyQuote, fetchedVia: QuoteFetchedVia) => + trackQuoteFetched: (buyQuote: BuyQuote, fetchedVia: QuoteFetchOrigin) => trackingEventFnWithPayload(EventNames.QUOTE_FETCHED)({ ...buyQuoteEventProperties(buyQuote), fetchedVia, }), - trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchedVia: QuoteFetchedVia) => { + trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchedVia: QuoteFetchOrigin) => { trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({ errorMessage, assetAmount: assetAmount.toString(), diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index d6c4bd71b..14af57660 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -6,7 +6,7 @@ import { Dispatch } from 'redux'; import { oc } from 'ts-optchain'; import { Action, actions } from '../redux/actions'; -import { AffiliateInfo, ERC20Asset, QuoteFetchedVia } from '../types'; +import { AffiliateInfo, ERC20Asset, QuoteFetchOrigin } from '../types'; import { analytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; @@ -20,7 +20,7 @@ export const buyQuoteUpdater = { options: { setPending: boolean; dispatchErrors: boolean; - fetchedVia: QuoteFetchedVia; + fetchedVia: QuoteFetchOrigin; affiliateInfo?: AffiliateInfo; }, ): Promise => { diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts index bf9e4291f..84aeb4dbc 100644 --- a/packages/instant/src/util/heartbeater_factory.ts +++ b/packages/instant/src/util/heartbeater_factory.ts @@ -1,6 +1,6 @@ import { asyncData } from '../redux/async_data'; import { Store } from '../redux/store'; -import { QuoteFetchedVia } from '../types'; +import { QuoteFetchOrigin } from '../types'; import { Heartbeater } from './heartbeater'; @@ -20,7 +20,7 @@ export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): H return new Heartbeater(async () => { await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, { updateSilently: true, - fetchedVia: QuoteFetchedVia.Heartbeat, + fetchedVia: QuoteFetchOrigin.Heartbeat, }); }, shouldPerformImmediatelyOnStart); }; -- cgit v1.2.3 From ec01893e9c987fcbd3fd7bcb4ec34498a6f516cc Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 28 Nov 2018 14:11:53 -0800 Subject: fetchedVia -> fetchOrigin --- packages/instant/src/components/zero_ex_instant_provider.tsx | 2 +- .../src/containers/selected_erc20_asset_amount_input.ts | 2 +- packages/instant/src/redux/async_data.ts | 4 ++-- packages/instant/src/util/analytics.ts | 8 ++++---- packages/instant/src/util/buy_quote_updater.ts | 10 +++++++--- packages/instant/src/util/heartbeater_factory.ts | 2 +- 6 files changed, 16 insertions(+), 12 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 7841f5bf7..f7880fc12 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -117,7 +117,7 @@ export class ZeroExInstantProvider extends React.Component { const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state; const assetBuyer = providerState.assetBuyer; @@ -102,7 +102,7 @@ export const asyncData = { { setPending: !options.updateSilently, dispatchErrors: !options.updateSilently, - fetchedVia: options.fetchedVia, + fetchOrigin: options.fetchOrigin, affiliateInfo, }, ); diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index c0ed8c638..99e8736d3 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -180,16 +180,16 @@ export const analytics = { trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload), trackTokenSelectorSearched: (searchText: string) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }), - trackQuoteFetched: (buyQuote: BuyQuote, fetchedVia: QuoteFetchOrigin) => + trackQuoteFetched: (buyQuote: BuyQuote, fetchOrigin: QuoteFetchOrigin) => trackingEventFnWithPayload(EventNames.QUOTE_FETCHED)({ ...buyQuoteEventProperties(buyQuote), - fetchedVia, + fetchOrigin, }), - trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchedVia: QuoteFetchOrigin) => { + trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchOrigin: QuoteFetchOrigin) => { trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({ errorMessage, assetAmount: assetAmount.toString(), - fetchedVia, + fetchOrigin, }); }, }; diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 14af57660..06474b69f 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -20,7 +20,7 @@ export const buyQuoteUpdater = { options: { setPending: boolean; dispatchErrors: boolean; - fetchedVia: QuoteFetchOrigin; + fetchOrigin: QuoteFetchOrigin; affiliateInfo?: AffiliateInfo; }, ): Promise => { @@ -37,7 +37,11 @@ export const buyQuoteUpdater = { } catch (error) { if (options.dispatchErrors) { dispatch(actions.setQuoteRequestStateFailure()); - analytics.trackQuoteError(error.message ? error.message : 'other', assetUnitAmount, options.fetchedVia); + analytics.trackQuoteError( + error.message ? error.message : 'other', + assetUnitAmount, + options.fetchOrigin, + ); let errorMessage; if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); @@ -65,6 +69,6 @@ export const buyQuoteUpdater = { errorFlasher.clearError(dispatch); // invalidate the last buy quote. dispatch(actions.updateLatestBuyQuote(newBuyQuote)); - analytics.trackQuoteFetched(newBuyQuote, options.fetchedVia); + analytics.trackQuoteFetched(newBuyQuote, options.fetchOrigin); }, }; diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts index 84aeb4dbc..5f7ef55e5 100644 --- a/packages/instant/src/util/heartbeater_factory.ts +++ b/packages/instant/src/util/heartbeater_factory.ts @@ -20,7 +20,7 @@ export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): H return new Heartbeater(async () => { await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, { updateSilently: true, - fetchedVia: QuoteFetchOrigin.Heartbeat, + fetchOrigin: QuoteFetchOrigin.Heartbeat, }); }, shouldPerformImmediatelyOnStart); }; -- cgit v1.2.3 From 208ee935c843cfff9f0559a4c4058af3908f6261 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 28 Nov 2018 14:17:26 -0800 Subject: Move fetch origin out of options --- packages/instant/src/components/zero_ex_instant_provider.tsx | 3 +-- .../src/containers/selected_erc20_asset_amount_input.ts | 3 +-- packages/instant/src/redux/async_data.ts | 5 +++-- packages/instant/src/util/buy_quote_updater.ts | 10 +++------- packages/instant/src/util/heartbeater_factory.ts | 12 ++++++++---- 5 files changed, 16 insertions(+), 17 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index f7880fc12..a4a03bbf4 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -115,9 +115,8 @@ export class ZeroExInstantProvider extends React.Component { const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state; const assetBuyer = providerState.assetBuyer; @@ -99,10 +100,10 @@ export const asyncData = { dispatch, selectedAsset as ERC20Asset, selectedAssetUnitAmount, + fetchOrigin, { setPending: !options.updateSilently, dispatchErrors: !options.updateSilently, - fetchOrigin: options.fetchOrigin, affiliateInfo, }, ); diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 06474b69f..5685a7d00 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -17,10 +17,10 @@ export const buyQuoteUpdater = { dispatch: Dispatch, asset: ERC20Asset, assetUnitAmount: BigNumber, + fetchOrigin: QuoteFetchOrigin, options: { setPending: boolean; dispatchErrors: boolean; - fetchOrigin: QuoteFetchOrigin; affiliateInfo?: AffiliateInfo; }, ): Promise => { @@ -37,11 +37,7 @@ export const buyQuoteUpdater = { } catch (error) { if (options.dispatchErrors) { dispatch(actions.setQuoteRequestStateFailure()); - analytics.trackQuoteError( - error.message ? error.message : 'other', - assetUnitAmount, - options.fetchOrigin, - ); + analytics.trackQuoteError(error.message ? error.message : 'other', assetUnitAmount, fetchOrigin); let errorMessage; if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); @@ -69,6 +65,6 @@ export const buyQuoteUpdater = { errorFlasher.clearError(dispatch); // invalidate the last buy quote. dispatch(actions.updateLatestBuyQuote(newBuyQuote)); - analytics.trackQuoteFetched(newBuyQuote, options.fetchOrigin); + analytics.trackQuoteFetched(newBuyQuote, fetchOrigin); }, }; diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts index 5f7ef55e5..cf29bf3ea 100644 --- a/packages/instant/src/util/heartbeater_factory.ts +++ b/packages/instant/src/util/heartbeater_factory.ts @@ -18,9 +18,13 @@ export const generateAccountHeartbeater = (options: HeartbeatFactoryOptions): He export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => { const { store, shouldPerformImmediatelyOnStart } = options; return new Heartbeater(async () => { - await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, { - updateSilently: true, - fetchOrigin: QuoteFetchOrigin.Heartbeat, - }); + await asyncData.fetchCurrentBuyQuoteAndDispatchToStore( + store.getState(), + store.dispatch, + QuoteFetchOrigin.Heartbeat, + { + updateSilently: true, + }, + ); }, shouldPerformImmediatelyOnStart); }; -- cgit v1.2.3 From b9c983b4d691e58894b8b47f8e5952fdfcc275f9 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 28 Nov 2018 14:24:02 -0800 Subject: Use base unit value --- packages/instant/src/util/buy_quote_updater.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 5685a7d00..c1899f8c1 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -37,7 +37,7 @@ export const buyQuoteUpdater = { } catch (error) { if (options.dispatchErrors) { dispatch(actions.setQuoteRequestStateFailure()); - analytics.trackQuoteError(error.message ? error.message : 'other', assetUnitAmount, fetchOrigin); + analytics.trackQuoteError(error.message ? error.message : 'other', baseUnitValue, fetchOrigin); let errorMessage; if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); -- cgit v1.2.3 From 76259352229881287a94cb561f82498920de5443 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 28 Nov 2018 16:36:52 -0800 Subject: feat: write version info directly to exported object --- packages/instant/src/index.umd.ts | 7 ++++--- packages/instant/src/util/version.ts | 8 -------- 2 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 packages/instant/src/util/version.ts (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 063874d36..45369d9ee 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -6,9 +6,6 @@ import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { assert } from './util/assert'; import { util } from './util/util'; -import { versionUtil } from './util/version'; - -versionUtil.writeVersionInfoToWindow(); const isInstantRendered = (): boolean => !!document.getElementById(INJECTED_DIV_ID); @@ -113,3 +110,7 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z }; window.onpopstate = onPopStateHandler; }; + +// Write version info to the exported object for debugging +export const GitSha = process.env.GIT_SHA; +export const NpmVersion = process.env.NPM_PACKAGE_VERSION; diff --git a/packages/instant/src/util/version.ts b/packages/instant/src/util/version.ts deleted file mode 100644 index 5264cd659..000000000 --- a/packages/instant/src/util/version.ts +++ /dev/null @@ -1,8 +0,0 @@ -const anyWindow = window as any; - -export const versionUtil = { - writeVersionInfoToWindow: () => { - anyWindow.__zeroExInstantGitSha = process.env.GIT_SHA; - anyWindow.__zeroExInstantNpmVersion = process.env.NPM_PACKAGE_VERSION; - }, -}; -- cgit v1.2.3 From 5c66f9117fa0bf6a5be29243dbecbfe016b95345 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 29 Nov 2018 08:19:39 -0800 Subject: assetAmount -> assetBuyAmount --- packages/instant/src/util/analytics.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 1468ef4a8..4b8aff4c9 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -206,10 +206,10 @@ export const analytics = { ...buyQuoteEventProperties(buyQuote), fetchOrigin, }), - trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchOrigin: QuoteFetchOrigin) => { + trackQuoteError: (errorMessage: string, assetBuyAmount: BigNumber, fetchOrigin: QuoteFetchOrigin) => { trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({ errorMessage, - assetAmount: assetAmount.toString(), + assetBuyAmount: assetBuyAmount.toString(), fetchOrigin, }); }, -- cgit v1.2.3 From bd03df8af02169ef88207eb14051bc79231927aa Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 29 Nov 2018 12:05:20 -0800 Subject: feat(instant): Cleaner config-specific setup --- packages/instant/src/constants.ts | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index be6077ca9..e70b3f1d8 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -20,6 +20,12 @@ export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; +export const INSTANT_ENVIRONMENT = process.env.INSTANT_ENVIRONMENT as + | 'dogfood' + | 'staging' + | 'development' + | 'production_cdn' + | 'production_standalone'; export const COINBASE_WALLET_IOS_APP_STORE_URL = 'https://itunes.apple.com/us/app/coinbase-wallet/id1278383455?mt=8'; export const COINBASE_WALLET_ANDROID_APP_STORE_URL = 'https://play.google.com/store/apps/details?id=org.toshi&hl=en'; export const COINBASE_WALLET_SITE_URL = 'https://wallet.coinbase.com/'; -- cgit v1.2.3 From 0af07bcf49f62aeeed4aa5ae7bf0e4d5835836e9 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 29 Nov 2018 14:10:12 -0800 Subject: feat: move instant base config to types file --- .../src/components/zero_ex_instant_provider.tsx | 20 ++------------------ packages/instant/src/types.ts | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 18 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index e006a5a5f..a57dd7993 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -11,7 +11,7 @@ import { asyncData } from '../redux/async_data'; import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; -import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; +import { AccountState, AffiliateInfo, AssetMetaData, Network, ZeroExInstantBaseConfig } from '../types'; import { analytics, disableAnalytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; @@ -20,23 +20,7 @@ import { Heartbeater } from '../util/heartbeater'; import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory'; import { providerStateFactory } from '../util/provider_state_factory'; -export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps & - Partial; - -export interface ZeroExInstantProviderRequiredProps { - orderSource: OrderSource; -} - -export interface ZeroExInstantProviderOptionalProps { - provider: Provider; - availableAssetDatas: string[]; - defaultAssetBuyAmount: number; - defaultSelectedAssetData: string; - additionalAssetMetaDataMap: ObjectMap; - networkId: Network; - affiliateInfo: AffiliateInfo; - shouldDisableAnalyticsTracking: boolean; -} +export type ZeroExInstantProviderProps = ZeroExInstantBaseConfig; export class ZeroExInstantProvider extends React.Component { private readonly _store: Store; diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 999d50fed..233390bf5 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -167,3 +167,20 @@ export enum ProviderType { Cipher = 'CIPHER', Fallback = 'FALLBACK', } + +export interface ZeroExInstantRequiredBaseConfig { + orderSource: OrderSource; +} + +export interface ZeroExInstantOptionalBaseConfig { + provider: Provider; + availableAssetDatas: string[]; + defaultAssetBuyAmount: number; + defaultSelectedAssetData: string; + additionalAssetMetaDataMap: ObjectMap; + networkId: Network; + affiliateInfo: AffiliateInfo; + shouldDisableAnalyticsTracking: boolean; +} + +export type ZeroExInstantBaseConfig = ZeroExInstantRequiredBaseConfig & Partial; -- cgit v1.2.3 From d99bdcf036eebc6613274fecfdd19187eaf4aa1a Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 29 Nov 2018 15:13:55 -0800 Subject: cdn approach to identifyign environments --- packages/instant/src/constants.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index e70b3f1d8..3370af094 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -20,12 +20,7 @@ export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; -export const INSTANT_ENVIRONMENT = process.env.INSTANT_ENVIRONMENT as - | 'dogfood' - | 'staging' - | 'development' - | 'production_cdn' - | 'production_standalone'; +export const INSTANT_CDN = process.env.INSTANT_CDN as 'production' | 'dogfood' | 'staging' | undefined; export const COINBASE_WALLET_IOS_APP_STORE_URL = 'https://itunes.apple.com/us/app/coinbase-wallet/id1278383455?mt=8'; export const COINBASE_WALLET_ANDROID_APP_STORE_URL = 'https://play.google.com/store/apps/details?id=org.toshi&hl=en'; export const COINBASE_WALLET_SITE_URL = 'https://wallet.coinbase.com/'; -- cgit v1.2.3 From 6c941eebeae4828177b0d195168f5f1b757432e2 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 30 Nov 2018 08:40:25 -0800 Subject: add missing import from merge --- packages/instant/src/util/analytics.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 2f76c4a76..714ff8bcd 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -6,6 +6,7 @@ import { AffiliateInfo, Asset, Network, + OrderProcessState, OrderSource, ProviderState, QuoteFetchOrigin, -- cgit v1.2.3 From 09813cb1d83da4c571cf69a448c35c5f6af94dec Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 30 Nov 2018 11:20:07 -0800 Subject: fix: address PR feedback --- packages/instant/src/index.umd.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 45369d9ee..95080f829 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -112,5 +112,5 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z }; // Write version info to the exported object for debugging -export const GitSha = process.env.GIT_SHA; -export const NpmVersion = process.env.NPM_PACKAGE_VERSION; +export const GIT_SHA = process.env.GIT_SHA; +export const NPM_VERSION = process.env.NPM_PACKAGE_VERSION; -- cgit v1.2.3 From ab631060a05fc6344ef6e2de7b0e6a0f0096e8ed Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 30 Nov 2018 12:42:40 -0800 Subject: cdn -> dischargeTarget, and report to heap --- packages/instant/src/components/zero_ex_instant_provider.tsx | 7 ++++++- packages/instant/src/constants.ts | 6 +++++- packages/instant/src/util/analytics.ts | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 9814aabf8..dc57513d1 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -5,7 +5,11 @@ import * as _ from 'lodash'; import * as React from 'react'; import { Provider as ReduxProvider } from 'react-redux'; -import { ACCOUNT_UPDATE_INTERVAL_TIME_MS, BUY_QUOTE_UPDATE_INTERVAL_TIME_MS } from '../constants'; +import { + ACCOUNT_UPDATE_INTERVAL_TIME_MS, + BUY_QUOTE_UPDATE_INTERVAL_TIME_MS, + INSTANT_DISCHARGE_TARGET, +} from '../constants'; import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider'; import { asyncData } from '../redux/async_data'; import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; @@ -132,6 +136,7 @@ export class ZeroExInstantProvider extends React.Component Date: Fri, 30 Nov 2018 12:58:42 -0800 Subject: removing unused references --- packages/instant/src/components/standard_sliding_panel.tsx | 2 +- packages/instant/src/redux/analytics_middleware.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/standard_sliding_panel.tsx b/packages/instant/src/components/standard_sliding_panel.tsx index f587ff79a..9f517d273 100644 --- a/packages/instant/src/components/standard_sliding_panel.tsx +++ b/packages/instant/src/components/standard_sliding_panel.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { SlideAnimationState, StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types'; +import { StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types'; import { InstallWalletPanelContent } from './install_wallet_panel_content'; import { SlidingPanel } from './sliding_panel'; diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 3dc5fe924..47876ca2d 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -3,7 +3,7 @@ import * as _ from 'lodash'; import { Middleware } from 'redux'; import { ETH_DECIMALS } from '../constants'; -import { Account, AccountState, StandardSlidingPanelContent } from '../types'; +import { AccountState, StandardSlidingPanelContent } from '../types'; import { analytics } from '../util/analytics'; import { Action, ActionTypes } from './actions'; -- cgit v1.2.3 From 9ebe8d63c829ea4b6b1fbbdf7a132c7f9b8f56dc Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 30 Nov 2018 13:34:03 -0800 Subject: fix: push to history edge case for second render where onpopstate is not defined on first render --- packages/instant/src/index.umd.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 95080f829..869b52353 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -91,10 +91,11 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z const anyWindow = window as any; if (window.onpopstate && !anyWindow.__zeroExInstantIntegratorsPopStateHandler) { anyWindow.__zeroExInstantIntegratorsPopStateHandler = window.onpopstate.bind(window); + } else { + anyWindow.__zeroExInstantIntegratorsPopStateHandler = util.boundNoop; } - const integratorsOnPopStateHandler = anyWindow.__zeroExInstantIntegratorsPopStateHandler || util.boundNoop; const onPopStateHandler = (e: PopStateEvent) => { - integratorsOnPopStateHandler(e); + anyWindow.__zeroExInstantIntegratorsPopStateHandler(e); const newState = e.state; if (newState && newState.zeroExInstantShowing) { // We have returned to a history state that expects instant to be rendered. -- cgit v1.2.3 From e47dd4a83ed52dd246beddeb93fc5de3378fae24 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 30 Nov 2018 13:47:47 -0800 Subject: chore: lint --- packages/instant/src/components/standard_sliding_panel.tsx | 2 +- packages/instant/src/index.umd.ts | 9 ++++----- packages/instant/src/redux/analytics_middleware.ts | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/standard_sliding_panel.tsx b/packages/instant/src/components/standard_sliding_panel.tsx index f587ff79a..9f517d273 100644 --- a/packages/instant/src/components/standard_sliding_panel.tsx +++ b/packages/instant/src/components/standard_sliding_panel.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { SlideAnimationState, StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types'; +import { StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types'; import { InstallWalletPanelContent } from './install_wallet_panel_content'; import { SlidingPanel } from './sliding_panel'; diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 869b52353..3d7774858 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -89,11 +89,10 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z // If the integrator defined a popstate handler, save it to __zeroExInstantIntegratorsPopStateHandler // unless we have already done so on a previous render. const anyWindow = window as any; - if (window.onpopstate && !anyWindow.__zeroExInstantIntegratorsPopStateHandler) { - anyWindow.__zeroExInstantIntegratorsPopStateHandler = window.onpopstate.bind(window); - } else { - anyWindow.__zeroExInstantIntegratorsPopStateHandler = util.boundNoop; - } + const popStateExistsAndNotSetPreviously = window.onpopstate && !anyWindow.__zeroExInstantIntegratorsPopStateHandler; + anyWindow.__zeroExInstantIntegratorsPopStateHandler = popStateExistsAndNotSetPreviously + ? anyWindow.onpopstate.bind(window) + : util.boundNoop; const onPopStateHandler = (e: PopStateEvent) => { anyWindow.__zeroExInstantIntegratorsPopStateHandler(e); const newState = e.state; diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 3dc5fe924..47876ca2d 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -3,7 +3,7 @@ import * as _ from 'lodash'; import { Middleware } from 'redux'; import { ETH_DECIMALS } from '../constants'; -import { Account, AccountState, StandardSlidingPanelContent } from '../types'; +import { AccountState, StandardSlidingPanelContent } from '../types'; import { analytics } from '../util/analytics'; import { Action, ActionTypes } from './actions'; -- cgit v1.2.3 From b19700221ff53d2a9d9ce716c6d6011b69e4cd4a Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 30 Nov 2018 14:09:43 -0800 Subject: update with new CDN --- packages/instant/src/constants.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 2fe0f4b89..ab644e0a4 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -28,8 +28,7 @@ export const HOST_DOMAINS = [ 'localhost', '127.0.0.1', '0.0.0.0', - 'unpkg.com', - 'jsdelivr.com', + 'https://instant.0xproject.com', ]; export const ROLLBAR_CLIENT_TOKEN = process.env.ROLLBAR_CLIENT_TOKEN; export const ROLLBAR_ENABLED = process.env.ROLLBAR_ENABLED; -- cgit v1.2.3 From 6a3f295b1fcb184b3dda24f06a0f5609beb70427 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 30 Nov 2018 14:16:49 -0800 Subject: Take out https:// prefix --- packages/instant/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index ab644e0a4..1194cf881 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -28,7 +28,7 @@ export const HOST_DOMAINS = [ 'localhost', '127.0.0.1', '0.0.0.0', - 'https://instant.0xproject.com', + 'instant.0xproject.com', ]; export const ROLLBAR_CLIENT_TOKEN = process.env.ROLLBAR_CLIENT_TOKEN; export const ROLLBAR_ENABLED = process.env.ROLLBAR_ENABLED; -- cgit v1.2.3 From 800016b430a941682d4cdb89f85b46c27b835e39 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 1 Dec 2018 00:03:07 -0800 Subject: fix(instant) various token selector fixes --- packages/instant/src/components/search_input.tsx | 8 ++++---- packages/instant/src/components/ui/container.tsx | 1 + packages/instant/src/components/ui/input.tsx | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/search_input.tsx b/packages/instant/src/components/search_input.tsx index 3a693b9f8..71bc18915 100644 --- a/packages/instant/src/components/search_input.tsx +++ b/packages/instant/src/components/search_input.tsx @@ -13,10 +13,10 @@ export interface SearchInputProps extends InputProps { } export const SearchInput: React.StatelessComponent = props => ( - - - - + + + + ); diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index e7d909d92..636eb8fc9 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -77,6 +77,7 @@ export const Container = ${props => cssRuleIfExists(props, 'opacity')} ${props => cssRuleIfExists(props, 'cursor')} ${props => cssRuleIfExists(props, 'overflow')} + ${props => (props.overflow === 'scroll' ? `-webkit-overflow-scrolling: touch` : '')}; ${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')}; ${props => props.display && stylesForMedia('display', props.display)} ${props => props.width && stylesForMedia('width', props.width)} diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index 1ea5d8fe1..863c970ef 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -10,6 +10,7 @@ export interface InputProps { fontSize?: string; fontColor?: ColorOption; placeholder?: string; + type?: string; onChange?: (event: React.ChangeEvent) => void; } -- cgit v1.2.3 From c0f4a35cfd67b5de387786a582bc615375a2dd4b Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 1 Dec 2018 00:04:21 -0800 Subject: fix(instant): DGD and DGX colors --- packages/instant/src/data/asset_meta_data_map.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts index b24c9c83d..0553be7f5 100644 --- a/packages/instant/src/data/asset_meta_data_map.ts +++ b/packages/instant/src/data/asset_meta_data_map.ts @@ -83,14 +83,14 @@ export const assetMetaDataMap: ObjectMap = { '0xf47261b0000000000000000000000000e0b7927c4af23765cb51314a0e0521a9645f0e2a': { assetProxyId: AssetProxyId.ERC20, decimals: 9, - primaryColor: '#DEB564', + primaryColor: '#E1AA3E', symbol: 'dgd', name: 'DigixDao', }, '0xf47261b00000000000000000000000004f3afec4e5a3f2a6a1a411def7d7dfe50ee057bf': { assetProxyId: AssetProxyId.ERC20, decimals: 9, - primaryColor: '#DEB564', + primaryColor: '#E1AA3E', symbol: 'dgx', name: 'Digix Gold Token', }, -- cgit v1.2.3 From 593ed12d91e2e3c3f6d6feda2468b20a1fb364ac Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 1 Dec 2018 00:06:36 -0800 Subject: fix(instant): update zrx icon --- packages/instant/src/assets/icons/zrx.svg | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/assets/icons/zrx.svg b/packages/instant/src/assets/icons/zrx.svg index 07518f551..da623710b 100644 --- a/packages/instant/src/assets/icons/zrx.svg +++ b/packages/instant/src/assets/icons/zrx.svg @@ -1,3 +1,6 @@ - - + + + + + -- cgit v1.2.3 From 074944247dfdcd91fb7acbe064ccf3c3d2139ddc Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 1 Dec 2018 00:22:09 -0800 Subject: feat(instant): add token symbol to buy button text --- packages/instant/src/components/buy_button.tsx | 12 +++++++++--- packages/instant/src/components/buy_order_state_buttons.tsx | 4 +++- .../src/containers/selected_asset_buy_order_state_buttons.ts | 5 ++++- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index eeb42d6fc..1489b94d4 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -1,4 +1,5 @@ import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer'; +import { AssetProxyId } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; @@ -7,7 +8,7 @@ import { oc } from 'ts-optchain'; import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants'; import { ColorOption } from '../style/theme'; -import { AffiliateInfo, ZeroExInstantError } from '../types'; +import { AffiliateInfo, Asset, ZeroExInstantError } from '../types'; import { analytics } from '../util/analytics'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { util } from '../util/util'; @@ -21,6 +22,7 @@ export interface BuyButtonProps { assetBuyer: AssetBuyer; web3Wrapper: Web3Wrapper; affiliateInfo?: AffiliateInfo; + selectedAsset?: Asset; onValidationPending: (buyQuote: BuyQuote) => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; onSignatureDenied: (buyQuote: BuyQuote) => void; @@ -36,8 +38,12 @@ export class BuyButton extends React.Component { onBuyFailure: util.boundNoop, }; public render(): React.ReactNode { - const { buyQuote, accountAddress } = this.props; + const { buyQuote, accountAddress, selectedAsset } = this.props; const shouldDisableButton = _.isUndefined(buyQuote) || _.isUndefined(accountAddress); + const buttonText = + !_.isUndefined(selectedAsset) && selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20 + ? `Buy ${selectedAsset.metaData.symbol.toUpperCase()}` + : 'Buy Now'; return ( ); } diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index e563bec73..833818900 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -4,7 +4,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; import * as React from 'react'; import { ColorOption } from '../style/theme'; -import { AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types'; +import { AffiliateInfo, Asset, OrderProcessState, ZeroExInstantError } from '../types'; import { BuyButton } from './buy_button'; import { PlacingOrderButton } from './placing_order_button'; @@ -21,6 +21,7 @@ export interface BuyOrderStateButtonProps { assetBuyer: AssetBuyer; web3Wrapper: Web3Wrapper; affiliateInfo?: AffiliateInfo; + selectedAsset?: Asset; onViewTransaction: () => void; onValidationPending: (buyQuote: BuyQuote) => void; onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void; @@ -60,6 +61,7 @@ export const BuyOrderStateButtons: React.StatelessComponent void; } @@ -41,6 +42,7 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButt const account = state.providerState.account; const accountAddress = account.state === AccountState.Ready ? account.address : undefined; const accountEthBalanceInWei = account.state === AccountState.Ready ? account.ethBalanceInWei : undefined; + const selectedAsset = state.selectedAsset; return { accountAddress, accountEthBalanceInWei, @@ -49,6 +51,7 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButt web3Wrapper, buyQuote: state.latestBuyQuote, affiliateInfo: state.affiliateInfo, + selectedAsset, onViewTransaction: () => { if ( state.buyOrderState.processState === OrderProcessState.Processing || -- cgit v1.2.3 From 6f44944ffdb3c529b2135414818bc7e5dcc198b0 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 1 Dec 2018 00:47:07 -0800 Subject: fix(instant): darken overlay color --- packages/instant/src/components/ui/overlay.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx index f67d6fb2f..7d311dc2f 100644 --- a/packages/instant/src/components/ui/overlay.tsx +++ b/packages/instant/src/components/ui/overlay.tsx @@ -33,7 +33,7 @@ export const Overlay = Overlay.defaultProps = { zIndex: zIndex.overlayDefault, - backgroundColor: generateOverlayBlack(0.6), + backgroundColor: generateOverlayBlack(0.9), }; Overlay.displayName = 'Overlay'; -- cgit v1.2.3 From f4e0f74a6df7b8ec89308e10757e7adc9929198f Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 1 Dec 2018 01:13:15 -0800 Subject: feat(instant): provide a custom wallet display name --- packages/instant/src/components/payment_method.tsx | 12 ++++++------ packages/instant/src/components/zero_ex_instant_provider.tsx | 2 ++ .../src/containers/connected_account_payment_method.ts | 4 +++- packages/instant/src/index.umd.ts | 3 +++ packages/instant/src/redux/reducer.ts | 1 + 5 files changed, 15 insertions(+), 7 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index c23b43267..4efe5b28e 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -18,7 +18,7 @@ import { WalletPrompt } from './wallet_prompt'; export interface PaymentMethodProps { account: Account; network: Network; - walletName: string; + walletDisplayName: string; onInstallWalletClick: () => void; onUnlockWalletClick: () => void; } @@ -62,11 +62,11 @@ export class PaymentMethod extends React.Component { if (account.state === AccountState.Ready || account.state === AccountState.Locked) { const circleColor: ColorOption = account.state === AccountState.Ready ? ColorOption.green : ColorOption.red; return ( - + - - - {this.props.walletName} + + + {this.props.walletDisplayName} @@ -91,7 +91,7 @@ export class PaymentMethod extends React.Component { image={} {...colors} > - Please Unlock {this.props.walletName} + Please Unlock {this.props.walletDisplayName} ); case AccountState.None: diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index a4a03bbf4..b544b86ff 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -29,6 +29,7 @@ export interface ZeroExInstantProviderRequiredProps { export interface ZeroExInstantProviderOptionalProps { provider: Provider; + walletDisplayName: string; availableAssetDatas: string[]; defaultAssetBuyAmount: number; defaultSelectedAssetData: string; @@ -66,6 +67,7 @@ export class ZeroExInstantProvider extends React.Component ({ network: state.network, providerState: state.providerState, + walletDisplayName: state.walletDisplayName, }); const mapDispatchToProps = ( @@ -56,7 +58,7 @@ const mergeProps = ( ...ownProps, network: connectedState.network, account: connectedState.providerState.account, - walletName: connectedState.providerState.name, + walletDisplayName: connectedState.walletDisplayName || connectedState.providerState.name, onUnlockWalletClick: () => connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState), onInstallWalletClick: () => { const isMobile = envUtil.isMobileOperatingSystem(); diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 7391e2844..b92fa3a7c 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -39,6 +39,9 @@ const validateInstantRenderConfig = (config: ZeroExInstantConfig, selector: stri if (!_.isUndefined(config.provider)) { assert.isWeb3Provider('provider', config.provider); } + if (!_.isUndefined(config.walletDisplayName)) { + assert.isString('walletDisplayName', config.walletDisplayName); + } if (!_.isUndefined(config.shouldDisablePushToHistory)) { assert.isBoolean('shouldDisablePushToHistory', config.shouldDisablePushToHistory); } diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index dfc2b89f3..a9a407b7d 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -49,6 +49,7 @@ interface OptionalState { latestBuyQuote: BuyQuote; latestErrorMessage: string; affiliateInfo: AffiliateInfo; + walletDisplayName: string; } export type State = DefaultState & PropsDerivedState & Partial; -- cgit v1.2.3 From 5edc3bfd33f4601f9edc6dc5073c790477f09849 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 3 Dec 2018 10:43:03 -0800 Subject: feat(instant): update DAI token color --- packages/instant/src/data/asset_meta_data_map.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts index b24c9c83d..2ddffae70 100644 --- a/packages/instant/src/data/asset_meta_data_map.ts +++ b/packages/instant/src/data/asset_meta_data_map.ts @@ -195,7 +195,7 @@ export const assetMetaDataMap: ObjectMap = { '0xf47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: '#F2B350', + primaryColor: '#DEA349', symbol: 'dai', name: 'Dai Stablecoin', }, -- cgit v1.2.3 From 239116eec47482807029c14b08f2ac6bb72b47d2 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 3 Dec 2018 14:53:25 -0800 Subject: feat(instant): have to use INSTANT_HEAP_FORCE_DEVELOPMENT to report to heap in development --- packages/instant/src/constants.ts | 1 + packages/instant/src/util/analytics.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 1194cf881..2439c7349 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -19,6 +19,7 @@ export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; +export const HEAP_ENABLED = process.env.HEAP_ENABLED; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e625824ef..760ec8b5c 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; -import { INSTANT_DISCHARGE_TARGET } from '../constants'; +import { HEAP_ENABLED, INSTANT_DISCHARGE_TARGET } from '../constants'; import { AffiliateInfo, Asset, @@ -16,15 +16,17 @@ import { import { EventProperties, heapUtil } from './heap'; -let isDisabled = false; +let isDisabledViaConfig = false; export const disableAnalytics = (shouldDisableAnalytics: boolean) => { - isDisabled = shouldDisableAnalytics; + isDisabledViaConfig = shouldDisableAnalytics; }; export const evaluateIfEnabled = (fnCall: () => void) => { - if (isDisabled) { + if (isDisabledViaConfig) { return; } - fnCall(); + if (HEAP_ENABLED) { + fnCall(); + } }; enum EventNames { -- cgit v1.2.3 From 7a03df946dc86ad2b9cc86947cf61bc74dcfbf3c Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 3 Dec 2018 16:01:37 -0800 Subject: feat(instant): Add eth balance, eth address, token symbol and decimals to event properties --- packages/instant/src/redux/analytics_middleware.ts | 18 ++++++++++++++---- packages/instant/src/util/analytics.ts | 4 ++++ 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 47876ca2d..9a98649f6 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -1,10 +1,11 @@ +import { AssetProxyId } from '@0x/types'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import { Middleware } from 'redux'; import { ETH_DECIMALS } from '../constants'; import { AccountState, StandardSlidingPanelContent } from '../types'; -import { analytics } from '../util/analytics'; +import { analytics, AnalyticsEventOptions } from '../util/analytics'; import { Action, ActionTypes } from './actions'; @@ -29,9 +30,11 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction if (didJustTurnReady) { analytics.trackAccountReady(ethAddress); analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); + analytics.addEventProperties({ ethAddress }); } else if (didJustUpdateAddress) { analytics.trackAccountAddressChanged(ethAddress); analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); + analytics.addEventProperties({ ethAddress }); } } break; @@ -51,7 +54,8 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction curAccount.ethBalanceInWei, ETH_DECIMALS, ).toString(); - analytics.addUserProperties({ ethBalanceInUnitAmount }); + analytics.addUserProperties({ ethBalanceInUnitAmount}); + analytics.addEventProperties({ ethBalanceInUnitAmount }); } break; case ActionTypes.UPDATE_SELECTED_ASSET: @@ -63,10 +67,16 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction assetName, assetData, }); - analytics.addEventProperties({ + + const selectedAssetEventProperties: AnalyticsEventOptions = { selectedAssetName: assetName, selectedAssetData: assetData, - }); + }; + if (selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20) { + selectedAssetEventProperties.selectedAssetDecimals = selectedAsset.metaData.decimals; + selectedAssetEventProperties.selectedAssetSymbol = selectedAsset.metaData.symbol; + } + analytics.addEventProperties(selectedAssetEventProperties); } break; case ActionTypes.SET_AVAILABLE_ASSETS: diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e625824ef..b632e8f1a 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -100,6 +100,8 @@ export interface AnalyticsUserOptions { export interface AnalyticsEventOptions { embeddedHost?: string; embeddedUrl?: string; + ethBalanceInUnitAmount?: string; + ethAddress?: string; networkId?: number; providerName?: string; gitSha?: string; @@ -110,7 +112,9 @@ export interface AnalyticsEventOptions { affiliateFeePercent?: number; numberAvailableAssets?: number; selectedAssetName?: string; + selectedAssetSymbol?: string; selectedAssetData?: string; + selectedAssetDecimals?: number; } export enum TokenSelectorClosedVia { ClickedX = 'Clicked X', -- cgit v1.2.3 From e592b27f771839fecd718c21fc1045c695a14f85 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 3 Dec 2018 16:36:27 -0800 Subject: fix(instant): render token selector when only one asset is available --- packages/instant/src/components/erc20_asset_amount_input.tsx | 8 ++++---- packages/instant/src/redux/async_data.ts | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index ff900842a..4da82eb73 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -113,7 +113,7 @@ export class ERC20AssetAmountInput extends React.Component { - if (!this._areMultipleAssetsAvailable()) { + if (!this._areAnyAssetsAvailable()) { return null; } return ( @@ -134,14 +134,14 @@ export class ERC20AssetAmountInput extends React.Component { + private readonly _areAnyAssetsAvailable = (): boolean => { const { numberOfAssetsAvailable } = this.props; - return !_.isUndefined(numberOfAssetsAvailable) && numberOfAssetsAvailable > 1; + return !_.isUndefined(numberOfAssetsAvailable) && numberOfAssetsAvailable > 0; }; private readonly _handleSelectAssetClick = (): void => { if (this.props.onSelectAssetClick) { diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 18f671cd7..c67b222d1 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -32,7 +32,8 @@ export const asyncData = { const assetBuyer = providerState.assetBuyer; try { const assetDatas = await assetBuyer.getAvailableAssetDatasAsync(); - const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network); + const deduplicatedAssetDatas = _.uniq(assetDatas); + const assets = assetUtils.createAssetsFromAssetDatas(deduplicatedAssetDatas, assetMetaDataMap, network); dispatch(actions.setAvailableAssets(assets)); } catch (e) { const errorMessage = 'Could not find any assets'; -- cgit v1.2.3 From 340493a0b14b0c70524407b4c66f61d115845c33 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 4 Dec 2018 13:36:47 -0800 Subject: polish: reduce vertical padding in instant --- packages/instant/src/components/buy_order_progress.tsx | 2 +- packages/instant/src/components/instant_heading.tsx | 2 +- packages/instant/src/components/order_details.tsx | 2 +- packages/instant/src/components/payment_method.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx index 6568de91b..a19f5a4d0 100644 --- a/packages/instant/src/components/buy_order_progress.tsx +++ b/packages/instant/src/components/buy_order_progress.tsx @@ -21,7 +21,7 @@ export const BuyOrderProgress: React.StatelessComponent = const hasEnded = buyOrderState.processState !== OrderProcessState.Processing; const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix; return ( - + diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 808c6dc7f..117f9dd5f 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -32,7 +32,7 @@ export class InstantHeading extends React.Component { public render(): React.ReactNode { const iconOrAmounts = this._renderIcon() || this._renderAmountsSection(); return ( - + { ? assetEthBaseUnitAmount.div(selectedAssetUnitAmount).ceil() : undefined; return ( - + { public render(): React.ReactNode { return ( - + Date: Tue, 4 Dec 2018 14:11:28 -0800 Subject: fix: instant linting issues --- packages/instant/src/components/zero_ex_instant_provider.tsx | 4 ---- 1 file changed, 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index bdc531617..8b75cdfc4 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -1,6 +1,4 @@ -import { ObjectMap } from '@0x/types'; import { BigNumber } from '@0x/utils'; -import { Provider } from 'ethereum-types'; import * as _ from 'lodash'; import * as React from 'react'; import { Provider as ReduxProvider } from 'react-redux'; @@ -13,8 +11,6 @@ import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; import { AccountState, - AffiliateInfo, - AssetMetaData, Network, QuoteFetchOrigin, ZeroExInstantBaseConfig, -- cgit v1.2.3 From 14ad091e83c12ff9dca49a6948cbeeac668730f4 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 4 Dec 2018 15:20:26 -0800 Subject: fix(instant): lighten the overlay color to 0.7 opacity from 0.9 --- packages/instant/src/components/ui/overlay.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx index 7d311dc2f..0b5eaf299 100644 --- a/packages/instant/src/components/ui/overlay.tsx +++ b/packages/instant/src/components/ui/overlay.tsx @@ -33,7 +33,7 @@ export const Overlay = Overlay.defaultProps = { zIndex: zIndex.overlayDefault, - backgroundColor: generateOverlayBlack(0.9), + backgroundColor: generateOverlayBlack(0.7), }; Overlay.displayName = 'Overlay'; -- cgit v1.2.3 From 8b659dbd77294f3d44f4c1fe75a62d6fec3fea15 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 4 Dec 2018 15:20:55 -0800 Subject: feat(instant): give a stable class name to the close button on the overlay --- .../src/components/zero_ex_instant_overlay.tsx | 20 +++++++++++--------- packages/instant/src/constants.ts | 1 + 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index b3fb57dd6..f823d050d 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { ZeroExInstantContainer } from '../components/zero_ex_instant_container'; -import { MAIN_CONTAINER_DIV_CLASS, OVERLAY_DIV_CLASS } from '../constants'; +import { MAIN_CONTAINER_DIV_CLASS, OVERLAY_CLOSE_BUTTON_DIV_CLASS, OVERLAY_DIV_CLASS } from '../constants'; import { ColorOption } from '../style/theme'; import { Container } from './ui/container'; @@ -22,14 +22,16 @@ export const ZeroExInstantOverlay: React.StatelessComponent - + + + Date: Tue, 4 Dec 2018 15:44:48 -0800 Subject: fix(instant): remove extra container around the button --- .../src/components/zero_ex_instant_overlay.tsx | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index f823d050d..96e560691 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -21,17 +21,21 @@ export const ZeroExInstantOverlay: React.StatelessComponent - - - - + + Date: Tue, 4 Dec 2018 15:58:36 -0800 Subject: feat(instant): input to trigger error for rollbar testing --- packages/instant/src/components/scaling_amount_input.tsx | 5 +++++ packages/instant/src/constants.ts | 1 + 2 files changed, 6 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 0861bbe05..f95020461 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import { Maybe } from '../types'; +import { MAGIC_TRIGGER_ERROR_INPUT } from '../constants'; import { ColorOption } from '../style/theme'; import { maybeBigNumberUtil } from '../util/maybe_big_number'; import { util } from '../util/util'; @@ -71,6 +72,10 @@ export class ScalingAmountInput extends React.Component): void => { + if (event.target.value === MAGIC_TRIGGER_ERROR_INPUT) { + throw new Error('Triggered error'); + } + const sanitizedValue = event.target.value.replace(/[^0-9.]/g, ''); // only allow numbers and "." this.setState({ stringValue: sanitizedValue, diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 2439c7349..bf434e33e 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -17,6 +17,7 @@ export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5; export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; +export const MAGIC_TRIGGER_ERROR_INPUT = '0`'; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; export const HEAP_ENABLED = process.env.HEAP_ENABLED; -- cgit v1.2.3 From a138ee7e836a2ddb7a2ae317fe56dddaca5703ff Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 4 Dec 2018 16:10:56 -0800 Subject: Add GIT_SHA and NPM_VERSION constants, report git and npm version in error --- packages/instant/src/components/scaling_amount_input.tsx | 4 ++-- packages/instant/src/constants.ts | 5 ++++- packages/instant/src/util/analytics.ts | 6 +++--- packages/instant/src/util/error_reporter.ts | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index f95020461..86aca5a65 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { Maybe } from '../types'; -import { MAGIC_TRIGGER_ERROR_INPUT } from '../constants'; +import { GIT_SHA, MAGIC_TRIGGER_ERROR_INPUT, MAGIC_TRIGGER_ERROR_MESSAGE, NPM_PACKAGE_VERSION } from '../constants'; import { ColorOption } from '../style/theme'; import { maybeBigNumberUtil } from '../util/maybe_big_number'; import { util } from '../util/util'; @@ -73,7 +73,7 @@ export class ScalingAmountInput extends React.Component): void => { if (event.target.value === MAGIC_TRIGGER_ERROR_INPUT) { - throw new Error('Triggered error'); + throw new Error(`${MAGIC_TRIGGER_ERROR_MESSAGE} git: ${GIT_SHA}, npm: ${NPM_PACKAGE_VERSION}`); } const sanitizedValue = event.target.value.replace(/[^0-9.]/g, ''); // only allow numbers and "." diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index bf434e33e..295208b2d 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -13,11 +13,14 @@ export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction fa export const GWEI_IN_WEI = new BigNumber(1000000000); export const ONE_SECOND_MS = 1000; export const ONE_MINUTE_MS = ONE_SECOND_MS * 60; +export const GIT_SHA = process.env.GIT_SHA; +export const NPM_PACKAGE_VERSION = process.env.NPM_PACKAGE_VERSION; export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5; export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; -export const MAGIC_TRIGGER_ERROR_INPUT = '0`'; +export const MAGIC_TRIGGER_ERROR_INPUT = '0€'; +export const MAGIC_TRIGGER_ERROR_MESSAGE = 'Triggered error'; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; export const HEAP_ENABLED = process.env.HEAP_ENABLED; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 760ec8b5c..b7cbfa82a 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; -import { HEAP_ENABLED, INSTANT_DISCHARGE_TARGET } from '../constants'; +import { GIT_SHA, HEAP_ENABLED, INSTANT_DISCHARGE_TARGET, NPM_PACKAGE_VERSION } from '../constants'; import { AffiliateInfo, Asset, @@ -145,8 +145,8 @@ export const analytics = { embeddedUrl: window.location.href, networkId: network, providerName: providerState.name, - gitSha: process.env.GIT_SHA, - npmVersion: process.env.NPM_PACKAGE_VERSION, + gitSha: GIT_SHA, + npmVersion: NPM_PACKAGE_VERSION, orderSource: orderSourceName, affiliateAddress, affiliateFeePercent, diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts index 3ec7b6daa..b1824eaf9 100644 --- a/packages/instant/src/util/error_reporter.ts +++ b/packages/instant/src/util/error_reporter.ts @@ -1,7 +1,7 @@ import { logUtils } from '@0x/utils'; import * as _ from 'lodash'; -import { HOST_DOMAINS, INSTANT_DISCHARGE_TARGET, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants'; +import { GIT_SHA, HOST_DOMAINS, INSTANT_DISCHARGE_TARGET, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants'; // Import version of Rollbar designed for embedded components // See https://docs.rollbar.com/docs/using-rollbarjs-inside-an-embedded-component @@ -24,7 +24,7 @@ export const setupRollbar = (): any => { client: { javascript: { source_map_enabled: true, - code_version: process.env.GIT_SHA, + code_version: GIT_SHA, guess_uncaught_frames: true, }, }, -- cgit v1.2.3 From 04226106a293f5e716bb3e268e89c7b231da96aa Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 4 Dec 2018 16:33:49 -0800 Subject: ethBalanceInUnitAmount -> lastEthBalanceInUnitAmount --- packages/instant/src/redux/analytics_middleware.ts | 2 +- packages/instant/src/util/analytics.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 9a98649f6..3f7a51707 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -54,7 +54,7 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction curAccount.ethBalanceInWei, ETH_DECIMALS, ).toString(); - analytics.addUserProperties({ ethBalanceInUnitAmount}); + analytics.addUserProperties({ lastEthBalanceInUnitAmount: ethBalanceInUnitAmount }); analytics.addEventProperties({ ethBalanceInUnitAmount }); } break; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index b632e8f1a..4bc4e7c6d 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -95,7 +95,7 @@ const buyQuoteEventProperties = (buyQuote: BuyQuote) => { export interface AnalyticsUserOptions { lastKnownEthAddress?: string; - ethBalanceInUnitAmount?: string; + lastEthBalanceInUnitAmount?: string; } export interface AnalyticsEventOptions { embeddedHost?: string; -- cgit v1.2.3 From f327d7b4d955e954c0f46bc77b7e3b34eb440dbb Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 4 Dec 2018 16:41:47 -0800 Subject: fix(instant): center powered by 0x svg --- packages/instant/src/components/zero_ex_instant_container.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 8a809ee31..0337c7714 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -70,7 +70,7 @@ export class ZeroExInstantContainer extends React.Component -- cgit v1.2.3 From d579ba1eda0fd3c0ca3d00d3d7874d8a9960777e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 4 Dec 2018 16:45:09 -0800 Subject: Please unlock -> Click to connect --- packages/instant/src/components/payment_method.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index 603788748..b10cd8d75 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -91,7 +91,7 @@ export class PaymentMethod extends React.Component { image={} {...colors} > - Please Unlock {this.props.walletDisplayName} + Click to connect {this.props.walletDisplayName} ); case AccountState.None: -- cgit v1.2.3 From 0af1bf11c86361010fa741541244a9e76674bccf Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 4 Dec 2018 17:11:58 -0800 Subject: Use git sha and npm version from constants --- packages/instant/src/index.umd.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index b92fa3a7c..d172f4145 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -2,7 +2,13 @@ import * as _ from 'lodash'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID } from './constants'; +import { + DEFAULT_ZERO_EX_CONTAINER_SELECTOR, + GIT_SHA as GIT_SHA_FROM_CONSTANT, + INJECTED_DIV_CLASS, + INJECTED_DIV_ID, + NPM_PACKAGE_VERSION, +} from './constants'; import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { analytics } from './util/analytics'; import { assert } from './util/assert'; @@ -117,5 +123,5 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z }; // Write version info to the exported object for debugging -export const GIT_SHA = process.env.GIT_SHA; -export const NPM_VERSION = process.env.NPM_PACKAGE_VERSION; +export const GIT_SHA = GIT_SHA_FROM_CONSTANT; +export const NPM_VERSION = NPM_PACKAGE_VERSION; -- cgit v1.2.3 From 40ac4509caf8749671b27f046941ac30e77aa521 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 4 Dec 2018 17:24:34 -0800 Subject: Wallet prompt tweaks per Chris's comment --- packages/instant/src/components/payment_method.tsx | 8 ++++++-- packages/instant/src/components/wallet_prompt.tsx | 4 ++-- packages/instant/src/style/theme.ts | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index b10cd8d75..7c93f1d1c 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -88,10 +88,14 @@ export class PaymentMethod extends React.Component { return ( } + image={ + + + + } {...colors} > - Click to connect {this.props.walletDisplayName} + Click to Connect {this.props.walletDisplayName} ); case AccountState.None: diff --git a/packages/instant/src/components/wallet_prompt.tsx b/packages/instant/src/components/wallet_prompt.tsx index a0b3ae457..c07cfe7b5 100644 --- a/packages/instant/src/components/wallet_prompt.tsx +++ b/packages/instant/src/components/wallet_prompt.tsx @@ -21,7 +21,7 @@ export const WalletPrompt: React.StatelessComponent = ({ primaryColor, }) => ( = ({ {image} - + {children} diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index 71e4b7052..fd3f03c3f 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -38,8 +38,8 @@ export const theme: Theme = { lightestGrey: '#EEEEEE', darkGrey: '#333333', white: 'white', - lightOrange: '#F9F2ED', - darkOrange: '#F2994C', + lightOrange: '#FFF8F2', + darkOrange: '#F7A24F', green: '#3CB34F', red: '#D00000', darkBlue: '#135df6', -- cgit v1.2.3 From 9eff85741617d9d64c674e41a344e42325153292 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 5 Dec 2018 09:45:34 -0800 Subject: Only include localhost in host domains if in development mode --- packages/instant/src/constants.ts | 7 +++---- packages/instant/src/util/analytics.ts | 4 ++-- packages/instant/src/util/error_reporter.ts | 24 +++++++++++++++++++++--- 3 files changed, 26 insertions(+), 9 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 506348092..f83eb4ac7 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -15,6 +15,7 @@ export const GWEI_IN_WEI = new BigNumber(1000000000); export const ONE_SECOND_MS = 1000; export const ONE_MINUTE_MS = ONE_SECOND_MS * 60; export const GIT_SHA = process.env.GIT_SHA; +export const NODE_ENV = process.env.NODE_ENV; export const NPM_PACKAGE_VERSION = process.env.NPM_PACKAGE_VERSION; export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5; export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; @@ -28,14 +29,12 @@ export const HEAP_ENABLED = process.env.HEAP_ENABLED; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; -export const HOST_DOMAINS = [ +export const HOST_DOMAINS_EXTERNAL = [ '0x-instant-staging.s3-website-us-east-1.amazonaws.com', '0x-instant-dogfood.s3-website-us-east-1.amazonaws.com', - 'localhost', - '127.0.0.1', - '0.0.0.0', 'instant.0xproject.com', ]; +export const HOST_DOMAINS_LOCAL = ['localhost', '127.0.0.1', '0.0.0.0']; export const ROLLBAR_CLIENT_TOKEN = process.env.ROLLBAR_CLIENT_TOKEN; export const ROLLBAR_ENABLED = process.env.ROLLBAR_ENABLED; export const INSTANT_DISCHARGE_TARGET = process.env.INSTANT_DISCHARGE_TARGET as diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 6da37bedb..6da52db16 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; -import { GIT_SHA, HEAP_ENABLED, INSTANT_DISCHARGE_TARGET, NPM_PACKAGE_VERSION } from '../constants'; +import { GIT_SHA, HEAP_ENABLED, INSTANT_DISCHARGE_TARGET, NODE_ENV, NPM_PACKAGE_VERSION } from '../constants'; import { AffiliateInfo, Asset, @@ -156,7 +156,7 @@ export const analytics = { affiliateFeePercent, selectedAssetName: selectedAsset ? selectedAsset.metaData.name : 'none', selectedAssetData: selectedAsset ? selectedAsset.assetData : 'none', - instantEnvironment: INSTANT_DISCHARGE_TARGET || `Local ${process.env.NODE_ENV}`, + instantEnvironment: INSTANT_DISCHARGE_TARGET || `Local ${NODE_ENV}`, }; return eventOptions; }, diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts index b1824eaf9..ec074c440 100644 --- a/packages/instant/src/util/error_reporter.ts +++ b/packages/instant/src/util/error_reporter.ts @@ -1,17 +1,35 @@ import { logUtils } from '@0x/utils'; import * as _ from 'lodash'; -import { GIT_SHA, HOST_DOMAINS, INSTANT_DISCHARGE_TARGET, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants'; +import { + GIT_SHA, + HOST_DOMAINS_EXTERNAL, + HOST_DOMAINS_LOCAL, + INSTANT_DISCHARGE_TARGET, + NODE_ENV, + ROLLBAR_CLIENT_TOKEN, + ROLLBAR_ENABLED, +} from '../constants'; // Import version of Rollbar designed for embedded components // See https://docs.rollbar.com/docs/using-rollbarjs-inside-an-embedded-component // tslint:disable-next-line:no-var-requires const Rollbar = require('rollbar/dist/rollbar.noconflict.umd'); +const getRollbarHostDomains = (): string[] => { + if (NODE_ENV === 'development') { + return HOST_DOMAINS_EXTERNAL.concat(HOST_DOMAINS_LOCAL); + } else { + return HOST_DOMAINS_EXTERNAL; + } +}; + let rollbar: any; // Configures rollbar and sets up error catching export const setupRollbar = (): any => { if (_.isUndefined(rollbar) && ROLLBAR_CLIENT_TOKEN && ROLLBAR_ENABLED) { + const hostDomains = getRollbarHostDomains(); + console.log('hostDomains', hostDomains); rollbar = new Rollbar({ accessToken: ROLLBAR_CLIENT_TOKEN, captureUncaught: true, @@ -20,7 +38,7 @@ export const setupRollbar = (): any => { itemsPerMinute: 10, maxItems: 500, payload: { - environment: INSTANT_DISCHARGE_TARGET || `Local ${process.env.NODE_ENV}`, + environment: INSTANT_DISCHARGE_TARGET || `Local ${NODE_ENV}`, client: { javascript: { source_map_enabled: true, @@ -29,7 +47,7 @@ export const setupRollbar = (): any => { }, }, }, - hostWhiteList: HOST_DOMAINS, + hostWhiteList: hostDomains, uncaughtErrorLevel: 'error', ignoredMessages: [ // Errors from the third-party scripts -- cgit v1.2.3 From 69d4e330cf312af99cf547add9cd2106e492c563 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 5 Dec 2018 10:17:18 -0800 Subject: Takeout console.log --- packages/instant/src/util/error_reporter.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts index ec074c440..8d7481684 100644 --- a/packages/instant/src/util/error_reporter.ts +++ b/packages/instant/src/util/error_reporter.ts @@ -29,7 +29,6 @@ let rollbar: any; export const setupRollbar = (): any => { if (_.isUndefined(rollbar) && ROLLBAR_CLIENT_TOKEN && ROLLBAR_ENABLED) { const hostDomains = getRollbarHostDomains(); - console.log('hostDomains', hostDomains); rollbar = new Rollbar({ accessToken: ROLLBAR_CLIENT_TOKEN, captureUncaught: true, -- cgit v1.2.3 From 3454bbfd65f69f219e210fe87bfad5be6993adde Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 5 Dec 2018 11:39:10 -0800 Subject: fix: input placeholder css specificity increase --- packages/instant/src/components/ui/input.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index 863c970ef..62c70f9e1 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -29,8 +29,8 @@ export const Input = outline: none; border: none; &::placeholder { - color: ${props => props.theme[props.fontColor || 'white']}; - opacity: 0.5; + color: ${props => props.theme[props.fontColor || 'white']} !important; + opacity: 0.5 !important; } } `; -- cgit v1.2.3 From 92d4c1d09e05d82bec010f0241c6772ff03da503 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 5 Dec 2018 11:52:27 -0800 Subject: fix: call toLowerCase in asset creation logic --- packages/instant/src/util/asset.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 08f3642e3..13f84ef74 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -26,7 +26,7 @@ export const assetUtils = { return; } return { - assetData, + assetData: assetData.toLowerCase(), metaData, }; }, @@ -36,7 +36,7 @@ export const assetUtils = { network: Network, ): Asset => { return { - assetData, + assetData: assetData.toLowerCase(), metaData: assetUtils.getMetaDataOrThrow(assetData, assetMetaDataMap, network), }; }, -- cgit v1.2.3 From f2c5a8e2f1e517e89f45b03bd3cdf5bb59c450bf Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 5 Dec 2018 12:16:55 -0800 Subject: feat: lowercase keys in additionalAssetMetaDataMap --- packages/instant/src/components/zero_ex_instant_provider.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index dae9124c6..f06d551c7 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -60,7 +60,8 @@ export class ZeroExInstantProvider extends React.Component key.toLowerCase()), ...defaultState.assetMetaDataMap, }; // construct the final state -- cgit v1.2.3 From ea6547cb75ca8579f49e2afd7fb25bee9db5b2ed Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 5 Dec 2018 13:04:42 -0800 Subject: chore: run prettier --- packages/instant/src/components/zero_ex_instant_provider.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 8b75cdfc4..6d7ed0b87 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -9,12 +9,7 @@ import { asyncData } from '../redux/async_data'; import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; -import { - AccountState, - Network, - QuoteFetchOrigin, - ZeroExInstantBaseConfig, -} from '../types'; +import { AccountState, Network, QuoteFetchOrigin, ZeroExInstantBaseConfig } from '../types'; import { analytics, disableAnalytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; -- cgit v1.2.3 From b0e7b82dd99f5411fc77cd4368faf22506de4b11 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 5 Dec 2018 17:47:25 -0800 Subject: feat(instant): More aggressive error reporting --- packages/instant/src/util/buy_quote_updater.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index 4229f2735..6191c92e3 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -38,14 +38,11 @@ export const buyQuoteUpdater = { } catch (error) { const errorMessage = assetUtils.assetBuyerErrorMessage(asset, error); - if (_.isUndefined(errorMessage)) { - // This is an unknown error, report it to rollbar - errorReporter.report(error); - } + errorReporter.report(error); + analytics.trackQuoteError(error.message ? error.message : 'other', baseUnitValue, fetchOrigin); if (options.dispatchErrors) { dispatch(actions.setQuoteRequestStateFailure()); - analytics.trackQuoteError(error.message ? error.message : 'other', baseUnitValue, fetchOrigin); errorFlasher.flashNewErrorMessage(dispatch, errorMessage || 'Error fetching price, please try again'); } return; -- cgit v1.2.3 From 57dc5b6fc086762d9cfedfc8adbfa55adf77fd73 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 7 Dec 2018 11:14:01 -0800 Subject: feat: log walletDisplayName to Heap --- packages/instant/src/components/zero_ex_instant_provider.tsx | 1 + packages/instant/src/util/analytics.ts | 3 +++ 2 files changed, 4 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 7ae27de23..4012af646 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -119,6 +119,7 @@ export class ZeroExInstantProvider extends React.Component { @@ -149,6 +151,7 @@ export const analytics = { embeddedUrl: window.location.href, networkId: network, providerName: providerState.name, + walletDisplayName, gitSha: GIT_SHA, npmVersion: NPM_PACKAGE_VERSION, orderSource: orderSourceName, -- cgit v1.2.3 From b74b4eb053e9e4210dbf507fed88361741ce1d63 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 7 Dec 2018 11:29:37 -0800 Subject: feat: refactor provider name and displayName logic --- .../src/components/zero_ex_instant_provider.tsx | 2 +- packages/instant/src/types.ts | 1 + packages/instant/src/util/analytics.ts | 5 ++-- packages/instant/src/util/env.ts | 7 +++++ .../instant/src/util/provider_state_factory.ts | 33 ++++++++++++++++++---- 5 files changed, 39 insertions(+), 9 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 4012af646..204115fa9 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -38,6 +38,7 @@ export class ZeroExInstantProvider extends React.Component { @@ -151,7 +150,7 @@ export const analytics = { embeddedUrl: window.location.href, networkId: network, providerName: providerState.name, - walletDisplayName, + providerDisplayName: providerState.displayName, gitSha: GIT_SHA, npmVersion: NPM_PACKAGE_VERSION, orderSource: orderSourceName, diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts index 4a32f9cb1..0fda0cc0e 100644 --- a/packages/instant/src/util/env.ts +++ b/packages/instant/src/util/env.ts @@ -62,4 +62,11 @@ export const envUtil = { } return PROVIDER_TYPE_TO_NAME[providerTypeIfExists]; }, + getProviderDisplayName(provider: Provider): string { + const providerTypeIfExists = envUtil.getProviderType(provider); + if (_.isUndefined(providerTypeIfExists)) { + return 'Wallet'; + } + return PROVIDER_TYPE_TO_NAME[providerTypeIfExists]; + }, }; diff --git a/packages/instant/src/util/provider_state_factory.ts b/packages/instant/src/util/provider_state_factory.ts index 7c788dff2..bd2d6dad5 100644 --- a/packages/instant/src/util/provider_state_factory.ts +++ b/packages/instant/src/util/provider_state_factory.ts @@ -10,27 +10,40 @@ import { assetBuyerFactory } from './asset_buyer_factory'; import { providerFactory } from './provider_factory'; export const providerStateFactory = { - getInitialProviderState: (orderSource: OrderSource, network: Network, provider?: Provider): ProviderState => { + getInitialProviderState: ( + orderSource: OrderSource, + network: Network, + provider?: Provider, + walletDisplayName?: string, + ): ProviderState => { if (!_.isUndefined(provider)) { - return providerStateFactory.getInitialProviderStateFromProvider(orderSource, network, provider); + return providerStateFactory.getInitialProviderStateFromProvider( + orderSource, + network, + provider, + walletDisplayName, + ); } const providerStateFromWindowIfExits = providerStateFactory.getInitialProviderStateFromWindowIfExists( orderSource, network, + walletDisplayName, ); if (providerStateFromWindowIfExits) { return providerStateFromWindowIfExits; } else { - return providerStateFactory.getInitialProviderStateFallback(orderSource, network); + return providerStateFactory.getInitialProviderStateFallback(orderSource, network, walletDisplayName); } }, getInitialProviderStateFromProvider: ( orderSource: OrderSource, network: Network, provider: Provider, + walletDisplayName?: string, ): ProviderState => { const providerState: ProviderState = { name: envUtil.getProviderName(provider), + displayName: walletDisplayName || envUtil.getProviderDisplayName(provider), provider, web3Wrapper: new Web3Wrapper(provider), assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network), @@ -38,11 +51,16 @@ export const providerStateFactory = { }; return providerState; }, - getInitialProviderStateFromWindowIfExists: (orderSource: OrderSource, network: Network): Maybe => { + getInitialProviderStateFromWindowIfExists: ( + orderSource: OrderSource, + network: Network, + walletDisplayName?: string, + ): Maybe => { const injectedProviderIfExists = providerFactory.getInjectedProviderIfExists(); if (!_.isUndefined(injectedProviderIfExists)) { const providerState: ProviderState = { name: envUtil.getProviderName(injectedProviderIfExists), + displayName: walletDisplayName || envUtil.getProviderDisplayName(injectedProviderIfExists), provider: injectedProviderIfExists, web3Wrapper: new Web3Wrapper(injectedProviderIfExists), assetBuyer: assetBuyerFactory.getAssetBuyer(injectedProviderIfExists, orderSource, network), @@ -53,10 +71,15 @@ export const providerStateFactory = { return undefined; } }, - getInitialProviderStateFallback: (orderSource: OrderSource, network: Network): ProviderState => { + getInitialProviderStateFallback: ( + orderSource: OrderSource, + network: Network, + walletDisplayName?: string, + ): ProviderState => { const provider = providerFactory.getFallbackNoSigningProvider(network); const providerState: ProviderState = { name: 'Fallback', + displayName: walletDisplayName || envUtil.getProviderDisplayName(provider), provider, web3Wrapper: new Web3Wrapper(provider), assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network), -- cgit v1.2.3 From 4e33d2b481b56ddb2f12e2ee63f40ab2381de741 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 7 Dec 2018 12:21:06 -0800 Subject: feat: only use display name from provider in ui --- packages/instant/src/containers/connected_account_payment_method.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/containers/connected_account_payment_method.ts b/packages/instant/src/containers/connected_account_payment_method.ts index bb68fdd57..f648f0b54 100644 --- a/packages/instant/src/containers/connected_account_payment_method.ts +++ b/packages/instant/src/containers/connected_account_payment_method.ts @@ -58,7 +58,7 @@ const mergeProps = ( ...ownProps, network: connectedState.network, account: connectedState.providerState.account, - walletDisplayName: connectedState.walletDisplayName || connectedState.providerState.name, + walletDisplayName: connectedState.providerState.displayName, onUnlockWalletClick: () => connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState), onInstallWalletClick: () => { const isMobile = envUtil.isMobileOperatingSystem(); -- cgit v1.2.3 From 9d8ab43f916ba70ee979f80a94317541af547b8b Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 10 Dec 2018 09:00:05 -0800 Subject: Don't throw error if can't find icon for token --- packages/instant/src/components/erc20_token_selector.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index f7d5a4fe4..cb8a8c797 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -7,7 +7,6 @@ import { analytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { SearchInput } from './search_input'; - import { Circle } from './ui/circle'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; @@ -123,10 +122,20 @@ interface TokenSelectorRowIconProps { token: ERC20Asset; } +const getTokenIcon = (symbol: string): React.StatelessComponent | undefined => { + try { + return require(`../assets/icons/${symbol}.svg`) as React.StatelessComponent; + } catch (e) { + // Can't find icon + return undefined; + } +}; + const TokenSelectorRowIcon: React.StatelessComponent = props => { const { token } = props; const iconUrlIfExists = token.metaData.iconUrl; - const TokenIcon = require(`../assets/icons/${token.metaData.symbol}.svg`); + + const TokenIcon = getTokenIcon(token.metaData.symbol); const displaySymbol = assetUtils.bestNameForAsset(token); if (!_.isUndefined(iconUrlIfExists)) { return ; -- cgit v1.2.3 From a0ea0415ddd2fb2b9b23ad249d5c0230314260c4 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 10 Dec 2018 09:16:15 -0800 Subject: fix(instant): Don't update heartbeat if amount is 0 --- packages/instant/src/redux/async_data.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index c67b222d1..932eb93e9 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -97,6 +97,7 @@ export const asyncData = { if ( !_.isUndefined(selectedAssetUnitAmount) && !_.isUndefined(selectedAsset) && + selectedAssetUnitAmount.greaterThan(BIG_NUMBER_ZERO) && buyOrderState.processState === OrderProcessState.None && selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20 ) { -- cgit v1.2.3 From dc21c79f2b182917852649dee8f83ba621f79acf Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 8 Dec 2018 09:48:17 -0800 Subject: fix(instant): hide loaders when no token or buy amount is chosen --- packages/instant/src/components/instant_heading.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 117f9dd5f..816cc5c33 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -61,12 +61,19 @@ export class InstantHeading extends React.Component { } private _renderAmountsSection(): React.ReactNode { - return ( - - {this._renderPlaceholderOrAmount(this._renderEthAmount)} - {this._renderPlaceholderOrAmount(this._renderDollarAmount)} - - ); + if ( + _.isUndefined(this.props.totalEthBaseUnitAmount) && + this.props.quoteRequestState !== AsyncProcessState.Pending + ) { + return null; + } else { + return ( + + {this._renderPlaceholderOrAmount(this._renderEthAmount)} + {this._renderPlaceholderOrAmount(this._renderDollarAmount)} + + ); + } } private _renderIcon(): React.ReactNode { -- cgit v1.2.3 From 6e54514013702fa8ca9a6b69c04f4d2468cd8b66 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 10 Dec 2018 17:30:32 -0800 Subject: feat: change input to number input --- packages/instant/src/components/scaling_input.tsx | 1 + packages/instant/src/components/ui/input.tsx | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 791692257..2c5567dc1 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -135,6 +135,7 @@ export class ScalingInput extends React.Component props.theme[props.fontColor || 'white']} !important; opacity: 0.5 !important; } + &::-webkit-outer-spin-button, &::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } } `; -- cgit v1.2.3 From 5cbe04acab982ead39f7794547de0f045952a1b7 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 7 Dec 2018 11:14:55 -0800 Subject: feat(instant): ETH/USD toggle --- packages/instant/src/components/order_details.tsx | 196 +++++++++++++++++---- .../containers/latest_buy_quote_order_details.ts | 33 ++-- packages/instant/src/redux/actions.ts | 4 +- packages/instant/src/redux/reducer.ts | 8 + packages/instant/src/types.ts | 5 + packages/instant/src/util/buy_quote.ts | 71 ++++++++ 6 files changed, 269 insertions(+), 48 deletions(-) create mode 100644 packages/instant/src/util/buy_quote.ts (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index a8e0e2513..85761a5b9 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -6,63 +6,92 @@ import { oc } from 'ts-optchain'; import { BIG_NUMBER_ZERO } from '../constants'; import { ColorOption } from '../style/theme'; +import { BaseCurrency } from '../types'; +import { buyQuoteUtil } from '../util/buy_quote'; import { format } from '../util/format'; import { AmountPlaceholder } from './amount_placeholder'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; -import { Text } from './ui/text'; +import { Text, TextProps } from './ui/text'; + +interface BaseCurrenySwitchProps { + currencyName: string; + onClick: () => void; + isSelected: boolean; +} +const BaseCurrencySelector: React.StatelessComponent = props => { + const textStyle: TextProps = { onClick: props.onClick, fontSize: '12px' }; + if (props.isSelected) { + textStyle.fontColor = ColorOption.primaryColor; + textStyle.fontWeight = 700; + } + return {props.currencyName}; +}; export interface OrderDetailsProps { buyQuoteInfo?: BuyQuoteInfo; selectedAssetUnitAmount?: BigNumber; ethUsdPrice?: BigNumber; isLoading: boolean; + assetName?: string; + baseCurrency: BaseCurrency; + onBaseCurrencySwitchEth: () => void; + onBaseCurrencySwitchUsd: () => void; } export class OrderDetails extends React.Component { public render(): React.ReactNode { const { buyQuoteInfo, ethUsdPrice, selectedAssetUnitAmount } = this.props; - const buyQuoteAccessor = oc(buyQuoteInfo); - const assetEthBaseUnitAmount = buyQuoteAccessor.assetEthAmount(); - const feeEthBaseUnitAmount = buyQuoteAccessor.feeEthAmount(); - const totalEthBaseUnitAmount = buyQuoteAccessor.totalEthAmount(); - const pricePerTokenEth = - !_.isUndefined(assetEthBaseUnitAmount) && - !_.isUndefined(selectedAssetUnitAmount) && - !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO) - ? assetEthBaseUnitAmount.div(selectedAssetUnitAmount).ceil() - : undefined; + const weiAmounts = buyQuoteUtil.getWeiAmounts(selectedAssetUnitAmount, buyQuoteInfo); + + const displayAmounts = + this.props.baseCurrency === BaseCurrency.USD + ? buyQuoteUtil.displayAmountsUsd(weiAmounts, ethUsdPrice) + : buyQuoteUtil.displayAmountsEth(weiAmounts, ethUsdPrice); + return ( - - Order Details - + + + Order Details + + + + + + / + + + + - - - + @@ -79,6 +108,103 @@ export interface EthAmountRowProps { isLoading: boolean; } +export interface OrderDetailsRowProps { + labelText: string; + isLabelBold?: boolean; + isLoading: boolean; + value?: React.ReactNode; +} +export class OrderDetailsRow extends React.Component { + public render(): React.ReactNode { + const { labelText, value, isLabelBold, isLoading } = this.props; + return ( + + + + {labelText} + + + {value || ( + + + + )} + + + + ); + } +} +export interface TotalCostRowProps { + displayPrimaryTotalCost?: React.ReactNode; + displaySecondaryTotalCost?: React.ReactNode; + isLoading: boolean; +} +export class TotalCostRow extends React.Component { + public render(): React.ReactNode { + let value: React.ReactNode; + if (this.props.displayPrimaryTotalCost) { + const secondaryText = this.props.displaySecondaryTotalCost && ( + + ({this.props.displaySecondaryTotalCost}) + + ); + value = ( + + {secondaryText} + + {this.props.displayPrimaryTotalCost} + + + ); + } + + return ( + + ); + } +} + +export interface TokenAmountRowProps { + assetName?: string; + displayPricePerToken?: React.ReactNode; + displayTotalPrice?: React.ReactNode; + isLoading: boolean; + numTokens?: BigNumber; +} +export class TokenAmountRow extends React.Component { + public static DEFAULT_TEXT: string = 'Token Price'; + public render(): React.ReactNode { + return ( + + ); + } + private _labelText(): string { + if (this.props.isLoading) { + return TokenAmountRow.DEFAULT_TEXT; + } + const { numTokens, displayPricePerToken, assetName } = this.props; + if (numTokens) { + let numTokensWithSymbol = numTokens.toString(); + + if (assetName) { + numTokensWithSymbol += ` ${assetName}`; + } + + if (displayPricePerToken) { + numTokensWithSymbol += ` @ ${displayPricePerToken}`; + } + return numTokensWithSymbol; + } + + return TokenAmountRow.DEFAULT_TEXT; + } +} + export class EthAmountRow extends React.Component { public static defaultProps = { shouldEmphasize: false, diff --git a/packages/instant/src/containers/latest_buy_quote_order_details.ts b/packages/instant/src/containers/latest_buy_quote_order_details.ts index 5dfe535e7..148735c47 100644 --- a/packages/instant/src/containers/latest_buy_quote_order_details.ts +++ b/packages/instant/src/containers/latest_buy_quote_order_details.ts @@ -1,32 +1,41 @@ -import { BuyQuoteInfo } from '@0x/asset-buyer'; -import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; import { oc } from 'ts-optchain'; +import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; -import { OrderDetails } from '../components/order_details'; -import { AsyncProcessState } from '../types'; +import { OrderDetails, OrderDetailsProps } from '../components/order_details'; +import { AsyncProcessState, BaseCurrency, Omit } from '../types'; +import { assetUtils } from '../util/asset'; -export interface LatestBuyQuoteOrderDetailsProps {} - -interface ConnectedState { - buyQuoteInfo?: BuyQuoteInfo; - selectedAssetUnitAmount?: BigNumber; - ethUsdPrice?: BigNumber; - isLoading: boolean; -} +type DispatchProperties = 'onBaseCurrencySwitchEth' | 'onBaseCurrencySwitchUsd'; +interface ConnectedState extends Omit {} const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProps): ConnectedState => ({ // use the worst case quote info buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(), selectedAssetUnitAmount: state.selectedAssetUnitAmount, ethUsdPrice: state.ethUsdPrice, isLoading: state.quoteRequestState === AsyncProcessState.Pending, + assetName: assetUtils.bestNameForAsset(state.selectedAsset), + baseCurrency: state.baseCurrency, }); +interface ConnectedDispatch extends Pick {} +const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ + onBaseCurrencySwitchEth: () => { + dispatch(actions.updateBaseCurrency(BaseCurrency.ETH)); + }, + onBaseCurrencySwitchUsd: () => { + dispatch(actions.updateBaseCurrency(BaseCurrency.USD)); + }, +}); + +export interface LatestBuyQuoteOrderDetailsProps {} export const LatestBuyQuoteOrderDetails: React.ComponentClass = connect( mapStateToProps, + mapDispatchToProps, )(OrderDetails); diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 77e3dec12..9d7a61fc7 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; -import { ActionsUnion, AddressAndEthBalanceInWei, Asset, StandardSlidingPanelContent } from '../types'; +import { ActionsUnion, AddressAndEthBalanceInWei, Asset, BaseCurrency, StandardSlidingPanelContent } from '../types'; export interface PlainAction { type: T; @@ -43,6 +43,7 @@ export enum ActionTypes { RESET_AMOUNT = 'RESET_AMOUNT', OPEN_STANDARD_SLIDING_PANEL = 'OPEN_STANDARD_SLIDING_PANEL', CLOSE_STANDARD_SLIDING_PANEL = 'CLOSE_STANDARD_SLIDING_PANEL', + UPDATE_BASE_CURRENCY = 'UPDATE_BASE_CURRENCY', } export const actions = { @@ -72,4 +73,5 @@ export const actions = { openStandardSlidingPanel: (content: StandardSlidingPanelContent) => createAction(ActionTypes.OPEN_STANDARD_SLIDING_PANEL, content), closeStandardSlidingPanel: () => createAction(ActionTypes.CLOSE_STANDARD_SLIDING_PANEL), + updateBaseCurrency: (baseCurrency: BaseCurrency) => createAction(ActionTypes.UPDATE_BASE_CURRENCY, baseCurrency), }; diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index a9a407b7d..4e734041f 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -14,6 +14,7 @@ import { Asset, AssetMetaData, AsyncProcessState, + BaseCurrency, DisplayStatus, Network, OrderProcessState, @@ -33,6 +34,7 @@ export interface DefaultState { latestErrorDisplayStatus: DisplayStatus; quoteRequestState: AsyncProcessState; standardSlidingPanelSettings: StandardSlidingPanelSettings; + baseCurrency: BaseCurrency; } // State that is required but needs to be derived from the props @@ -64,6 +66,7 @@ export const DEFAULT_STATE: DefaultState = { animationState: 'none', content: StandardSlidingPanelContent.None, }, + baseCurrency: BaseCurrency.ETH, }; export const createReducer = (initialState: State) => { @@ -243,6 +246,11 @@ export const createReducer = (initialState: State) => { animationState: 'slidOut', }, }; + case ActionTypes.UPDATE_BASE_CURRENCY: + return { + ...state, + baseCurrency: action.data, + }; default: return state; } diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 1c7490e63..e7c920f36 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -26,6 +26,11 @@ export enum QuoteFetchOrigin { Heartbeat = 'Heartbeat', } +export enum BaseCurrency { + USD = 'USD', + ETH = 'ETH', +} + export interface SimulatedProgress { startTimeUnix: number; expectedEndTimeUnix: number; diff --git a/packages/instant/src/util/buy_quote.ts b/packages/instant/src/util/buy_quote.ts new file mode 100644 index 000000000..acd4d389c --- /dev/null +++ b/packages/instant/src/util/buy_quote.ts @@ -0,0 +1,71 @@ +import { BuyQuoteInfo } from '@0x/asset-buyer'; +import { BigNumber } from '@0x/utils'; +import * as _ from 'lodash'; +import { oc } from 'ts-optchain'; + +import { format } from '../util/format'; + +import { BIG_NUMBER_ZERO } from '../constants'; + +export interface DisplayAmounts { + pricePerToken: React.ReactNode; + assetTotal: React.ReactNode; + feeTotal: React.ReactNode; + primaryGrandTotal: React.ReactNode; + secondaryGrandTotal?: React.ReactNode; +} + +export interface BuyQuoteWeiAmounts { + assetTotalInWei: BigNumber | undefined; + feeTotalInWei: BigNumber | undefined; + grandTotalInWei: BigNumber | undefined; + pricePerTokenInWei: BigNumber | undefined; +} + +const ethDisplayFormat = (amountInWei?: BigNumber) => { + return format.ethBaseUnitAmount(amountInWei, 4, ''); +}; +const usdDisplayFormat = (amountInWei?: BigNumber, ethUsdPrice?: BigNumber) => { + return format.ethBaseUnitAmountInUsd(amountInWei, ethUsdPrice, 2, ''); +}; + +export const buyQuoteUtil = { + getWeiAmounts: ( + selectedAssetUnitAmount: BigNumber | undefined, + buyQuoteInfo: BuyQuoteInfo | undefined, + ): BuyQuoteWeiAmounts => { + const buyQuoteAccessor = oc(buyQuoteInfo); + const assetTotalInWei = buyQuoteAccessor.assetEthAmount(); + const pricePerTokenInWei = + !_.isUndefined(assetTotalInWei) && + !_.isUndefined(selectedAssetUnitAmount) && + !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO) + ? assetTotalInWei.div(selectedAssetUnitAmount).ceil() + : undefined; + + return { + assetTotalInWei, + feeTotalInWei: buyQuoteAccessor.feeEthAmount(), + grandTotalInWei: buyQuoteAccessor.totalEthAmount(), + pricePerTokenInWei, + }; + }, + displayAmountsEth: (weiAmounts: BuyQuoteWeiAmounts, ethUsdPrice?: BigNumber): DisplayAmounts => { + return { + pricePerToken: ethDisplayFormat(weiAmounts.pricePerTokenInWei), + assetTotal: ethDisplayFormat(weiAmounts.assetTotalInWei), + feeTotal: ethDisplayFormat(weiAmounts.feeTotalInWei), + primaryGrandTotal: ethDisplayFormat(weiAmounts.grandTotalInWei), + secondaryGrandTotal: usdDisplayFormat(weiAmounts.grandTotalInWei, ethUsdPrice), + }; + }, + displayAmountsUsd: (weiAmounts: BuyQuoteWeiAmounts, ethUsdPrice?: BigNumber): DisplayAmounts => { + return { + pricePerToken: usdDisplayFormat(weiAmounts.pricePerTokenInWei, ethUsdPrice), + assetTotal: usdDisplayFormat(weiAmounts.assetTotalInWei, ethUsdPrice), + feeTotal: usdDisplayFormat(weiAmounts.feeTotalInWei, ethUsdPrice), + primaryGrandTotal: usdDisplayFormat(weiAmounts.grandTotalInWei, ethUsdPrice), + secondaryGrandTotal: ethDisplayFormat(weiAmounts.grandTotalInWei), + }; + }, +}; -- cgit v1.2.3 From 286474ca767e955b4f7fca985d3864511fa4dfbb Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 11 Dec 2018 14:43:07 -0800 Subject: Remove unused component --- packages/instant/src/components/order_details.tsx | 49 ----------------------- 1 file changed, 49 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 85761a5b9..2fcde5aa4 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -2,9 +2,7 @@ import { BuyQuoteInfo } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import { oc } from 'ts-optchain'; -import { BIG_NUMBER_ZERO } from '../constants'; import { ColorOption } from '../style/theme'; import { BaseCurrency } from '../types'; import { buyQuoteUtil } from '../util/buy_quote'; @@ -204,50 +202,3 @@ export class TokenAmountRow extends React.Component { return TokenAmountRow.DEFAULT_TEXT; } } - -export class EthAmountRow extends React.Component { - public static defaultProps = { - shouldEmphasize: false, - isEthAmountInBaseUnits: true, - }; - public render(): React.ReactNode { - const { rowLabel, ethAmount, isEthAmountInBaseUnits, shouldEmphasize, isLoading } = this.props; - - const fontWeight = shouldEmphasize ? 700 : 400; - const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseUnitAmount : format.ethUnitAmount; - return ( - - - - {rowLabel} - - - {this._renderUsdSection()} - - {ethFormatter( - ethAmount, - 4, - - - , - )} - - - - - ); - } - private _renderUsdSection(): React.ReactNode { - const usdFormatter = this.props.isEthAmountInBaseUnits - ? format.ethBaseUnitAmountInUsd - : format.ethUnitAmountInUsd; - const shouldHideUsdPriceSection = _.isUndefined(this.props.ethUsdPrice) || _.isUndefined(this.props.ethAmount); - return shouldHideUsdPriceSection ? null : ( - - - ({usdFormatter(this.props.ethAmount, this.props.ethUsdPrice)}) - - - ); - } -} -- cgit v1.2.3 From ee7d6fb3afad313fa699018c727c24db4f2024bd Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 11 Dec 2018 14:55:32 -0800 Subject: Show as 0 when selected --- packages/instant/src/components/order_details.tsx | 18 +++++++++++------- packages/instant/src/constants.ts | 1 + packages/instant/src/util/asset.ts | 3 ++- 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 2fcde5aa4..67090898e 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -3,10 +3,10 @@ import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; +import { DEFAULT_UNKOWN_ASSET_NAME } from '../constants'; import { ColorOption } from '../style/theme'; import { BaseCurrency } from '../types'; import { buyQuoteUtil } from '../util/buy_quote'; -import { format } from '../util/format'; import { AmountPlaceholder } from './amount_placeholder'; @@ -171,7 +171,7 @@ export interface TokenAmountRowProps { numTokens?: BigNumber; } export class TokenAmountRow extends React.Component { - public static DEFAULT_TEXT: string = 'Token Price'; + public static DEFAULT_TEXT: string = 'Token Amount'; public render(): React.ReactNode { return ( { ); } private _labelText(): string { - if (this.props.isLoading) { - return TokenAmountRow.DEFAULT_TEXT; - } - const { numTokens, displayPricePerToken, assetName } = this.props; - if (numTokens) { + const { displayPricePerToken, assetName } = this.props; + + // Display as 0 if we have a selected asset + const numTokens = + assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(this.props.numTokens) + ? 0 + : this.props.numTokens; + + if (!_.isUndefined(numTokens)) { let numTokensWithSymbol = numTokens.toString(); if (assetName) { diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index f83eb4ac7..975dfcbea 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -17,6 +17,7 @@ export const ONE_MINUTE_MS = ONE_SECOND_MS * 60; export const GIT_SHA = process.env.GIT_SHA; export const NODE_ENV = process.env.NODE_ENV; export const NPM_PACKAGE_VERSION = process.env.NPM_PACKAGE_VERSION; +export const DEFAULT_UNKOWN_ASSET_NAME = '???'; export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5; export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 13f84ef74..faaeb7c22 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -2,6 +2,7 @@ import { AssetBuyerError } from '@0x/asset-buyer'; import { AssetProxyId, ObjectMap } from '@0x/types'; import * as _ from 'lodash'; +import { DEFAULT_UNKOWN_ASSET_NAME } from '../constants'; import { assetDataNetworkMapping } from '../data/asset_data_network_mapping'; import { Asset, AssetMetaData, ERC20Asset, Network, ZeroExInstantError } from '../types'; @@ -71,7 +72,7 @@ export const assetUtils = { } return metaData; }, - bestNameForAsset: (asset?: Asset, defaultName: string = '???'): string => { + bestNameForAsset: (asset?: Asset, defaultName: string = DEFAULT_UNKOWN_ASSET_NAME): string => { if (_.isUndefined(asset)) { return defaultName; } -- cgit v1.2.3 From b1a73f5c742b96906e832e532dbdc3e4e9583c6d Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 11 Dec 2018 17:03:07 -0800 Subject: Refactor out custom components --- packages/instant/src/components/order_details.tsx | 137 +++++++++------------- 1 file changed, 55 insertions(+), 82 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 67090898e..9eaf2fb2e 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -28,6 +28,49 @@ const BaseCurrencySelector: React.StatelessComponent = p return {props.currencyName}; }; +const grandTotalDisplayValue = ( + displayPrimaryTotalCost?: React.ReactNode, + displaySecondaryTotalCost?: React.ReactNode, +): React.ReactNode => { + if (!displayPrimaryTotalCost) { + return undefined; + } + const secondaryText = displaySecondaryTotalCost && ( + + ({displaySecondaryTotalCost}) + + ); + return ( + + {secondaryText} + + {displayPrimaryTotalCost} + + + ); +}; + +const tokenAmountLabel = (displayPricePerToken?: React.ReactNode, assetName?: string, numTokens?: BigNumber) => { + // Display as 0 if we have a selected asset + const displayNumTokens = + assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(numTokens) ? new BigNumber(0) : numTokens; + + if (!_.isUndefined(displayNumTokens)) { + let numTokensWithSymbol = displayNumTokens.toString(); + + if (assetName) { + numTokensWithSymbol += ` ${assetName}`; + } + + if (displayPricePerToken) { + numTokensWithSymbol += ` @ ${displayPricePerToken}`; + } + return numTokensWithSymbol; + } + + return 'Token Amount'; +}; + export interface OrderDetailsProps { buyQuoteInfo?: BuyQuoteInfo; selectedAssetUnitAmount?: BigNumber; @@ -79,18 +122,21 @@ export class OrderDetails extends React.Component { - - - + ); @@ -133,76 +179,3 @@ export class OrderDetailsRow extends React.Component { ); } } -export interface TotalCostRowProps { - displayPrimaryTotalCost?: React.ReactNode; - displaySecondaryTotalCost?: React.ReactNode; - isLoading: boolean; -} -export class TotalCostRow extends React.Component { - public render(): React.ReactNode { - let value: React.ReactNode; - if (this.props.displayPrimaryTotalCost) { - const secondaryText = this.props.displaySecondaryTotalCost && ( - - ({this.props.displaySecondaryTotalCost}) - - ); - value = ( - - {secondaryText} - - {this.props.displayPrimaryTotalCost} - - - ); - } - - return ( - - ); - } -} - -export interface TokenAmountRowProps { - assetName?: string; - displayPricePerToken?: React.ReactNode; - displayTotalPrice?: React.ReactNode; - isLoading: boolean; - numTokens?: BigNumber; -} -export class TokenAmountRow extends React.Component { - public static DEFAULT_TEXT: string = 'Token Amount'; - public render(): React.ReactNode { - return ( - - ); - } - private _labelText(): string { - const { displayPricePerToken, assetName } = this.props; - - // Display as 0 if we have a selected asset - const numTokens = - assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(this.props.numTokens) - ? 0 - : this.props.numTokens; - - if (!_.isUndefined(numTokens)) { - let numTokensWithSymbol = numTokens.toString(); - - if (assetName) { - numTokensWithSymbol += ` ${assetName}`; - } - - if (displayPricePerToken) { - numTokensWithSymbol += ` @ ${displayPricePerToken}`; - } - return numTokensWithSymbol; - } - - return TokenAmountRow.DEFAULT_TEXT; - } -} -- cgit v1.2.3 From 5f7ed71937c8319bb5613dc57f005848b1fa336c Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Tue, 11 Dec 2018 17:06:27 -0800 Subject: Delete old interface and rename BaseCurrencyChoice --- packages/instant/src/components/order_details.tsx | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 9eaf2fb2e..8bff0af14 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -14,12 +14,12 @@ import { Container } from './ui/container'; import { Flex } from './ui/flex'; import { Text, TextProps } from './ui/text'; -interface BaseCurrenySwitchProps { +interface BaseCurryChoiceProps { currencyName: string; onClick: () => void; isSelected: boolean; } -const BaseCurrencySelector: React.StatelessComponent = props => { +const BaseCurrencyChoice: React.StatelessComponent = props => { const textStyle: TextProps = { onClick: props.onClick, fontSize: '12px' }; if (props.isSelected) { textStyle.fontColor = ColorOption.primaryColor; @@ -106,7 +106,7 @@ export class OrderDetails extends React.Component { - { / - { } } -export interface EthAmountRowProps { - rowLabel: string; - ethAmount?: BigNumber; - isEthAmountInBaseUnits?: boolean; - ethUsdPrice?: BigNumber; - shouldEmphasize?: boolean; - isLoading: boolean; -} - export interface OrderDetailsRowProps { labelText: string; isLabelBold?: boolean; -- cgit v1.2.3 From 7aacf1f5a457e1166f5188836d30a8c38f3f2c68 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 08:23:40 -0800 Subject: Render OrderDetailsRow directly --- packages/instant/src/components/order_details.tsx | 39 +++++++++++++++++------ packages/instant/src/util/buy_quote.ts | 35 -------------------- 2 files changed, 29 insertions(+), 45 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 8bff0af14..f553351ff 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -7,6 +7,7 @@ import { DEFAULT_UNKOWN_ASSET_NAME } from '../constants'; import { ColorOption } from '../style/theme'; import { BaseCurrency } from '../types'; import { buyQuoteUtil } from '../util/buy_quote'; +import { format } from '../util/format'; import { AmountPlaceholder } from './amount_placeholder'; @@ -71,6 +72,19 @@ const tokenAmountLabel = (displayPricePerToken?: React.ReactNode, assetName?: st return 'Token Amount'; }; +const getDisplayAmount = ( + baseCurrency: BaseCurrency, + weiAmount?: BigNumber, + ethUsdPrice?: BigNumber, +): React.ReactNode => { + switch (baseCurrency) { + case BaseCurrency.USD: + return format.ethBaseUnitAmountInUsd(weiAmount, ethUsdPrice, 2, ''); + case BaseCurrency.ETH: + return format.ethBaseUnitAmount(weiAmount, 4, ''); + } +}; + export interface OrderDetailsProps { buyQuoteInfo?: BuyQuoteInfo; selectedAssetUnitAmount?: BigNumber; @@ -83,13 +97,14 @@ export interface OrderDetailsProps { } export class OrderDetails extends React.Component { public render(): React.ReactNode { - const { buyQuoteInfo, ethUsdPrice, selectedAssetUnitAmount } = this.props; - const weiAmounts = buyQuoteUtil.getWeiAmounts(selectedAssetUnitAmount, buyQuoteInfo); + const { baseCurrency, buyQuoteInfo, ethUsdPrice, selectedAssetUnitAmount } = this.props; - const displayAmounts = - this.props.baseCurrency === BaseCurrency.USD - ? buyQuoteUtil.displayAmountsUsd(weiAmounts, ethUsdPrice) - : buyQuoteUtil.displayAmountsEth(weiAmounts, ethUsdPrice); + const weiAmounts = buyQuoteUtil.getWeiAmounts(selectedAssetUnitAmount, buyQuoteInfo); + const secondaryCurrency = baseCurrency === BaseCurrency.USD ? BaseCurrency.ETH : BaseCurrency.USD; + const grandTotalValue = grandTotalDisplayValue( + getDisplayAmount(baseCurrency, weiAmounts.grandTotalInWei, ethUsdPrice), + getDisplayAmount(secondaryCurrency, weiAmounts.grandTotalInWei, ethUsdPrice), + ); return ( @@ -125,18 +140,22 @@ export class OrderDetails extends React.Component { + - ); diff --git a/packages/instant/src/util/buy_quote.ts b/packages/instant/src/util/buy_quote.ts index acd4d389c..0e880f51c 100644 --- a/packages/instant/src/util/buy_quote.ts +++ b/packages/instant/src/util/buy_quote.ts @@ -3,18 +3,8 @@ import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import { oc } from 'ts-optchain'; -import { format } from '../util/format'; - import { BIG_NUMBER_ZERO } from '../constants'; -export interface DisplayAmounts { - pricePerToken: React.ReactNode; - assetTotal: React.ReactNode; - feeTotal: React.ReactNode; - primaryGrandTotal: React.ReactNode; - secondaryGrandTotal?: React.ReactNode; -} - export interface BuyQuoteWeiAmounts { assetTotalInWei: BigNumber | undefined; feeTotalInWei: BigNumber | undefined; @@ -22,13 +12,6 @@ export interface BuyQuoteWeiAmounts { pricePerTokenInWei: BigNumber | undefined; } -const ethDisplayFormat = (amountInWei?: BigNumber) => { - return format.ethBaseUnitAmount(amountInWei, 4, ''); -}; -const usdDisplayFormat = (amountInWei?: BigNumber, ethUsdPrice?: BigNumber) => { - return format.ethBaseUnitAmountInUsd(amountInWei, ethUsdPrice, 2, ''); -}; - export const buyQuoteUtil = { getWeiAmounts: ( selectedAssetUnitAmount: BigNumber | undefined, @@ -50,22 +33,4 @@ export const buyQuoteUtil = { pricePerTokenInWei, }; }, - displayAmountsEth: (weiAmounts: BuyQuoteWeiAmounts, ethUsdPrice?: BigNumber): DisplayAmounts => { - return { - pricePerToken: ethDisplayFormat(weiAmounts.pricePerTokenInWei), - assetTotal: ethDisplayFormat(weiAmounts.assetTotalInWei), - feeTotal: ethDisplayFormat(weiAmounts.feeTotalInWei), - primaryGrandTotal: ethDisplayFormat(weiAmounts.grandTotalInWei), - secondaryGrandTotal: usdDisplayFormat(weiAmounts.grandTotalInWei, ethUsdPrice), - }; - }, - displayAmountsUsd: (weiAmounts: BuyQuoteWeiAmounts, ethUsdPrice?: BigNumber): DisplayAmounts => { - return { - pricePerToken: usdDisplayFormat(weiAmounts.pricePerTokenInWei, ethUsdPrice), - assetTotal: usdDisplayFormat(weiAmounts.assetTotalInWei, ethUsdPrice), - feeTotal: usdDisplayFormat(weiAmounts.feeTotalInWei, ethUsdPrice), - primaryGrandTotal: usdDisplayFormat(weiAmounts.grandTotalInWei, ethUsdPrice), - secondaryGrandTotal: ethDisplayFormat(weiAmounts.grandTotalInWei), - }; - }, }; -- cgit v1.2.3 From 8923817b2ff6c8d3cffe6914634e75cdf06db4a9 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 08:25:20 -0800 Subject: Move header to helper --- packages/instant/src/components/order_details.tsx | 62 ++++++++++++----------- 1 file changed, 33 insertions(+), 29 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index f553351ff..5d306f43e 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -108,35 +108,7 @@ export class OrderDetails extends React.Component { return ( - - - - Order Details - - - - - - / - - - - - + {this._renderHeader()} { ); } + + private _renderHeader(): React.ReactNode { + return ( + + + Order Details + + + + + + / + + + + + ); + } } export interface OrderDetailsRowProps { -- cgit v1.2.3 From 3b9e8e669f179aeda7a3aa3f91c78477fa7f08cd Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 09:14:25 -0800 Subject: Refactor OrderDetails to use private instance methods --- packages/instant/src/components/order_details.tsx | 206 ++++++++++++---------- 1 file changed, 115 insertions(+), 91 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 5d306f43e..7e33e06ac 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -2,11 +2,11 @@ import { BuyQuoteInfo } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; +import { oc } from 'ts-optchain'; -import { DEFAULT_UNKOWN_ASSET_NAME } from '../constants'; +import { BIG_NUMBER_ZERO, DEFAULT_UNKOWN_ASSET_NAME } from '../constants'; import { ColorOption } from '../style/theme'; import { BaseCurrency } from '../types'; -import { buyQuoteUtil } from '../util/buy_quote'; import { format } from '../util/format'; import { AmountPlaceholder } from './amount_placeholder'; @@ -29,62 +29,6 @@ const BaseCurrencyChoice: React.StatelessComponent = props return {props.currencyName}; }; -const grandTotalDisplayValue = ( - displayPrimaryTotalCost?: React.ReactNode, - displaySecondaryTotalCost?: React.ReactNode, -): React.ReactNode => { - if (!displayPrimaryTotalCost) { - return undefined; - } - const secondaryText = displaySecondaryTotalCost && ( - - ({displaySecondaryTotalCost}) - - ); - return ( - - {secondaryText} - - {displayPrimaryTotalCost} - - - ); -}; - -const tokenAmountLabel = (displayPricePerToken?: React.ReactNode, assetName?: string, numTokens?: BigNumber) => { - // Display as 0 if we have a selected asset - const displayNumTokens = - assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(numTokens) ? new BigNumber(0) : numTokens; - - if (!_.isUndefined(displayNumTokens)) { - let numTokensWithSymbol = displayNumTokens.toString(); - - if (assetName) { - numTokensWithSymbol += ` ${assetName}`; - } - - if (displayPricePerToken) { - numTokensWithSymbol += ` @ ${displayPricePerToken}`; - } - return numTokensWithSymbol; - } - - return 'Token Amount'; -}; - -const getDisplayAmount = ( - baseCurrency: BaseCurrency, - weiAmount?: BigNumber, - ethUsdPrice?: BigNumber, -): React.ReactNode => { - switch (baseCurrency) { - case BaseCurrency.USD: - return format.ethBaseUnitAmountInUsd(weiAmount, ethUsdPrice, 2, ''); - case BaseCurrency.ETH: - return format.ethBaseUnitAmount(weiAmount, 4, ''); - } -}; - export interface OrderDetailsProps { buyQuoteInfo?: BuyQuoteInfo; selectedAssetUnitAmount?: BigNumber; @@ -97,42 +41,107 @@ export interface OrderDetailsProps { } export class OrderDetails extends React.Component { public render(): React.ReactNode { - const { baseCurrency, buyQuoteInfo, ethUsdPrice, selectedAssetUnitAmount } = this.props; - - const weiAmounts = buyQuoteUtil.getWeiAmounts(selectedAssetUnitAmount, buyQuoteInfo); - const secondaryCurrency = baseCurrency === BaseCurrency.USD ? BaseCurrency.ETH : BaseCurrency.USD; - const grandTotalValue = grandTotalDisplayValue( - getDisplayAmount(baseCurrency, weiAmounts.grandTotalInWei, ethUsdPrice), - getDisplayAmount(secondaryCurrency, weiAmounts.grandTotalInWei, ethUsdPrice), - ); + const { baseCurrency, buyQuoteInfo } = this.props; return ( {this._renderHeader()} + ); } + private _totalCostSecondaryValue(): React.ReactNode { + const secondaryCurrency = this.props.baseCurrency === BaseCurrency.USD ? BaseCurrency.ETH : BaseCurrency.USD; + + const canDisplayCurrency = + secondaryCurrency === BaseCurrency.ETH || + (secondaryCurrency === BaseCurrency.USD && + this.props.ethUsdPrice && + this.props.ethUsdPrice.greaterThan(BIG_NUMBER_ZERO)); + + if (this.props.buyQuoteInfo && canDisplayCurrency) { + return this._displayAmount(secondaryCurrency, this.props.buyQuoteInfo.totalEthAmount); + } else { + return undefined; + } + } + + private _displayAmountOrPlaceholder(weiAmount?: BigNumber): React.ReactNode { + const { baseCurrency, ethUsdPrice, isLoading } = this.props; + + if (_.isUndefined(weiAmount)) { + return ( + + + + ); + } + + return this._displayAmount(baseCurrency, weiAmount); + } + + private _displayAmount(currency: BaseCurrency, weiAmount: BigNumber): React.ReactNode { + switch (currency) { + case BaseCurrency.USD: + return format.ethBaseUnitAmountInUsd(weiAmount, this.props.ethUsdPrice, 2, ''); + case BaseCurrency.ETH: + return format.ethBaseUnitAmount(weiAmount, 4, ''); + } + } + + private _assetLabelText(): string { + const { assetName, baseCurrency, ethUsdPrice } = this.props; + const numTokens = this.props.selectedAssetUnitAmount; + + // Display as 0 if we have a selected asset + const displayNumTokens = + assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(numTokens) + ? new BigNumber(0) + : numTokens; + + if (!_.isUndefined(displayNumTokens)) { + let numTokensWithSymbol = displayNumTokens.toString(); + + if (assetName) { + numTokensWithSymbol += ` ${assetName}`; + } + + const pricePerTokenWei = this._pricePerTokenWei(); + if (pricePerTokenWei) { + numTokensWithSymbol += ` @ ${this._displayAmount(baseCurrency, pricePerTokenWei)}`; + } + return numTokensWithSymbol; + } + + return 'Token Amount'; + } + + private _pricePerTokenWei(): BigNumber | undefined { + const buyQuoteAccessor = oc(this.props.buyQuoteInfo); + const assetTotalInWei = buyQuoteAccessor.assetEthAmount(); + const selectedAssetUnitAmount = this.props.selectedAssetUnitAmount; + return !_.isUndefined(assetTotalInWei) && + !_.isUndefined(selectedAssetUnitAmount) && + !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO) + ? assetTotalInWei.div(selectedAssetUnitAmount).ceil() + : undefined; + } + private _renderHeader(): React.ReactNode { return ( @@ -169,27 +178,42 @@ export class OrderDetails extends React.Component { export interface OrderDetailsRowProps { labelText: string; isLabelBold?: boolean; - isLoading: boolean; - value?: React.ReactNode; + isPrimaryValueBold?: boolean; + primaryValue: React.ReactNode; + secondaryValue?: React.ReactNode; } export class OrderDetailsRow extends React.Component { public render(): React.ReactNode { - const { labelText, value, isLabelBold, isLoading } = this.props; return ( - - {labelText} - - - {value || ( - - - - )} - + {this._renderLabel()} + {this._renderValues()} ); } + + private _renderLabel(): React.ReactNode { + return ( + + {this.props.labelText} + + ); + } + + private _renderValues(): React.ReactNode { + const secondaryValueNode: React.ReactNode = this.props.secondaryValue && ( + + ({this.props.secondaryValue}) + + ); + + return ( + + {secondaryValueNode} + {this.props.primaryValue} + + ); + } } -- cgit v1.2.3 From ad3d20b34267eda1a9b1d397fb15f2bce0eb221f Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 09:15:18 -0800 Subject: Default to USD --- packages/instant/src/redux/reducer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 4e734041f..8c13c9c72 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -66,7 +66,7 @@ export const DEFAULT_STATE: DefaultState = { animationState: 'none', content: StandardSlidingPanelContent.None, }, - baseCurrency: BaseCurrency.ETH, + baseCurrency: BaseCurrency.USD, }; export const createReducer = (initialState: State) => { -- cgit v1.2.3 From aeefdeaef78fad38b84e728cceff2141eb302ab5 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 09:25:48 -0800 Subject: Remove unused util --- packages/instant/src/util/buy_quote.ts | 36 ---------------------------------- 1 file changed, 36 deletions(-) delete mode 100644 packages/instant/src/util/buy_quote.ts (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/buy_quote.ts b/packages/instant/src/util/buy_quote.ts deleted file mode 100644 index 0e880f51c..000000000 --- a/packages/instant/src/util/buy_quote.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { BuyQuoteInfo } from '@0x/asset-buyer'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import { oc } from 'ts-optchain'; - -import { BIG_NUMBER_ZERO } from '../constants'; - -export interface BuyQuoteWeiAmounts { - assetTotalInWei: BigNumber | undefined; - feeTotalInWei: BigNumber | undefined; - grandTotalInWei: BigNumber | undefined; - pricePerTokenInWei: BigNumber | undefined; -} - -export const buyQuoteUtil = { - getWeiAmounts: ( - selectedAssetUnitAmount: BigNumber | undefined, - buyQuoteInfo: BuyQuoteInfo | undefined, - ): BuyQuoteWeiAmounts => { - const buyQuoteAccessor = oc(buyQuoteInfo); - const assetTotalInWei = buyQuoteAccessor.assetEthAmount(); - const pricePerTokenInWei = - !_.isUndefined(assetTotalInWei) && - !_.isUndefined(selectedAssetUnitAmount) && - !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO) - ? assetTotalInWei.div(selectedAssetUnitAmount).ceil() - : undefined; - - return { - assetTotalInWei, - feeTotalInWei: buyQuoteAccessor.feeEthAmount(), - grandTotalInWei: buyQuoteAccessor.totalEthAmount(), - pricePerTokenInWei, - }; - }, -}; -- cgit v1.2.3 From 8a5609718aa6e31e30915300e38e47d30d528896 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 09:26:00 -0800 Subject: Refactor BaseCurrencyChoice to be done in helper function --- packages/instant/src/components/order_details.tsx | 46 ++++++++++------------- 1 file changed, 19 insertions(+), 27 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 7e33e06ac..298bd86c9 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -15,20 +15,6 @@ import { Container } from './ui/container'; import { Flex } from './ui/flex'; import { Text, TextProps } from './ui/text'; -interface BaseCurryChoiceProps { - currencyName: string; - onClick: () => void; - isSelected: boolean; -} -const BaseCurrencyChoice: React.StatelessComponent = props => { - const textStyle: TextProps = { onClick: props.onClick, fontSize: '12px' }; - if (props.isSelected) { - textStyle.fontColor = ColorOption.primaryColor; - textStyle.fontWeight = 700; - } - return {props.currencyName}; -}; - export interface OrderDetailsProps { buyQuoteInfo?: BuyQuoteInfo; selectedAssetUnitAmount?: BigNumber; @@ -41,7 +27,7 @@ export interface OrderDetailsProps { } export class OrderDetails extends React.Component { public render(): React.ReactNode { - const { baseCurrency, buyQuoteInfo } = this.props; + const { buyQuoteInfo } = this.props; return ( @@ -82,7 +68,7 @@ export class OrderDetails extends React.Component { } private _displayAmountOrPlaceholder(weiAmount?: BigNumber): React.ReactNode { - const { baseCurrency, ethUsdPrice, isLoading } = this.props; + const { baseCurrency, isLoading } = this.props; if (_.isUndefined(weiAmount)) { return ( @@ -105,7 +91,7 @@ export class OrderDetails extends React.Component { } private _assetLabelText(): string { - const { assetName, baseCurrency, ethUsdPrice } = this.props; + const { assetName, baseCurrency } = this.props; const numTokens = this.props.selectedAssetUnitAmount; // Display as 0 if we have a selected asset @@ -142,6 +128,20 @@ export class OrderDetails extends React.Component { : undefined; } + private _baseCurrencyChoice(choice: BaseCurrency): React.ReactNode { + const onClick = + choice === BaseCurrency.ETH ? this.props.onBaseCurrencySwitchEth : this.props.onBaseCurrencySwitchUsd; + const isSelected = this.props.baseCurrency === choice; + + const textStyle: TextProps = { onClick, fontSize: '12px ' }; + if (isSelected) { + textStyle.fontColor = ColorOption.primaryColor; + textStyle.fontWeight = 700; + } + + return {choice}; + } + private _renderHeader(): React.ReactNode { return ( @@ -156,19 +156,11 @@ export class OrderDetails extends React.Component { - + {this._baseCurrencyChoice(BaseCurrency.ETH)} / - + {this._baseCurrencyChoice(BaseCurrency.USD)} ); -- cgit v1.2.3 From 99941972a3965f27b3607a382a476b79722151fc Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 09:29:23 -0800 Subject: Small clean up --- packages/instant/src/components/order_details.tsx | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 298bd86c9..cbe36be64 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -34,7 +34,7 @@ export class OrderDetails extends React.Component { {this._renderHeader()} { } } - private _assetLabelText(): string { + private _assetAmountLabel(): string { const { assetName, baseCurrency } = this.props; const numTokens = this.props.selectedAssetUnitAmount; @@ -99,21 +99,17 @@ export class OrderDetails extends React.Component { assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(numTokens) ? new BigNumber(0) : numTokens; - if (!_.isUndefined(displayNumTokens)) { let numTokensWithSymbol = displayNumTokens.toString(); - if (assetName) { numTokensWithSymbol += ` ${assetName}`; } - const pricePerTokenWei = this._pricePerTokenWei(); if (pricePerTokenWei) { numTokensWithSymbol += ` @ ${this._displayAmount(baseCurrency, pricePerTokenWei)}`; } return numTokensWithSymbol; } - return 'Token Amount'; } @@ -138,7 +134,6 @@ export class OrderDetails extends React.Component { textStyle.fontColor = ColorOption.primaryColor; textStyle.fontWeight = 700; } - return {choice}; } @@ -154,7 +149,6 @@ export class OrderDetails extends React.Component { > Order Details - {this._baseCurrencyChoice(BaseCurrency.ETH)} @@ -179,28 +173,21 @@ export class OrderDetailsRow extends React.Component { return ( - {this._renderLabel()} + + {this.props.labelText} + {this._renderValues()} ); } - private _renderLabel(): React.ReactNode { - return ( - - {this.props.labelText} - - ); - } - private _renderValues(): React.ReactNode { const secondaryValueNode: React.ReactNode = this.props.secondaryValue && ( ({this.props.secondaryValue}) ); - return ( {secondaryValueNode} -- cgit v1.2.3 From aa8dfa88e113ca7a98887ed77dc8eb3ad39e5f41 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 09:37:39 -0800 Subject: Make primary value in total cost bold --- packages/instant/src/components/order_details.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index cbe36be64..537b9ee4e 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -45,6 +45,7 @@ export class OrderDetails extends React.Component { labelText="Total Cost" isLabelBold={true} primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.totalEthAmount)} + isPrimaryValueBold={true} secondaryValue={this._totalCostSecondaryValue()} /> -- cgit v1.2.3 From fb99b5ce9d3639e1584214828216879f99dfa020 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 09:51:15 -0800 Subject: Show error when fetching usd prices --- packages/instant/src/components/order_details.tsx | 36 ++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 537b9ee4e..ea975a5f7 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -27,12 +27,19 @@ export interface OrderDetailsProps { } export class OrderDetails extends React.Component { public render(): React.ReactNode { - const { buyQuoteInfo } = this.props; - + const showUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice(); return ( {this._renderHeader()} + {showUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()} + + ); + } + private _renderRows(): React.ReactNode { + const { buyQuoteInfo } = this.props; + return ( + { isPrimaryValueBold={true} secondaryValue={this._totalCostSecondaryValue()} /> - + ); } + private _renderErrorFetchingUsdPrice(): React.ReactNode { + return ( + + There was an error fetching the USD price. + + Click here + + {' to view ETH prices'} + + ); + } + + private _hadErrorFetchingUsdPrice(): boolean { + return this.props.ethUsdPrice === BIG_NUMBER_ZERO; + } + private _totalCostSecondaryValue(): React.ReactNode { const secondaryCurrency = this.props.baseCurrency === BaseCurrency.USD ? BaseCurrency.ETH : BaseCurrency.USD; @@ -92,7 +119,8 @@ export class OrderDetails extends React.Component { } private _assetAmountLabel(): string { - const { assetName, baseCurrency } = this.props; + const { assetName, baseCurrency, ethUsdPrice } = this.props; + const numTokens = this.props.selectedAssetUnitAmount; // Display as 0 if we have a selected asset -- cgit v1.2.3 From 0690e68a833e0ca75d31614621aa0278009cc10c Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 09:54:06 -0800 Subject: Change base currency to ETH if we can't get USD price --- packages/instant/src/redux/async_data.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index c67b222d1..8ef95add4 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash'; import { Dispatch } from 'redux'; import { BIG_NUMBER_ZERO } from '../constants'; -import { AccountState, ERC20Asset, OrderProcessState, ProviderState, QuoteFetchOrigin } from '../types'; +import { AccountState, BaseCurrency, ERC20Asset, OrderProcessState, ProviderState, QuoteFetchOrigin } from '../types'; import { analytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { buyQuoteUpdater } from '../util/buy_quote_updater'; @@ -24,6 +24,7 @@ export const asyncData = { const errorMessage = 'Error fetching ETH/USD price'; errorFlasher.flashNewErrorMessage(dispatch, errorMessage); dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO)); + dispatch(actions.updateBaseCurrency(BaseCurrency.ETH)); errorReporter.report(e); } }, -- cgit v1.2.3 From 68faaaba5f4278d7a1bd5d02f97921fa3c4238f4 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 10:04:23 -0800 Subject: Analytics events for ETH/USD toggle and failure to fetch eth usd price --- packages/instant/src/components/zero_ex_instant_provider.tsx | 1 + packages/instant/src/redux/analytics_middleware.ts | 3 +++ packages/instant/src/redux/async_data.ts | 1 + packages/instant/src/util/analytics.ts | 9 +++++++++ 4 files changed, 14 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 204115fa9..2de327cd7 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -122,6 +122,7 @@ export class ZeroExInstantProvider extends React.Component next => middlewareAction analytics.trackInstallWalletModalClosed(); } break; + case ActionTypes.UPDATE_BASE_CURRENCY: + analytics.trackBaseCurrencyChanged(curState.baseCurrency); + analytics.addEventProperties({ baseCurrency: curState.baseCurrency }); } return nextAction; diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 8ef95add4..3961d8821 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -26,6 +26,7 @@ export const asyncData = { dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO)); dispatch(actions.updateBaseCurrency(BaseCurrency.ETH)); errorReporter.report(e); + analytics.trackUsdPriceFailed(); } }, fetchAvailableAssetDatasAndDispatchToStore: async (state: State, dispatch: Dispatch) => { diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e6128f857..6c63907dc 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -6,6 +6,7 @@ import { GIT_SHA, HEAP_ENABLED, INSTANT_DISCHARGE_TARGET, NODE_ENV, NPM_PACKAGE_ import { AffiliateInfo, Asset, + BaseCurrency, Network, OrderProcessState, OrderSource, @@ -37,6 +38,7 @@ enum EventNames { ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested', ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', + BASE_CURRENCY_CHANGED = 'Base Currency - Changed', PAYMENT_METHOD_DROPDOWN_OPENED = 'Payment Method - Dropdown Opened', PAYMENT_METHOD_OPENED_ETHERSCAN = 'Payment Method - Opened Etherscan', PAYMENT_METHOD_COPIED_ADDRESS = 'Payment Method - Copied Address', @@ -47,6 +49,7 @@ enum EventNames { BUY_TX_SUBMITTED = 'Buy - Tx Submitted', BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded', BUY_TX_FAILED = 'Buy - Tx Failed', + USD_PRICE_FETCH_FAILED = 'USD Price - Fetch Failed', INSTALL_WALLET_CLICKED = 'Install Wallet - Clicked', INSTALL_WALLET_MODAL_OPENED = 'Install Wallet - Modal - Opened', INSTALL_WALLET_MODAL_CLICKED_EXPLANATION = 'Install Wallet - Modal - Clicked Explanation', @@ -118,6 +121,7 @@ export interface AnalyticsEventOptions { selectedAssetSymbol?: string; selectedAssetData?: string; selectedAssetDecimals?: number; + baseCurrency?: string; } export enum TokenSelectorClosedVia { ClickedX = 'Clicked X', @@ -141,6 +145,7 @@ export const analytics = { window: Window, selectedAsset?: Asset, affiliateInfo?: AffiliateInfo, + baseCurrency?: BaseCurrency, ): AnalyticsEventOptions => { const affiliateAddress = affiliateInfo ? affiliateInfo.feeRecipient : 'none'; const affiliateFeePercent = affiliateInfo ? parseFloat(affiliateInfo.feePercentage.toFixed(4)) : 0; @@ -159,6 +164,7 @@ export const analytics = { selectedAssetName: selectedAsset ? selectedAsset.metaData.name : 'none', selectedAssetData: selectedAsset ? selectedAsset.assetData : 'none', instantEnvironment: INSTANT_DISCHARGE_TARGET || `Local ${NODE_ENV}`, + baseCurrency, }; return eventOptions; }, @@ -170,6 +176,8 @@ export const analytics = { trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), trackAccountAddressChanged: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), + trackBaseCurrencyChanged: (currencyChangedTo: BaseCurrency) => + trackingEventFnWithPayload(EventNames.BASE_CURRENCY_CHANGED)({ currencyChangedTo }), trackPaymentMethodDropdownOpened: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_DROPDOWN_OPENED), trackPaymentMethodOpenedEtherscan: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_OPENED_ETHERSCAN), trackPaymentMethodCopiedAddress: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_COPIED_ADDRESS), @@ -230,4 +238,5 @@ export const analytics = { fetchOrigin, }); }, + trackUsdPriceFailed: trackingEventFnWithoutPayload(EventNames.USD_PRICE_FETCH_FAILED), }; -- cgit v1.2.3 From 756dc1e95ebbb8ef73ff8f712062997ea3d8c45e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 10:07:45 -0800 Subject: Linting --- packages/instant/src/components/order_details.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index ea975a5f7..c069a8bcc 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -27,11 +27,11 @@ export interface OrderDetailsProps { } export class OrderDetails extends React.Component { public render(): React.ReactNode { - const showUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice(); + const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice(); return ( {this._renderHeader()} - {showUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()} + {shouldShowUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()} ); } @@ -119,8 +119,7 @@ export class OrderDetails extends React.Component { } private _assetAmountLabel(): string { - const { assetName, baseCurrency, ethUsdPrice } = this.props; - + const { assetName, baseCurrency } = this.props; const numTokens = this.props.selectedAssetUnitAmount; // Display as 0 if we have a selected asset -- cgit v1.2.3 From 65579c023670c09f39b4f7a733d7b703888d9d99 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 13:43:08 -0800 Subject: Abstract SectionHeader and make 12px per Chris's comment and figma design --- packages/instant/src/components/order_details.tsx | 21 +++++++++------------ packages/instant/src/components/payment_method.tsx | 11 ++--------- packages/instant/src/components/section_header.tsx | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 21 deletions(-) create mode 100644 packages/instant/src/components/section_header.tsx (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index c069a8bcc..4aa375017 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -10,6 +10,7 @@ import { BaseCurrency } from '../types'; import { format } from '../util/format'; import { AmountPlaceholder } from './amount_placeholder'; +import { SectionHeader } from './section_header'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; @@ -157,10 +158,12 @@ export class OrderDetails extends React.Component { choice === BaseCurrency.ETH ? this.props.onBaseCurrencySwitchEth : this.props.onBaseCurrencySwitchUsd; const isSelected = this.props.baseCurrency === choice; - const textStyle: TextProps = { onClick, fontSize: '12px ' }; + const textStyle: TextProps = { onClick, fontSize: '12px' }; if (isSelected) { textStyle.fontColor = ColorOption.primaryColor; textStyle.fontWeight = 700; + } else { + textStyle.fontColor = ColorOption.lightGrey; } return {choice}; } @@ -168,19 +171,13 @@ export class OrderDetails extends React.Component { private _renderHeader(): React.ReactNode { return ( - - Order Details - + Order Details {this._baseCurrencyChoice(BaseCurrency.ETH)} - - / + + + / + {this._baseCurrencyChoice(BaseCurrency.USD)} diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index 7c93f1d1c..abadf4bd6 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -8,6 +8,7 @@ import { envUtil } from '../util/env'; import { CoinbaseWalletLogo } from './coinbase_wallet_logo'; import { MetaMaskLogo } from './meta_mask_logo'; import { PaymentMethodDropdown } from './payment_method_dropdown'; +import { SectionHeader } from './section_header'; import { Circle } from './ui/circle'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; @@ -29,15 +30,7 @@ export class PaymentMethod extends React.Component { - - {this._renderTitleText()} - + {this._renderTitleText()} {this._renderTitleLabel()} diff --git a/packages/instant/src/components/section_header.tsx b/packages/instant/src/components/section_header.tsx new file mode 100644 index 000000000..a6be3d8af --- /dev/null +++ b/packages/instant/src/components/section_header.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Text } from './ui/text'; + +export interface SectionHeaderProps { + children?: React.ReactNode; +} +export const SectionHeader: React.StatelessComponent<{}> = props => { + return ( + + {props.children} + + ); +}; -- cgit v1.2.3 From 9e5e1f568ba71927cec2255bf779322edb6f7d07 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 14:25:56 -0800 Subject: show as <$0.01 when less than a cent in USD, and also show 1 significant digit if rounded amount is 0 --- packages/instant/src/util/format.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/format.ts b/packages/instant/src/util/format.ts index e9c432b2f..3aaf9a3a7 100644 --- a/packages/instant/src/util/format.ts +++ b/packages/instant/src/util/format.ts @@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; -import { ETH_DECIMALS } from '../constants'; +import { BIG_NUMBER_ZERO, ETH_DECIMALS } from '../constants'; export const format = { ethBaseUnitAmount: ( @@ -25,7 +25,10 @@ export const format = { return defaultText; } const roundedAmount = ethUnitAmount.round(decimalPlaces).toDigits(decimalPlaces); - return `${roundedAmount} ETH`; + // Sometimes for small ETH amounts (i.e. 0.000045) the amount rounded to 4 decimalPlaces is 0 + // If that is the case, show to 1 significant digit + const displayAmount = roundedAmount.eq(BIG_NUMBER_ZERO) ? ethUnitAmount.toPrecision(1) : roundedAmount; + return `${displayAmount} ETH`; }, ethBaseUnitAmountInUsd: ( ethBaseUnitAmount?: BigNumber, @@ -48,7 +51,13 @@ export const format = { if (_.isUndefined(ethUnitAmount) || _.isUndefined(ethUsdPrice)) { return defaultText; } - return `$${ethUnitAmount.mul(ethUsdPrice).toFixed(decimalPlaces)}`; + const rawUsdPrice = ethUnitAmount.mul(ethUsdPrice); + const roundedUsdPrice = rawUsdPrice.toFixed(decimalPlaces); + if (roundedUsdPrice === '0.00' && rawUsdPrice.gt(BIG_NUMBER_ZERO)) { + return '<$0.01'; + } else { + return `$${roundedUsdPrice}`; + } }, ethAddress: (address: string): string => { return `0x${address.slice(2, 7)}…${address.slice(-5)}`; -- cgit v1.2.3 From 2e7d363f2cf76e383bb8723cfb0f2e3c1e4783d8 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 15:46:46 -0800 Subject: Use helper function to check for error --- packages/instant/src/components/order_details.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 4aa375017..6ce19742f 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -85,9 +85,7 @@ export class OrderDetails extends React.Component { const canDisplayCurrency = secondaryCurrency === BaseCurrency.ETH || - (secondaryCurrency === BaseCurrency.USD && - this.props.ethUsdPrice && - this.props.ethUsdPrice.greaterThan(BIG_NUMBER_ZERO)); + (secondaryCurrency === BaseCurrency.USD && this.props.ethUsdPrice && !this._hadErrorFetchingUsdPrice); if (this.props.buyQuoteInfo && canDisplayCurrency) { return this._displayAmount(secondaryCurrency, this.props.buyQuoteInfo.totalEthAmount); -- cgit v1.2.3 From 167a3fbc112120b6a583f3ec3c8fdd70d39df078 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 15:57:28 -0800 Subject: Use BN equals and call function --- packages/instant/src/components/order_details.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 6ce19742f..96bdb7150 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -77,7 +77,7 @@ export class OrderDetails extends React.Component { } private _hadErrorFetchingUsdPrice(): boolean { - return this.props.ethUsdPrice === BIG_NUMBER_ZERO; + return this.props.ethUsdPrice ? this.props.ethUsdPrice.equals(BIG_NUMBER_ZERO) : false; } private _totalCostSecondaryValue(): React.ReactNode { @@ -85,7 +85,7 @@ export class OrderDetails extends React.Component { const canDisplayCurrency = secondaryCurrency === BaseCurrency.ETH || - (secondaryCurrency === BaseCurrency.USD && this.props.ethUsdPrice && !this._hadErrorFetchingUsdPrice); + (secondaryCurrency === BaseCurrency.USD && this.props.ethUsdPrice && !this._hadErrorFetchingUsdPrice()); if (this.props.buyQuoteInfo && canDisplayCurrency) { return this._displayAmount(secondaryCurrency, this.props.buyQuoteInfo.totalEthAmount); -- cgit v1.2.3 From 8d54772389b28dec021aa81423ac84795e132581 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 17:34:14 -0800 Subject: show < 0.00001 ETH when amount gets really small --- packages/instant/src/util/format.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/format.ts b/packages/instant/src/util/format.ts index 3aaf9a3a7..4adb63e21 100644 --- a/packages/instant/src/util/format.ts +++ b/packages/instant/src/util/format.ts @@ -20,14 +20,24 @@ export const format = { ethUnitAmount?: BigNumber, decimalPlaces: number = 4, defaultText: React.ReactNode = '0 ETH', + minUnitAmountToDisplay: BigNumber = new BigNumber('0.00001'), ): React.ReactNode => { if (_.isUndefined(ethUnitAmount)) { return defaultText; } - const roundedAmount = ethUnitAmount.round(decimalPlaces).toDigits(decimalPlaces); - // Sometimes for small ETH amounts (i.e. 0.000045) the amount rounded to 4 decimalPlaces is 0 - // If that is the case, show to 1 significant digit - const displayAmount = roundedAmount.eq(BIG_NUMBER_ZERO) ? ethUnitAmount.toPrecision(1) : roundedAmount; + let roundedAmount = ethUnitAmount.round(decimalPlaces).toDigits(decimalPlaces); + + if (roundedAmount.eq(BIG_NUMBER_ZERO) && ethUnitAmount.greaterThan(BIG_NUMBER_ZERO)) { + // Sometimes for small ETH amounts (i.e. 0.000045) the amount rounded to 4 decimalPlaces is 0 + // If that is the case, show to 1 significant digit + roundedAmount = new BigNumber(ethUnitAmount.toPrecision(1)); + } + + const displayAmount = + roundedAmount.greaterThan(BIG_NUMBER_ZERO) && roundedAmount.lessThan(minUnitAmountToDisplay) + ? `< ${minUnitAmountToDisplay.toString()}` + : roundedAmount.toString(); + return `${displayAmount} ETH`; }, ethBaseUnitAmountInUsd: ( @@ -35,12 +45,13 @@ export const format = { ethUsdPrice?: BigNumber, decimalPlaces: number = 2, defaultText: React.ReactNode = '$0.00', + minUnitAmountToDisplay: BigNumber = new BigNumber('0.00001'), ): React.ReactNode => { if (_.isUndefined(ethBaseUnitAmount) || _.isUndefined(ethUsdPrice)) { return defaultText; } const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseUnitAmount, ETH_DECIMALS); - return format.ethUnitAmountInUsd(ethUnitAmount, ethUsdPrice, decimalPlaces); + return format.ethUnitAmountInUsd(ethUnitAmount, ethUsdPrice, decimalPlaces, minUnitAmountToDisplay); }, ethUnitAmountInUsd: ( ethUnitAmount?: BigNumber, -- cgit v1.2.3 From 193cd67d6bfffc35feccd46d5c1b5f23320dc8ce Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 12 Dec 2018 17:43:27 -0800 Subject: A little bit of scaling logic for not cutting off text --- packages/instant/src/components/instant_heading.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 816cc5c33..99e531574 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -113,20 +113,23 @@ export class InstantHeading extends React.Component { } private readonly _renderEthAmount = (): React.ReactNode => { + const ethAmount = format.ethBaseUnitAmount( + this.props.totalEthBaseUnitAmount, + 4, + , + ); + + const fontSize = typeof ethAmount === 'string' && ethAmount.length >= 13 ? '14px' : '16px'; return ( - {format.ethBaseUnitAmount( - this.props.totalEthBaseUnitAmount, - 4, - , - )} + {ethAmount} ); }; -- cgit v1.2.3 From 9a1d2c055e176414ee1e7661d5acc764cc9a745d Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 13 Dec 2018 08:31:40 -0800 Subject: Fix SectionHeaderProps --- packages/instant/src/components/section_header.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/section_header.tsx b/packages/instant/src/components/section_header.tsx index a6be3d8af..d0974ebdc 100644 --- a/packages/instant/src/components/section_header.tsx +++ b/packages/instant/src/components/section_header.tsx @@ -4,10 +4,8 @@ import { ColorOption } from '../style/theme'; import { Text } from './ui/text'; -export interface SectionHeaderProps { - children?: React.ReactNode; -} -export const SectionHeader: React.StatelessComponent<{}> = props => { +export interface SectionHeaderProps {} +export const SectionHeader: React.StatelessComponent = props => { return ( Date: Thu, 13 Dec 2018 12:45:38 -0800 Subject: simplify scaling input logic --- .../src/components/scaling_amount_input.tsx | 1 + packages/instant/src/components/scaling_input.tsx | 65 ++++++---------------- packages/instant/src/components/ui/input.tsx | 2 +- 3 files changed, 18 insertions(+), 50 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 86aca5a65..4feb0502d 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -58,6 +58,7 @@ export class ScalingAmountInput extends React.Component { +export class ScalingInput extends React.Component { public static defaultProps = { onChange: util.boundNoop, onFontSizeChange: util.boundNoop, @@ -54,9 +49,6 @@ export class ScalingInput extends React.Component(); public static getPhase(textLengthThreshold: number, value: string): ScalingInputPhase { if (value.length <= textLengthThreshold) { @@ -93,36 +85,15 @@ export class ScalingInput extends React.Component { return ScalingInput.calculateFontSizeFromProps(this.props, phase); @@ -178,4 +137,12 @@ export class ScalingInput extends React.Component): void => { + const value = event.target.value; + const { maxLength } = this.props; + if (!_.isUndefined(value) && !_.isUndefined(maxLength) && value.length > maxLength) { + return; + } + this.props.onChange(event); + }; } diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index 1e476bed3..697bfaf0f 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { ColorOption, styled } from '../../style/theme'; -export interface InputProps { +export interface InputProps extends React.HTMLAttributes { tabIndex?: number; className?: string; value?: string; -- cgit v1.2.3 From 9cd859a68a94e90eb9891c5b9a4ec7518b7fb64d Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 13 Dec 2018 13:03:45 -0800 Subject: run linter --- packages/instant/src/components/scaling_input.tsx | 39 ++++++++++++++++------- packages/instant/src/components/ui/input.tsx | 6 ++-- 2 files changed, 31 insertions(+), 14 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 78c83115a..00aea37da 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -1,3 +1,4 @@ +import { ObjectMap } from '@0x/types'; import * as _ from 'lodash'; import * as React from 'react'; @@ -13,6 +14,11 @@ export enum ScalingInputPhase { export interface ScalingSettings { percentageToReduceFontSizePerCharacter: number; + // 1ch = the width of the 0 chararacter. + // Allow to customize 'char' length for different characters. + characterWidthOverrides: ObjectMap; + // How much room to leave to the right of the scaling input. + additionalInputSpaceInCh: number; } export interface ScalingInputProps { @@ -38,13 +44,18 @@ export interface ScalingInputSnapshot { // These are magic numbers that were determined experimentally. const defaultScalingSettings: ScalingSettings = { percentageToReduceFontSizePerCharacter: 0.1, + characterWidthOverrides: { + '1': 0.7, + '.': 0.4, + }, + additionalInputSpaceInCh: 0.4, }; export class ScalingInput extends React.Component { public static defaultProps = { onChange: util.boundNoop, onFontSizeChange: util.boundNoop, - maxLength: 7, + maxLength: 9, scalingSettings: defaultScalingSettings, isDisabled: false, hasAutofocus: false, @@ -102,7 +113,7 @@ export class ScalingInput extends React.Component { } } public render(): React.ReactNode { - const { type, hasAutofocus, isDisabled, fontColor, onChange, placeholder, value, maxLength } = this.props; + const { type, hasAutofocus, isDisabled, fontColor, placeholder, value, maxLength } = this.props; const phase = ScalingInput.getPhaseFromProps(this.props); return ( { ); } private readonly _calculateWidth = (phase: ScalingInputPhase): string => { - const { value, textLengthThreshold, scalingSettings } = this.props; + const { value, scalingSettings } = this.props; if (_.isEmpty(value)) { return `${this.props.emptyInputWidthCh}ch`; } - return `${value.length}ch`; + const lengthInCh = _.reduce( + value.split(''), + (sum, char) => { + const widthOverride = scalingSettings.characterWidthOverrides[char]; + if (!_.isUndefined(widthOverride)) { + // tslint is confused + // tslint:disable-next-line:restrict-plus-operands + return sum + widthOverride; + } + return sum + 1; + }, + scalingSettings.additionalInputSpaceInCh, + ); + return `${lengthInCh}ch`; }; private readonly _calculateFontSize = (phase: ScalingInputPhase): number => { return ScalingInput.calculateFontSizeFromProps(this.props, phase); }; - private readonly _getInputWidthInPx = (): number => { - const ref = this._inputRef.current; - if (!ref) { - return 0; - } - return ref.getBoundingClientRect().width; - }; private readonly _handleChange = (event: React.ChangeEvent): void => { const value = event.target.value; const { maxLength } = this.props; diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index 697bfaf0f..53c43ea0b 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -32,9 +32,9 @@ export const Input = color: ${props => props.theme[props.fontColor || 'white']} !important; opacity: 0.5 !important; } - &::-webkit-outer-spin-button, &::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; + &::-webkit-outer-spin-button, &::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; } } `; -- cgit v1.2.3 From 9697d66b66a9c8ae9f350aae8cf0d6b951a3c96b Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 13 Dec 2018 13:31:30 -0800 Subject: typeof -> isString --- packages/instant/src/components/instant_heading.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 99e531574..5b1f9592d 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -119,7 +119,7 @@ export class InstantHeading extends React.Component { , ); - const fontSize = typeof ethAmount === 'string' && ethAmount.length >= 13 ? '14px' : '16px'; + const fontSize = _.isString(ethAmount) && ethAmount.length >= 13 ? '14px' : '16px'; return ( Date: Thu, 13 Dec 2018 14:27:27 -0800 Subject: Show @ price in light grey --- packages/instant/src/components/order_details.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 96bdb7150..33a115044 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -117,7 +117,7 @@ export class OrderDetails extends React.Component { } } - private _assetAmountLabel(): string { + private _assetAmountLabel(): React.ReactNode { const { assetName, baseCurrency } = this.props; const numTokens = this.props.selectedAssetUnitAmount; @@ -127,13 +127,14 @@ export class OrderDetails extends React.Component { ? new BigNumber(0) : numTokens; if (!_.isUndefined(displayNumTokens)) { - let numTokensWithSymbol = displayNumTokens.toString(); + let numTokensWithSymbol: React.ReactNode = displayNumTokens.toString(); if (assetName) { numTokensWithSymbol += ` ${assetName}`; } const pricePerTokenWei = this._pricePerTokenWei(); if (pricePerTokenWei) { - numTokensWithSymbol += ` @ ${this._displayAmount(baseCurrency, pricePerTokenWei)}`; + const atPriceDisplay = @ {this._displayAmount(baseCurrency, pricePerTokenWei)}; + numTokensWithSymbol = {numTokensWithSymbol} {atPriceDisplay} } return numTokensWithSymbol; } @@ -185,7 +186,7 @@ export class OrderDetails extends React.Component { } export interface OrderDetailsRowProps { - labelText: string; + labelText: React.ReactNode; isLabelBold?: boolean; isPrimaryValueBold?: boolean; primaryValue: React.ReactNode; -- cgit v1.2.3 From 926fcb296fb728c3520c638a43a5da950393832e Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 14 Dec 2018 14:06:24 -0800 Subject: fix(instant): treat executeBuyQuote errors as signature denials --- packages/instant/src/components/buy_button.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 1489b94d4..880303cc7 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -10,6 +10,7 @@ import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants' import { ColorOption } from '../style/theme'; import { AffiliateInfo, Asset, ZeroExInstantError } from '../types'; import { analytics } from '../util/analytics'; +import { errorReporter } from '../util/error_reporter'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { util } from '../util/util'; @@ -82,14 +83,17 @@ export class BuyButton extends React.Component { }); } catch (e) { if (e instanceof Error) { - if (e.message === AssetBuyerError.SignatureRequestDenied) { - analytics.trackBuySignatureDenied(buyQuote); - this.props.onSignatureDenied(buyQuote); - return; - } else if (e.message === AssetBuyerError.TransactionValueTooLow) { + if (e.message === AssetBuyerError.TransactionValueTooLow) { analytics.trackBuySimulationFailed(buyQuote); this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow); return; + } else { + if (e.message !== AssetBuyerError.SignatureRequestDenied) { + errorReporter.report(e); + } + analytics.trackBuySignatureDenied(buyQuote); + this.props.onSignatureDenied(buyQuote); + return; } } throw e; -- cgit v1.2.3 From 21a193e51650a78e59aaf6ae49b5120fb8b73e15 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 14 Dec 2018 14:10:15 -0800 Subject: feature(instant): add trust wallet detection --- packages/instant/src/constants.ts | 1 + packages/instant/src/types.ts | 1 + packages/instant/src/util/env.ts | 2 ++ 3 files changed, 4 insertions(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index f83eb4ac7..6d3680dc1 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -71,5 +71,6 @@ export const PROVIDER_TYPE_TO_NAME: { [key in ProviderType]: string } = { [ProviderType.Mist]: 'Mist', [ProviderType.CoinbaseWallet]: 'Coinbase Wallet', [ProviderType.Parity]: 'Parity', + [ProviderType.TrustWallet]: 'Trust Wallet', [ProviderType.Fallback]: 'Fallback', }; diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 1c7490e63..6374dda09 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -176,6 +176,7 @@ export enum ProviderType { Mist = 'MIST', CoinbaseWallet = 'COINBASE_WALLET', Cipher = 'CIPHER', + TrustWallet = 'TRUST_WALLET', Fallback = 'FALLBACK', } diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts index 0fda0cc0e..0f0b472b2 100644 --- a/packages/instant/src/util/env.ts +++ b/packages/instant/src/util/env.ts @@ -44,6 +44,8 @@ export const envUtil = { getProviderType(provider: Provider): ProviderType | undefined { if (provider.constructor.name === 'EthereumProvider') { return ProviderType.Mist; + } else if (provider.constructor.name === 'TrustWeb3Provider') { + return ProviderType.TrustWallet; } else if ((provider as any).isParity) { return ProviderType.Parity; } else if ((provider as any).isMetaMask) { -- cgit v1.2.3 From 67422db4bd0b194296a1a584af7ead089e281715 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 14 Dec 2018 15:58:23 -0800 Subject: fix semicolon and apply prettier --- packages/instant/src/components/order_details.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 33a115044..9c10ef9e6 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -133,8 +133,16 @@ export class OrderDetails extends React.Component { } const pricePerTokenWei = this._pricePerTokenWei(); if (pricePerTokenWei) { - const atPriceDisplay = @ {this._displayAmount(baseCurrency, pricePerTokenWei)}; - numTokensWithSymbol = {numTokensWithSymbol} {atPriceDisplay} + const atPriceDisplay = ( + + @ {this._displayAmount(baseCurrency, pricePerTokenWei)} + + ); + numTokensWithSymbol = ( + + {numTokensWithSymbol} {atPriceDisplay} + + ); } return numTokensWithSymbol; } -- cgit v1.2.3 From 2effc3e267f01e620c50622138d98381883d4c32 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 20 Dec 2018 14:10:29 -0800 Subject: fix(instant): use isTrust property to determine if provider is trust wallet --- packages/instant/src/util/env.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts index 0f0b472b2..aedf4f5d6 100644 --- a/packages/instant/src/util/env.ts +++ b/packages/instant/src/util/env.ts @@ -44,7 +44,7 @@ export const envUtil = { getProviderType(provider: Provider): ProviderType | undefined { if (provider.constructor.name === 'EthereumProvider') { return ProviderType.Mist; - } else if (provider.constructor.name === 'TrustWeb3Provider') { + } else if ((provider as any).isTrust) { return ProviderType.TrustWallet; } else if ((provider as any).isParity) { return ProviderType.Parity; -- cgit v1.2.3 From 080c6d3146bee3691b6f3b9452be639354236e44 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 20 Dec 2018 14:32:11 -0800 Subject: fix(instant): catch unknown errors from executeBuyAsync, report them and show could not submit transaction --- packages/instant/src/components/buy_button.tsx | 9 +++++---- .../src/containers/selected_asset_buy_order_state_buttons.ts | 3 +++ packages/instant/src/types.ts | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 880303cc7..ff1cda1e1 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -87,13 +87,14 @@ export class BuyButton extends React.Component { analytics.trackBuySimulationFailed(buyQuote); this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow); return; - } else { - if (e.message !== AssetBuyerError.SignatureRequestDenied) { - errorReporter.report(e); - } + } else if (e.message === AssetBuyerError.SignatureRequestDenied) { analytics.trackBuySignatureDenied(buyQuote); this.props.onSignatureDenied(buyQuote); return; + } else { + errorReporter.report(e); + this.props.onValidationFail(buyQuote, ZeroExInstantError.CouldNotSubmitTransaction); + return; } } throw e; diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts index 80943a96f..4da99cf04 100644 --- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts +++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts @@ -95,6 +95,9 @@ const mapDispatchToProps = ( if (error === ZeroExInstantError.InsufficientETH) { const errorMessage = "You don't have enough ETH"; errorFlasher.flashNewErrorMessage(dispatch, errorMessage); + } else if (error === ZeroExInstantError.CouldNotSubmitTransaction) { + const errorMessage = 'Could not submit transaction'; + errorFlasher.flashNewErrorMessage(dispatch, errorMessage); } else { errorFlasher.flashNewErrorMessage(dispatch); } diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 6374dda09..d217c1a4f 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -91,6 +91,7 @@ export enum Network { export enum ZeroExInstantError { AssetMetaDataNotAvailable = 'ASSET_META_DATA_NOT_AVAILABLE', InsufficientETH = 'INSUFFICIENT_ETH', + CouldNotSubmitTransaction = 'COULD_NOT_SUBMIT_TRANSACTION', } export type SimpleHandler = () => void; -- cgit v1.2.3 From bbe9862aa6c0e495c58ee028d8e4964b63377d1c Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 20 Dec 2018 14:43:14 -0800 Subject: fix(instant): add analytics to unknown error on executeBuyAsync --- packages/instant/src/components/buy_button.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index ff1cda1e1..46d121611 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -93,6 +93,7 @@ export class BuyButton extends React.Component { return; } else { errorReporter.report(e); + analytics.trackBuySignatureDenied(buyQuote); this.props.onValidationFail(buyQuote, ZeroExInstantError.CouldNotSubmitTransaction); return; } -- cgit v1.2.3 From b399aa25aa9386d388d31edb463e803c7c31a2db Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 20 Dec 2018 15:05:54 -0800 Subject: feat(instant): add new event for unknown buy errors --- packages/instant/src/components/buy_button.tsx | 2 +- packages/instant/src/util/analytics.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 46d121611..5c9c28ae4 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -93,7 +93,7 @@ export class BuyButton extends React.Component { return; } else { errorReporter.report(e); - analytics.trackBuySignatureDenied(buyQuote); + analytics.trackBuyUnknownError(buyQuote, e.message); this.props.onValidationFail(buyQuote, ZeroExInstantError.CouldNotSubmitTransaction); return; } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e6128f857..21d3a4d9e 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -44,6 +44,7 @@ enum EventNames { BUY_STARTED = 'Buy - Started', BUY_SIGNATURE_DENIED = 'Buy - Signature Denied', BUY_SIMULATION_FAILED = 'Buy - Simulation Failed', + BUY_UNKNOWN_ERROR = 'Buy - Unknown Error', BUY_TX_SUBMITTED = 'Buy - Tx Submitted', BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded', BUY_TX_FAILED = 'Buy - Tx Failed', @@ -181,6 +182,11 @@ export const analytics = { trackingEventFnWithPayload(EventNames.BUY_SIGNATURE_DENIED)(buyQuoteEventProperties(buyQuote)), trackBuySimulationFailed: (buyQuote: BuyQuote) => trackingEventFnWithPayload(EventNames.BUY_SIMULATION_FAILED)(buyQuoteEventProperties(buyQuote)), + trackBuyUnknownError: (buyQuote: BuyQuote, errorMessage: string) => + trackingEventFnWithPayload(EventNames.BUY_UNKNOWN_ERROR)({ + ...buyQuoteEventProperties(buyQuote), + errorMessage, + }), trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ ...buyQuoteEventProperties(buyQuote), -- cgit v1.2.3 From 586a8ba8e7427eab2fdc974dab6483105b7cd5b6 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 2 Jan 2019 16:01:40 +0100 Subject: feat: use PureComponent instead of Component --- packages/instant/src/components/buy_button.tsx | 2 +- packages/instant/src/components/erc20_asset_amount_input.tsx | 2 +- packages/instant/src/components/erc20_token_selector.tsx | 4 ++-- packages/instant/src/components/install_wallet_panel_content.tsx | 2 +- packages/instant/src/components/instant_heading.tsx | 2 +- packages/instant/src/components/order_details.tsx | 4 ++-- packages/instant/src/components/payment_method.tsx | 2 +- packages/instant/src/components/payment_method_dropdown.tsx | 2 +- packages/instant/src/components/scaling_amount_input.tsx | 2 +- packages/instant/src/components/scaling_input.tsx | 2 +- packages/instant/src/components/standard_sliding_panel.tsx | 2 +- packages/instant/src/components/time_counter.tsx | 2 +- packages/instant/src/components/timed_progress_bar.tsx | 2 +- packages/instant/src/components/ui/dropdown.tsx | 2 +- packages/instant/src/components/zero_ex_instant_container.tsx | 2 +- packages/instant/src/components/zero_ex_instant_provider.tsx | 2 +- 16 files changed, 18 insertions(+), 18 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 5c9c28ae4..551e857a5 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -32,7 +32,7 @@ export interface BuyButtonProps { onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; } -export class BuyButton extends React.Component { +export class BuyButton extends React.PureComponent { public static defaultProps = { onClick: util.boundNoop, onBuySuccess: util.boundNoop, diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index 4da82eb73..0418f9165 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -31,7 +31,7 @@ export interface ERC20AssetAmountInputState { currentFontSizePx: number; } -export class ERC20AssetAmountInput extends React.Component { +export class ERC20AssetAmountInput extends React.PureComponent { public static defaultProps = { onChange: util.boundNoop, isDisabled: false, diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index cb8a8c797..fc7c21d47 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -21,7 +21,7 @@ export interface ERC20TokenSelectorState { searchQuery: string; } -export class ERC20TokenSelector extends React.Component { +export class ERC20TokenSelector extends React.PureComponent { public state: ERC20TokenSelectorState = { searchQuery: '', }; @@ -76,7 +76,7 @@ interface TokenSelectorRowProps { onClick: (token: ERC20Asset) => void; } -class TokenSelectorRow extends React.Component { +class TokenSelectorRow extends React.PureComponent { public render(): React.ReactNode { const { token } = this.props; const circleColor = token.metaData.primaryColor || 'black'; diff --git a/packages/instant/src/components/install_wallet_panel_content.tsx b/packages/instant/src/components/install_wallet_panel_content.tsx index 481d82da0..1af3dafbb 100644 --- a/packages/instant/src/components/install_wallet_panel_content.tsx +++ b/packages/instant/src/components/install_wallet_panel_content.tsx @@ -18,7 +18,7 @@ import { Button } from './ui/button'; export interface InstallWalletPanelContentProps {} -export class InstallWalletPanelContent extends React.Component { +export class InstallWalletPanelContent extends React.PureComponent { public render(): React.ReactNode { const panelProps = this._getStandardPanelContentProps(); return ; diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 5b1f9592d..e943f68d7 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -28,7 +28,7 @@ const ICON_WIDTH = 34; const ICON_HEIGHT = 34; const ICON_COLOR = ColorOption.white; -export class InstantHeading extends React.Component { +export class InstantHeading extends React.PureComponent { public render(): React.ReactNode { const iconOrAmounts = this._renderIcon() || this._renderAmountsSection(); return ( diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 9c10ef9e6..4db20b13e 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -26,7 +26,7 @@ export interface OrderDetailsProps { onBaseCurrencySwitchEth: () => void; onBaseCurrencySwitchUsd: () => void; } -export class OrderDetails extends React.Component { +export class OrderDetails extends React.PureComponent { public render(): React.ReactNode { const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice(); return ( @@ -200,7 +200,7 @@ export interface OrderDetailsRowProps { primaryValue: React.ReactNode; secondaryValue?: React.ReactNode; } -export class OrderDetailsRow extends React.Component { +export class OrderDetailsRow extends React.PureComponent { public render(): React.ReactNode { return ( diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index abadf4bd6..ada9f7bab 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -24,7 +24,7 @@ export interface PaymentMethodProps { onUnlockWalletClick: () => void; } -export class PaymentMethod extends React.Component { +export class PaymentMethod extends React.PureComponent { public render(): React.ReactNode { return ( diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx index 872ac0831..e463e3eae 100644 --- a/packages/instant/src/components/payment_method_dropdown.tsx +++ b/packages/instant/src/components/payment_method_dropdown.tsx @@ -16,7 +16,7 @@ export interface PaymentMethodDropdownProps { network: Network; } -export class PaymentMethodDropdown extends React.Component { +export class PaymentMethodDropdown extends React.PureComponent { public render(): React.ReactNode { const { accountAddress, accountEthBalanceInWei } = this.props; const value = format.ethAddress(accountAddress); diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 4feb0502d..7dc1fdc0c 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -26,7 +26,7 @@ interface ScalingAmountInputState { } const { stringToMaybeBigNumber, areMaybeBigNumbersEqual } = maybeBigNumberUtil; -export class ScalingAmountInput extends React.Component { +export class ScalingAmountInput extends React.PureComponent { public static defaultProps = { onAmountChange: util.boundNoop, onFontSizeChange: util.boundNoop, diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 00aea37da..c31de1fb5 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -51,7 +51,7 @@ const defaultScalingSettings: ScalingSettings = { additionalInputSpaceInCh: 0.4, }; -export class ScalingInput extends React.Component { +export class ScalingInput extends React.PureComponent { public static defaultProps = { onChange: util.boundNoop, onFontSizeChange: util.boundNoop, diff --git a/packages/instant/src/components/standard_sliding_panel.tsx b/packages/instant/src/components/standard_sliding_panel.tsx index 9f517d273..bcc9d3dce 100644 --- a/packages/instant/src/components/standard_sliding_panel.tsx +++ b/packages/instant/src/components/standard_sliding_panel.tsx @@ -9,7 +9,7 @@ export interface StandardSlidingPanelProps extends StandardSlidingPanelSettings onClose: () => void; } -export class StandardSlidingPanel extends React.Component { +export class StandardSlidingPanel extends React.PureComponent { public render(): React.ReactNode { const { animationState, content, onClose } = this.props; return ( diff --git a/packages/instant/src/components/time_counter.tsx b/packages/instant/src/components/time_counter.tsx index f9b68163c..93dc497d5 100644 --- a/packages/instant/src/components/time_counter.tsx +++ b/packages/instant/src/components/time_counter.tsx @@ -16,7 +16,7 @@ interface TimeCounterState { elapsedSeconds: number; } -export class TimeCounter extends React.Component { +export class TimeCounter extends React.PureComponent { public state = { elapsedSeconds: 0, }; diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index fb3927088..b1644b871 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -17,7 +17,7 @@ export interface TimedProgressBarProps { * Goes from 0% -> PROGRESS_STALL_AT_WIDTH over time of expectedTimeMs * When hasEnded set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length of time */ -export class TimedProgressBar extends React.Component { +export class TimedProgressBar extends React.PureComponent { private readonly _barRef = React.createRef(); public render(): React.ReactNode { diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index 02e87d639..590d9dedb 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -26,7 +26,7 @@ export interface DropdownState { isOpen: boolean; } -export class Dropdown extends React.Component { +export class Dropdown extends React.PureComponent { public static defaultProps = { items: [], }; diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 0337c7714..63497e639 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -24,7 +24,7 @@ export interface ZeroExInstantContainerState { tokenSelectionPanelAnimationState: SlideAnimationState; } -export class ZeroExInstantContainer extends React.Component { +export class ZeroExInstantContainer extends React.PureComponent { public state = { tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 2de327cd7..ec8e82ee3 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -21,7 +21,7 @@ import { providerStateFactory } from '../util/provider_state_factory'; export type ZeroExInstantProviderProps = ZeroExInstantBaseConfig; -export class ZeroExInstantProvider extends React.Component { +export class ZeroExInstantProvider extends React.PureComponent { private readonly _store: Store; private _accountUpdateHeartbeat?: Heartbeater; private _buyQuoteHeartbeat?: Heartbeater; -- cgit v1.2.3 From 5721b25c3ace6e0dc336e2bfc7a0e45fd575a5a8 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 2 Jan 2019 16:08:15 +0100 Subject: feat: give all stateless components a displayName or make them private --- packages/instant/src/components/amount_placeholder.tsx | 2 ++ packages/instant/src/components/animations/slide_animation.tsx | 2 ++ packages/instant/src/components/buy_order_progress.tsx | 2 ++ packages/instant/src/components/buy_order_state_buttons.tsx | 2 ++ packages/instant/src/components/placing_order_button.tsx | 2 ++ packages/instant/src/components/secondary_button.tsx | 1 + packages/instant/src/components/section_header.tsx | 1 + packages/instant/src/components/sliding_error.tsx | 4 ++++ packages/instant/src/components/sliding_panel.tsx | 4 ++++ packages/instant/src/components/standard_panel_content.tsx | 2 ++ packages/instant/src/components/ui/dropdown.tsx | 2 ++ packages/instant/src/components/wallet_prompt.tsx | 2 ++ packages/instant/src/components/zero_ex_instant.tsx | 2 ++ packages/instant/src/components/zero_ex_instant_overlay.tsx | 2 ++ packages/instant/src/containers/latest_error.tsx | 4 ++-- 15 files changed, 32 insertions(+), 2 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx index 29ce8fafb..290e34a07 100644 --- a/packages/instant/src/components/amount_placeholder.tsx +++ b/packages/instant/src/components/amount_placeholder.tsx @@ -30,3 +30,5 @@ export const AmountPlaceholder: React.StatelessComponent return ; } }; + +AmountPlaceholder.displayName = 'AmountPlaceholder'; diff --git a/packages/instant/src/components/animations/slide_animation.tsx b/packages/instant/src/components/animations/slide_animation.tsx index 5992bcba7..dc42e168d 100644 --- a/packages/instant/src/components/animations/slide_animation.tsx +++ b/packages/instant/src/components/animations/slide_animation.tsx @@ -24,3 +24,5 @@ export const SlideAnimation: React.StatelessComponent = pro ); }; + +SlideAnimation.displayName = 'SlideAnimation'; diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx index a19f5a4d0..11ac5d5e0 100644 --- a/packages/instant/src/components/buy_order_progress.tsx +++ b/packages/instant/src/components/buy_order_progress.tsx @@ -31,3 +31,5 @@ export const BuyOrderProgress: React.StatelessComponent = } return null; }; + +BuyOrderProgress.displayName = 'BuyOrderProgress'; diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index 833818900..1214559d1 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -71,3 +71,5 @@ export const BuyOrderStateButtons: React.StatelessComponent ); }; + +BuyOrderStateButtons.displayName = 'BuyOrderStateButtons'; diff --git a/packages/instant/src/components/placing_order_button.tsx b/packages/instant/src/components/placing_order_button.tsx index 2516b90b1..528a305dc 100644 --- a/packages/instant/src/components/placing_order_button.tsx +++ b/packages/instant/src/components/placing_order_button.tsx @@ -14,3 +14,5 @@ export const PlacingOrderButton: React.StatelessComponent<{}> = props => ( Placing Order… ); + +PlacingOrderButton.displayName = 'PlacingOrderButton'; diff --git a/packages/instant/src/components/secondary_button.tsx b/packages/instant/src/components/secondary_button.tsx index 705390e28..0714ce287 100644 --- a/packages/instant/src/components/secondary_button.tsx +++ b/packages/instant/src/components/secondary_button.tsx @@ -24,3 +24,4 @@ export const SecondaryButton: React.StatelessComponent = p SecondaryButton.defaultProps = { width: '100%', }; +SecondaryButton.displayName = 'SecondaryButton'; diff --git a/packages/instant/src/components/section_header.tsx b/packages/instant/src/components/section_header.tsx index d0974ebdc..2185b67ba 100644 --- a/packages/instant/src/components/section_header.tsx +++ b/packages/instant/src/components/section_header.tsx @@ -18,3 +18,4 @@ export const SectionHeader: React.StatelessComponent = props ); }; +SectionHeader.displayName = 'SectionHeader'; diff --git a/packages/instant/src/components/sliding_error.tsx b/packages/instant/src/components/sliding_error.tsx index b59e2a905..c7c6732cf 100644 --- a/packages/instant/src/components/sliding_error.tsx +++ b/packages/instant/src/components/sliding_error.tsx @@ -38,6 +38,8 @@ export const Error: React.StatelessComponent = props => ( ); +Error.displayName = 'Error'; + export interface SlidingErrorProps extends ErrorProps { animationState: SlideAnimationState; } @@ -94,3 +96,5 @@ export const SlidingError: React.StatelessComponent = props = ); }; + +SlidingError.displayName = 'SlidingError'; diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx index 7f9037049..33a483662 100644 --- a/packages/instant/src/components/sliding_panel.tsx +++ b/packages/instant/src/components/sliding_panel.tsx @@ -26,6 +26,8 @@ export const Panel: React.StatelessComponent = ({ children, onClose ); +Panel.displayName = 'Panel'; + export interface SlidingPanelProps extends PanelProps { animationState: SlideAnimationState; } @@ -65,3 +67,5 @@ export const SlidingPanel: React.StatelessComponent = props = ); }; + +SlidingPanel.displayName = 'SlidingPanel'; diff --git a/packages/instant/src/components/standard_panel_content.tsx b/packages/instant/src/components/standard_panel_content.tsx index 79b7bff24..f2987df82 100644 --- a/packages/instant/src/components/standard_panel_content.tsx +++ b/packages/instant/src/components/standard_panel_content.tsx @@ -71,3 +71,5 @@ export const StandardPanelContent: React.StatelessComponent{action} ); + +StandardPanelContent.displayName = 'StandardPanelContent'; diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index 590d9dedb..93ad06aee 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -138,3 +138,5 @@ export const DropdownItem: React.StatelessComponent = ({ text ); + +DropdownItem.displayName = 'DropdownItem'; diff --git a/packages/instant/src/components/wallet_prompt.tsx b/packages/instant/src/components/wallet_prompt.tsx index c07cfe7b5..10433767f 100644 --- a/packages/instant/src/components/wallet_prompt.tsx +++ b/packages/instant/src/components/wallet_prompt.tsx @@ -45,3 +45,5 @@ WalletPrompt.defaultProps = { primaryColor: ColorOption.darkOrange, secondaryColor: ColorOption.lightOrange, }; + +WalletPrompt.displayName = 'WalletPrompt'; diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx index 2267b4dbf..e9cb48e61 100644 --- a/packages/instant/src/components/zero_ex_instant.tsx +++ b/packages/instant/src/components/zero_ex_instant.tsx @@ -17,3 +17,5 @@ export const ZeroExInstant: React.StatelessComponent = props
); }; + +ZeroExInstant.displayName = 'ZeroExInstant'; diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index 96e560691..38a716091 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -49,3 +49,5 @@ export const ZeroExInstantOverlay: React.StatelessComponent ); }; + +ZeroExInstantOverlay.displayName = 'ZeroExInstantOverlay'; diff --git a/packages/instant/src/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx index 0d4349124..6da4558ef 100644 --- a/packages/instant/src/containers/latest_error.tsx +++ b/packages/instant/src/containers/latest_error.tsx @@ -14,7 +14,7 @@ import { zIndex } from '../style/z_index'; import { Asset, DisplayStatus, Omit, SlideAnimationState } from '../types'; import { errorFlasher } from '../util/error_flasher'; -export interface LatestErrorComponentProps { +interface LatestErrorComponentProps { asset?: Asset; latestErrorMessage?: string; animationState: SlideAnimationState; @@ -22,7 +22,7 @@ export interface LatestErrorComponentProps { onOverlayClick: () => void; } -export const LatestErrorComponent: React.StatelessComponent = props => { +const LatestErrorComponent: React.StatelessComponent = props => { if (!props.latestErrorMessage) { // Render a hidden SlidingError such that instant does not move when a real error is rendered. return ( -- cgit v1.2.3 From 4252a760f072da907d1b542e3bb9917db3f22b07 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 2 Jan 2019 16:55:29 +0100 Subject: feat: dont re-render the token selector on every input change --- .../src/components/erc20_token_selector.tsx | 39 +++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index fc7c21d47..b5f01e349 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -26,7 +26,7 @@ export class ERC20TokenSelector extends React.PureComponent @@ -42,12 +42,11 @@ export class ERC20TokenSelector extends React.PureComponent - {_.map(tokens, token => { - if (!this._isTokenQueryMatch(token)) { - return null; - } - return ; - })} + ); @@ -59,8 +58,32 @@ export class ERC20TokenSelector extends React.PureComponent { + this.props.onTokenSelect(token); + }; +} + +interface TokenRowFilterProps { + tokens: ERC20Asset[]; + onClick: (token: ERC20Asset) => void; + searchQuery: string; +} + +class TokenRowFilter extends React.Component { + public render(): React.ReactNode { + return _.map(this.props.tokens, token => { + if (!this._isTokenQueryMatch(token)) { + return null; + } + return ; + }); + } + public shouldComponentUpdate(nextProps: TokenRowFilterProps): boolean { + const arePropsDeeplyEqual = _.isEqual(nextProps, this.props); + return !arePropsDeeplyEqual; + } private readonly _isTokenQueryMatch = (token: ERC20Asset): boolean => { - const { searchQuery } = this.state; + const { searchQuery } = this.props; const searchQueryLowerCase = searchQuery.toLowerCase().trim(); if (searchQueryLowerCase === '') { return true; -- cgit v1.2.3 From 1ceb3c96645fd3682c59459fdce996cdf5f216cf Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 2 Jan 2019 19:07:02 +0100 Subject: feat: unmount the token selector when its not displaying --- .../src/components/animations/slide_animation.tsx | 8 ++- .../src/components/erc20_token_selector.tsx | 34 +++++----- packages/instant/src/components/sliding_panel.tsx | 74 +++++++++++----------- .../src/components/zero_ex_instant_container.tsx | 13 +++- 4 files changed, 75 insertions(+), 54 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/animations/slide_animation.tsx b/packages/instant/src/components/animations/slide_animation.tsx index dc42e168d..6ac47e9a6 100644 --- a/packages/instant/src/components/animations/slide_animation.tsx +++ b/packages/instant/src/components/animations/slide_animation.tsx @@ -11,6 +11,7 @@ export interface SlideAnimationProps { slideOutSettings: OptionallyScreenSpecific; zIndex?: OptionallyScreenSpecific; height?: string; + onAnimationEnd?: () => void; } export const SlideAnimation: React.StatelessComponent = props => { @@ -19,7 +20,12 @@ export const SlideAnimation: React.StatelessComponent = pro } const positionSettings = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings; return ( - + {props.children} ); diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index b5f01e349..a26fb5cf5 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -154,21 +154,23 @@ const getTokenIcon = (symbol: string): React.StatelessComponent | undefined => { } }; -const TokenSelectorRowIcon: React.StatelessComponent = props => { - const { token } = props; - const iconUrlIfExists = token.metaData.iconUrl; +class TokenSelectorRowIcon extends React.PureComponent { + public render(): React.ReactNode { + const { token } = this.props; + const iconUrlIfExists = token.metaData.iconUrl; - const TokenIcon = getTokenIcon(token.metaData.symbol); - const displaySymbol = assetUtils.bestNameForAsset(token); - if (!_.isUndefined(iconUrlIfExists)) { - return ; - } else if (!_.isUndefined(TokenIcon)) { - return ; - } else { - return ( - - {displaySymbol} - - ); + const TokenIcon = getTokenIcon(token.metaData.symbol); + const displaySymbol = assetUtils.bestNameForAsset(token); + if (!_.isUndefined(iconUrlIfExists)) { + return ; + } else if (!_.isUndefined(TokenIcon)) { + return ; + } else { + return ( + + {displaySymbol} + + ); + } } -}; +} diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx index 33a483662..9b09a0d80 100644 --- a/packages/instant/src/components/sliding_panel.tsx +++ b/packages/instant/src/components/sliding_panel.tsx @@ -30,42 +30,44 @@ Panel.displayName = 'Panel'; export interface SlidingPanelProps extends PanelProps { animationState: SlideAnimationState; + onAnimationEnd?: () => void; } -export const SlidingPanel: React.StatelessComponent = props => { - if (props.animationState === 'none') { - return null; +export class SlidingPanel extends React.PureComponent { + public render(): React.ReactNode { + if (this.props.animationState === 'none') { + return null; + } + const { animationState, onAnimationEnd, ...rest } = this.props; + const slideAmount = '100%'; + const slideUpSettings: PositionAnimationSettings = { + duration: '0.3s', + timingFunction: 'ease-in-out', + top: { + from: slideAmount, + to: '0px', + }, + position: 'absolute', + }; + const slideDownSettings: PositionAnimationSettings = { + duration: '0.3s', + timingFunction: 'ease-out', + top: { + from: '0px', + to: slideAmount, + }, + position: 'absolute', + }; + return ( + + + + ); } - const { animationState, ...rest } = props; - const slideAmount = '100%'; - const slideUpSettings: PositionAnimationSettings = { - duration: '0.3s', - timingFunction: 'ease-in-out', - top: { - from: slideAmount, - to: '0px', - }, - position: 'absolute', - }; - const slideDownSettings: PositionAnimationSettings = { - duration: '0.3s', - timingFunction: 'ease-out', - top: { - from: '0px', - to: slideAmount, - }, - position: 'absolute', - }; - return ( - - - - ); -}; - -SlidingPanel.displayName = 'SlidingPanel'; +} diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 63497e639..e8c64d5d1 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -24,7 +24,10 @@ export interface ZeroExInstantContainerState { tokenSelectionPanelAnimationState: SlideAnimationState; } -export class ZeroExInstantContainer extends React.PureComponent { +export class ZeroExInstantContainer extends React.PureComponent< + ZeroExInstantContainerProps, + ZeroExInstantContainerState +> { public state = { tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; @@ -60,6 +63,7 @@ export class ZeroExInstantContainer extends React.PureComponent @@ -98,4 +102,11 @@ export class ZeroExInstantContainer extends React.PureComponent { + if (this.state.tokenSelectionPanelAnimationState === 'slidOut') { + // When the slidOut animation completes, don't keep the panel mounted. + // Performance optimization + this.setState({ tokenSelectionPanelAnimationState: 'none' }); + } + }; } -- cgit v1.2.3 From c62d862967a3c90e903e016fae2456afb2f9d8f9 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Wed, 2 Jan 2019 10:58:41 -0800 Subject: fix(instant): Dropdown hover should be 10% of primary color --- packages/instant/src/components/ui/container.tsx | 2 ++ packages/instant/src/components/ui/dropdown.tsx | 39 +++++++++++++----------- 2 files changed, 24 insertions(+), 17 deletions(-) (limited to 'packages/instant/src') diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 636eb8fc9..58d7d5871 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -36,6 +36,7 @@ export interface ContainerProps { cursor?: string; overflow?: string; darkenOnHover?: boolean; + rawHoverColor?: string; boxShadowOnHover?: boolean; flexGrow?: string | number; } @@ -87,6 +88,7 @@ export const Container = background-color: ${props => getBackgroundColor(props.theme, props.backgroundColor, props.rawBackgroundColor)}; border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')}; &:hover { + ${props => (props.rawHoverColor ? `background-color: ${props.rawHoverColor}` : '')} ${props => props.darkenOnHover ? `background-color: ${ diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index 02e87d639..9b5824c5e 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -1,7 +1,8 @@ import * as _ from 'lodash'; +import { transparentize } from 'polished'; import * as React from 'react'; -import { ColorOption, completelyTransparent } from '../../style/theme'; +import { ColorOption, completelyTransparent, ThemeConsumer } from '../../style/theme'; import { zIndex } from '../../style/z_index'; import { Container } from './container'; @@ -121,20 +122,24 @@ export interface DropdownItemProps extends DropdownItemConfig { } export const DropdownItem: React.StatelessComponent = ({ text, onClick, isLast }) => ( - - - {text} - - + + {theme => ( + + + {text} + + + )} + ); -- cgit v1.2.3