From 83f4fa92a5619afc129dd1098877f4c889dc27c4 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff 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 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 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 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 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 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 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 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 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