From 351e0e6f5f2add25c4d779356a8cfd4aefb305cb Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 20 Nov 2018 22:34:57 -0800 Subject: feat(instant): implement account related events --- .../containers/connected_account_payment_method.ts | 8 +++-- packages/instant/src/redux/analytics_middleware.ts | 34 ++++++++++++---------- packages/instant/src/redux/async_data.ts | 2 ++ packages/instant/src/util/analytics.ts | 13 +++++++-- 4 files changed, 37 insertions(+), 20 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/containers/connected_account_payment_method.ts b/packages/instant/src/containers/connected_account_payment_method.ts index eacbadfca..cdeb49a25 100644 --- a/packages/instant/src/containers/connected_account_payment_method.ts +++ b/packages/instant/src/containers/connected_account_payment_method.ts @@ -12,6 +12,7 @@ import { Action, actions } from '../redux/actions'; import { asyncData } from '../redux/async_data'; import { State } from '../redux/reducer'; import { Network, Omit, OperatingSystem, ProviderState, StandardSlidingPanelContent } from '../types'; +import { analytics } from '../util/analytics'; import { envUtil } from '../util/env'; export interface ConnectedAccountPaymentMethodProps {} @@ -40,8 +41,11 @@ const mapDispatchToProps = ( ownProps: ConnectedAccountPaymentMethodProps, ): ConnectedDispatch => ({ openInstallWalletPanel: () => dispatch(actions.openStandardSlidingPanel(StandardSlidingPanelContent.InstallWallet)), - unlockWalletAndDispatchToStore: async (providerState: ProviderState) => - asyncData.fetchAccountInfoAndDispatchToStore(providerState, dispatch, true), + unlockWalletAndDispatchToStore: (providerState: ProviderState) => { + analytics.trackAccountUnlockRequested(); + // tslint:disable-next-line:no-floating-promises + asyncData.fetchAccountInfoAndDispatchToStore(providerState, dispatch, true); + }, }); const mergeProps = ( diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index f971dbd33..893844f5d 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -10,20 +10,6 @@ import { Action, ActionTypes } from './actions'; import { State } from './reducer'; -const shouldTriggerWalletReady = (prevAccount: Account, curAccount: Account): boolean => { - const didJustTurnReady = curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready; - if (didJustTurnReady) { - return true; - } - - if (curAccount.state === AccountState.Ready && prevAccount.state === AccountState.Ready) { - // Account was ready, and is now ready again, but address has changed - return curAccount.address !== prevAccount.address; - } - - return false; -}; - export const analyticsMiddleware: Middleware = store => next => middlewareAction => { const prevState = store.getState() as State; const prevAccount = prevState.providerState.account; @@ -35,10 +21,26 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction switch (nextAction.type) { case ActionTypes.SET_ACCOUNT_STATE_READY: - if (curAccount.state === AccountState.Ready && shouldTriggerWalletReady(prevAccount, curAccount)) { + if (prevAccount.state !== AccountState.Ready && curAccount.state === AccountState.Ready) { + // if we are moving from account not ready to account ready, update the current address and track `Account - Ready` const ethAddress = curAccount.address; analytics.addUserProperties({ ethAddress }); - analytics.trackWalletReady(); + analytics.trackAccountReady(ethAddress); + } else if (prevAccount.state === AccountState.Ready && curAccount.state === AccountState.Ready) { + if (prevAccount.address !== curAccount.address) { + // if our account state was already ready and our address has changed, update the current address and track `Account - Address Changed` + const ethAddress = curAccount.address; + analytics.addUserProperties({ ethAddress }); + analytics.trackAccountAddressChanged(ethAddress); + } + } + break; + case ActionTypes.SET_ACCOUNT_STATE_LOCKED: + if (prevAccount.state !== AccountState.Locked && curAccount.state === AccountState.Locked) { + // if we are moving from account not locked to account locked, update the current address to undefined and track `Account - Locked` + const ethAddress = undefined; + analytics.addUserProperties({ ethAddress }); + analytics.trackAccountLocked(); } break; case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 5d30388b8..6feb760e7 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -5,6 +5,7 @@ import { Dispatch } from 'redux'; import { BIG_NUMBER_ZERO } from '../constants'; import { AccountState, ERC20Asset, OrderProcessState, ProviderState } from '../types'; +import { analytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { buyQuoteUpdater } from '../util/buy_quote_updater'; import { coinbaseApi } from '../util/coinbase_api'; @@ -58,6 +59,7 @@ export const asyncData = { ? await (provider as any).enable() : await web3Wrapper.getAvailableAddressesAsync(); } catch (e) { + analytics.trackAccountUnlockDenied(); dispatch(actions.setAccountStateLocked()); return; } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 2ffaac1dd..d36bf8fc3 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -15,7 +15,11 @@ export const evaluateIfEnabled = (fnCall: () => void) => { enum EventNames { INSTANT_OPENED = 'Instant - Opened', - WALLET_READY = 'Wallet - Ready', + ACCOUNT_LOCKED = 'Account - Locked', + ACCOUNT_READY = 'Account - Ready', + ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested', + ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', + ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', } const track = (eventName: EventNames, eventData: ObjectMap = {}): void => { evaluateIfEnabled(() => { @@ -59,6 +63,11 @@ export const analytics = { heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); }); }, - trackWalletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), + trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED), + trackAccountReady: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ address }), + trackAccountUnlockRequested: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_REQUESTED), + trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), + trackAccountAddressChanged: (address: string) => + trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), }; -- cgit v1.2.3 From 31d1b4ba670d25c4cd4ed93d32d12718b4804e5d Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 21 Nov 2018 12:30:52 -0800 Subject: chore(instant): refactor account tracking logic in middleware to be more readable --- packages/instant/src/redux/analytics_middleware.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 893844f5d..889cc875e 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -21,17 +21,17 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction switch (nextAction.type) { case ActionTypes.SET_ACCOUNT_STATE_READY: - if (prevAccount.state !== AccountState.Ready && curAccount.state === AccountState.Ready) { - // if we are moving from account not ready to account ready, update the current address and track `Account - Ready` + if (curAccount.state === AccountState.Ready) { + const didJustTurnReady = prevAccount.state !== AccountState.Ready; + const didJustUpdateAddress = + prevAccount.state === AccountState.Ready && prevAccount.address !== curAccount.address; const ethAddress = curAccount.address; - analytics.addUserProperties({ ethAddress }); - analytics.trackAccountReady(ethAddress); - } else if (prevAccount.state === AccountState.Ready && curAccount.state === AccountState.Ready) { - if (prevAccount.address !== curAccount.address) { - // if our account state was already ready and our address has changed, update the current address and track `Account - Address Changed` - const ethAddress = curAccount.address; + if (didJustTurnReady) { + analytics.trackAccountReady(ethAddress); analytics.addUserProperties({ ethAddress }); + } else if (didJustUpdateAddress) { analytics.trackAccountAddressChanged(ethAddress); + analytics.addUserProperties({ ethAddress }); } } break; -- cgit v1.2.3 From 6604e2db20d6263e05b00cf5d36b56788e42d9c2 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 21 Nov 2018 12:44:28 -0800 Subject: chore(instant): refactor usage of event properties in heap --- packages/instant/src/redux/analytics_middleware.ts | 12 ++++---- packages/instant/src/util/analytics.ts | 32 ++++++++++++---------- packages/instant/src/util/heap.ts | 4 ++- 3 files changed, 26 insertions(+), 22 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 889cc875e..931902187 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -27,19 +27,17 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction prevAccount.state === AccountState.Ready && prevAccount.address !== curAccount.address; const ethAddress = curAccount.address; if (didJustTurnReady) { - analytics.trackAccountReady(ethAddress); - analytics.addUserProperties({ ethAddress }); + analytics.trackAccountReady({ address: ethAddress }); + analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); } else if (didJustUpdateAddress) { - analytics.trackAccountAddressChanged(ethAddress); - analytics.addUserProperties({ ethAddress }); + analytics.trackAccountAddressChanged({ address: ethAddress }); + analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); } } break; case ActionTypes.SET_ACCOUNT_STATE_LOCKED: if (prevAccount.state !== AccountState.Locked && curAccount.state === AccountState.Locked) { - // if we are moving from account not locked to account locked, update the current address to undefined and track `Account - Locked` - const ethAddress = undefined; - analytics.addUserProperties({ ethAddress }); + // if we are moving from account not locked to account locked, track `Account - Locked` analytics.trackAccountLocked(); } break; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index d36bf8fc3..31233fe7a 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,6 +1,4 @@ -import { ObjectMap } from '@0x/types'; - -import { heapUtil } from './heap'; +import { EventProperties, heapUtil } from './heap'; let isDisabled = false; export const disableAnalytics = (shouldDisableAnalytics: boolean) => { @@ -21,9 +19,9 @@ enum EventNames { ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', } -const track = (eventName: EventNames, eventData: ObjectMap = {}): void => { +const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => { evaluateIfEnabled(() => { - heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventData)); + heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventProperties)); }); }; function trackingEventFnWithoutPayload(eventName: EventNames): () => void { @@ -32,16 +30,14 @@ function trackingEventFnWithoutPayload(eventName: EventNames): () => void { }; } // tslint:disable-next-line:no-unused-variable -function trackingEventFnWithPayload>( - eventName: EventNames, -): (eventDataProperties: T) => void { - return (eventDataProperties: T) => { - track(eventName, eventDataProperties); +function trackingEventFnWithPayload(eventName: EventNames): (eventProperties: EventProperties) => void { + return (eventProperties: EventProperties) => { + track(eventName, eventProperties); }; } export interface AnalyticsUserOptions { - ethAddress?: string; + lastKnownEthAddress?: string; ethBalanceInUnitAmount?: string; } export interface AnalyticsEventOptions { @@ -52,6 +48,13 @@ export interface AnalyticsEventOptions { gitSha?: string; npmVersion?: string; } +export interface AccountReadyEventProperties { + address: string; +} +export interface AccountAddressChangedEventProperties { + address: string; +} + export const analytics = { addUserProperties: (properties: AnalyticsUserOptions): void => { evaluateIfEnabled(() => { @@ -65,9 +68,10 @@ export const analytics = { }, trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED), - trackAccountReady: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ address }), + trackAccountReady: (eventProperties: AccountReadyEventProperties) => + trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ ...eventProperties }), trackAccountUnlockRequested: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_REQUESTED), trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), - trackAccountAddressChanged: (address: string) => - trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), + trackAccountAddressChanged: (eventProperties: AccountAddressChangedEventProperties) => + trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ ...eventProperties }), }; diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 78ec3b3cc..7c53c9918 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -6,11 +6,13 @@ import { HEAP_ANALYTICS_ID } from '../constants'; import { AnalyticsEventOptions, AnalyticsUserOptions } from './analytics'; +export type EventProperties = ObjectMap; + export interface HeapAnalytics { loaded: boolean; appid: string; identify(id: string, idType: string): void; - track(eventName: string, eventProperties?: ObjectMap): void; + track(eventName: string, eventProperties?: EventProperties): void; resetIdentity(): void; addUserProperties(properties: AnalyticsUserOptions): void; addEventProperties(properties: AnalyticsEventOptions): void; -- cgit v1.2.3 From 804de89796de047fe43dbb736b5e8b82bb30ee3a Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 21 Nov 2018 13:40:23 -0800 Subject: chore(instant): revert usage of event properties --- packages/instant/src/redux/analytics_middleware.ts | 4 ++-- packages/instant/src/util/analytics.ts | 13 +++---------- 2 files changed, 5 insertions(+), 12 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 931902187..299c2560e 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -27,10 +27,10 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction prevAccount.state === AccountState.Ready && prevAccount.address !== curAccount.address; const ethAddress = curAccount.address; if (didJustTurnReady) { - analytics.trackAccountReady({ address: ethAddress }); + analytics.trackAccountReady(ethAddress); analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); } else if (didJustUpdateAddress) { - analytics.trackAccountAddressChanged({ address: ethAddress }); + analytics.trackAccountAddressChanged(ethAddress); analytics.addUserProperties({ lastKnownEthAddress: ethAddress }); } } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 31233fe7a..e389e1530 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -48,12 +48,6 @@ export interface AnalyticsEventOptions { gitSha?: string; npmVersion?: string; } -export interface AccountReadyEventProperties { - address: string; -} -export interface AccountAddressChangedEventProperties { - address: string; -} export const analytics = { addUserProperties: (properties: AnalyticsUserOptions): void => { @@ -68,10 +62,9 @@ export const analytics = { }, trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED), - trackAccountReady: (eventProperties: AccountReadyEventProperties) => - trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ ...eventProperties }), + trackAccountReady: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ address }), trackAccountUnlockRequested: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_REQUESTED), trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), - trackAccountAddressChanged: (eventProperties: AccountAddressChangedEventProperties) => - trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ ...eventProperties }), + trackAccountAddressChanged: (address: string) => + trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), }; -- cgit v1.2.3