Merge branch 'development' into feature/instant/dropdown-analytics

This commit is contained in:
Steve Klebanoff
2018-11-27 10:38:26 -08:00
5 changed files with 67 additions and 11 deletions

View File

@@ -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<ERC20TokenSelectorProps>
this.setState({
searchQuery,
});
analytics.trackTokenSelectorSearched(searchQuery);
};
private readonly _isTokenQueryMatch = (token: ERC20Asset): boolean => {
const { searchQuery } = this.state;

View File

@@ -11,21 +11,20 @@ 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';
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<ZeroExInstantContainerProps, ZeroExInstantContainerState> {
public state = {
tokenSelectionPanelAnimationState: 'none' as SlideAnimationState,
};
@@ -60,9 +59,9 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon
</Flex>
<SlidingPanel
animationState={this.state.tokenSelectionPanelAnimationState}
onClose={this._handlePanelClose}
onClose={this._handlePanelCloseClickedX}
>
<AvailableERC20TokenSelector onTokenSelect={this._handlePanelClose} />
<AvailableERC20TokenSelector onTokenSelect={this._handlePanelCloseAfterChose} />
</SlidingPanel>
<CurrentStandardSlidingPanel />
</Container>
@@ -82,11 +81,19 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon
);
}
private readonly _handleSymbolClick = (): void => {
analytics.trackTokenSelectorOpened();
this.setState({
tokenSelectionPanelAnimationState: 'slidIn',
});
};
private readonly _handlePanelClose = (): void => {
private readonly _handlePanelCloseClickedX = (): void => {
this._handlePanelClose(TokenSelectorClosedVia.ClickedX);
};
private readonly _handlePanelCloseAfterChose = (): void => {
this._handlePanelClose(TokenSelectorClosedVia.TokenChose);
};
private readonly _handlePanelClose = (closedVia: TokenSelectorClosedVia): void => {
analytics.trackTokenSelectorClosed(closedVia);
this.setState({
tokenSelectionPanelAnimationState: 'slidOut',
});

View File

@@ -131,6 +131,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
this.props.orderSource,
state.providerState,
window,
state.selectedAsset,
this.props.affiliateInfo,
),
);

View File

@@ -53,6 +53,30 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction
).toString();
analytics.addUserProperties({ ethBalanceInUnitAmount });
}
break;
case ActionTypes.UPDATE_SELECTED_ASSET:
const selectedAsset = curState.selectedAsset;
if (selectedAsset) {
const assetName = selectedAsset.metaData.name;
const assetData = selectedAsset.assetData;
analytics.trackTokenSelectorChose({
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;
}
return nextAction;

View File

@@ -1,4 +1,4 @@
import { AffiliateInfo, Network, OrderSource, ProviderState } from '../types';
import { AffiliateInfo, Asset, Network, OrderSource, ProviderState } from '../types';
import { EventProperties, heapUtil } from './heap';
@@ -23,7 +23,12 @@ enum EventNames {
PAYMENT_METHOD_DROPDOWN_OPENED = 'Payment Method - Dropdown Opened',
PAYMENT_METHOD_OPENED_ETHERSCAN = 'Payment Method - Opened Etherscan',
PAYMENT_METHOD_COPIED_ADDRESS = 'Payment Method - Copied Address',
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(() => {
heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventProperties));
@@ -55,8 +60,14 @@ export interface AnalyticsEventOptions {
orderSource?: string;
affiliateAddress?: string;
affiliateFeePercent?: number;
numberAvailableAssets?: number;
selectedAssetName?: string;
selectedAssetData?: string;
}
export enum TokenSelectorClosedVia {
ClickedX = 'Clicked X',
TokenChose = 'Token Chose',
}
export const analytics = {
addUserProperties: (properties: AnalyticsUserOptions): void => {
evaluateIfEnabled(() => {
@@ -73,12 +84,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,
@@ -88,7 +100,10 @@ export const analytics = {
orderSource: orderSourceName,
affiliateAddress,
affiliateFeePercent,
selectedAssetName: selectedAsset ? selectedAsset.metaData.name : 'none',
selectedAssetData: selectedAsset ? selectedAsset.assetData : 'none',
};
return eventOptions;
},
trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED),
trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED),
@@ -100,4 +115,11 @@ export const analytics = {
trackPaymentMethodDropdownOpened: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_DROPDOWN_OPENED),
trackPaymentMethodOpenedEtherscan: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_OPENED_ETHERSCAN),
trackPaymentMethodCopiedAddress: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_COPIED_ADDRESS),
trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED),
trackTokenSelectorClosed: (closedVia: TokenSelectorClosedVia) =>
trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CLOSED)({ closedVia }),
trackTokenSelectorChose: (payload: { assetName: string; assetData: string }) =>
trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload),
trackTokenSelectorSearched: (searchText: string) =>
trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }),
};