diff options
author | Steve Klebanoff <steve.klebanoff@gmail.com> | 2018-12-01 06:09:23 +0800 |
---|---|---|
committer | Steve Klebanoff <steve.klebanoff@gmail.com> | 2018-12-01 06:09:23 +0800 |
commit | ef041d1603ed9c707c032c5620f9829eeaf0e361 (patch) | |
tree | e67491b0c66fc50dcf8dfdfa7e57068696f219fc /packages/instant/src/components | |
parent | 271adcdb7e3ecb9f88f05f36ffb71d2147bac292 (diff) | |
parent | 34b2f4736e30b50f94a3110c313131b56e35bc02 (diff) | |
download | dexon-0x-contracts-ef041d1603ed9c707c032c5620f9829eeaf0e361.tar.gz dexon-0x-contracts-ef041d1603ed9c707c032c5620f9829eeaf0e361.tar.zst dexon-0x-contracts-ef041d1603ed9c707c032c5620f9829eeaf0e361.zip |
Merge branch 'feature/instant/prod-env-switches-cdn' into feature/instant/rollbar-env
Diffstat (limited to 'packages/instant/src/components')
18 files changed, 152 insertions, 45 deletions
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 8b6121e43..eeb42d6fc 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<BuyButtonProps> { // 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(buyQuote); this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH); return; } @@ -66,6 +68,7 @@ export class BuyButton extends React.Component<BuyButtonProps> { const gasInfo = await gasPriceEstimator.getGasInfoAsync(); const feeRecipient = oc(affiliateInfo).feeRecipient(); try { + analytics.trackBuyStarted(buyQuote); txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { feeRecipient, takerAddress: accountAddress, @@ -74,9 +77,11 @@ export class BuyButton extends React.Component<BuyButtonProps> { } catch (e) { if (e instanceof Error) { if (e.message === AssetBuyerError.SignatureRequestDenied) { + analytics.trackBuySignatureDenied(buyQuote); this.props.onSignatureDenied(buyQuote); return; } else if (e.message === AssetBuyerError.TransactionValueTooLow) { + analytics.trackBuySimulationFailed(buyQuote); this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow); return; } @@ -87,14 +92,17 @@ export class BuyButton extends React.Component<BuyButtonProps> { 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) { 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, startTimeUnix, expectedEndTimeUnix); this.props.onBuySuccess(buyQuote, txHash); }; } diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index b825255c4..ff900842a 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -64,6 +64,9 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput maxFontSizePx={this.props.startingFontSizePx} onAmountChange={this._handleChange} onFontSizeChange={this._handleFontSizeChange} + hasAutofocus={true} + /* We send in a key of asset data to force a rerender of this component when the user selects a new asset. We do this so the autofocus attribute will bring focus onto this input */ + key={asset.assetData} /> </Container> <Container diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 1b1921acb..f7d5a4fe4 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'; @@ -18,12 +19,12 @@ export interface ERC20TokenSelectorProps { } export interface ERC20TokenSelectorState { - searchQuery?: string; + searchQuery: string; } export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps> { public state: ERC20TokenSelectorState = { - searchQuery: undefined, + searchQuery: '', }; public render(): React.ReactNode { const { tokens, onTokenSelect } = this.props; @@ -57,13 +58,14 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps> this.setState({ searchQuery, }); + analytics.trackTokenSelectorSearched(searchQuery); }; 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); 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<InstallWalletPane default: break; } + const onActionClick = () => { + analytics.trackInstallWalletModalClickedGet(); + util.createOpenUrlInNewWindow(actionUrl)(); + }; return { image: <MetaMaskLogo width={85} height={80} />, title: 'Install MetaMask', @@ -52,10 +58,11 @@ export class InstallWalletPanelContent extends React.Component<InstallWalletPane moreInfoSettings: { href: META_MASK_SITE_URL, text: 'What is MetaMask?', + onClick: analytics.trackInstallWalletModalClickedExplanation, }, action: ( <Button - href={actionUrl} + onClick={onActionClick} width="100%" fontColor={ColorOption.white} backgroundColor={ColorOption.darkOrange} diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 002695269..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<InstantHeadingProps, {}> { private readonly _renderEthAmount = (): React.ReactNode => { return ( - <Text fontSize="16px" fontColor={ColorOption.white} fontWeight={500}> + <Text + fontSize="16px" + textAlign="right" + width="100%" + fontColor={ColorOption.white} + fontWeight={500} + noWrap={true} + > {format.ethBaseUnitAmount( this.props.totalEthBaseUnitAmount, 4, @@ -119,7 +126,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { private readonly _renderDollarAmount = (): React.ReactNode => { return ( - <Text fontSize="16px" fontColor={ColorOption.white}> + <Text fontSize="16px" textAlign="right" width="100%" fontColor={ColorOption.white} noWrap={true}> {format.ethBaseUnitAmountInUsd( this.props.totalEthBaseUnitAmount, this.props.ethUsdPrice, 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<PaymentMethodProps> { public render(): React.ReactNode { return ( - <Container padding="20px" width="100%"> + <Container padding="20px" width="100%" height="133px"> <Container marginBottom="12px"> <Flex justify="space-between"> <Text @@ -83,8 +83,7 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> { const colors = { primaryColor, secondaryColor }; switch (account.state) { case AccountState.Loading: - // Just take up the same amount of space as the other states. - return <Container height="52px" />; + return null; case AccountState.Locked: return ( <WalletPrompt diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx index b330dbcd6..872ac0831 100644 --- a/packages/instant/src/components/payment_method_dropdown.tsx +++ b/packages/instant/src/components/payment_method_dropdown.tsx @@ -1,8 +1,9 @@ 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'; +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<PaymentMethodDropdown const { accountAddress, accountEthBalanceInWei } = this.props; const value = format.ethAddress(accountAddress); const label = format.ethBaseUnitAmount(accountEthBalanceInWei, 4, '') as string; - return <Dropdown value={value} label={label} items={this._getDropdownItemConfigs()} />; + return ( + <Dropdown + value={value} + label={label} + items={this._getDropdownItemConfigs()} + onOpen={analytics.trackPaymentMethodDropdownOpened} + /> + ); } private readonly _getDropdownItemConfigs = (): DropdownItemConfig[] => { if (envUtil.isMobileOperatingSystem()) { @@ -37,11 +45,15 @@ export class PaymentMethodDropdown extends React.Component<PaymentMethodDropdown return [viewOnEtherscan, copyAddressToClipboard]; }; private readonly _handleEtherscanClick = (): void => { + 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/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 5dc719293..0861bbe05 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -18,6 +18,7 @@ export interface ScalingAmountInputProps { value?: BigNumber; onAmountChange: (value?: BigNumber) => void; onFontSizeChange: (fontSizePx: number) => void; + hasAutofocus: boolean; } interface ScalingAmountInputState { stringValue: string; @@ -29,6 +30,7 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps, onAmountChange: util.boundNoop, onFontSizeChange: util.boundNoop, isDisabled: false, + hasAutofocus: false, }; public constructor(props: ScalingAmountInputProps) { super(props); @@ -64,6 +66,7 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps, placeholder="0.00" emptyInputWidthCh={3.5} isDisabled={this.props.isDisabled} + hasAutofocus={this.props.hasAutofocus} /> ); } diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index e1599a316..791692257 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; + hasAutofocus: boolean; } export interface ScalingInputState { @@ -51,6 +52,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu maxLength: 7, scalingSettings: defaultScalingSettings, isDisabled: false, + hasAutofocus: false, }; public state: ScalingInputState = { inputWidthPxAtPhaseChange: undefined, @@ -96,6 +98,12 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu inputWidthPx: this._getInputWidthInPx(), }; } + public componentDidMount(): void { + // Trigger an initial notification of the calculated fontSize. + const currentPhase = ScalingInput.getPhaseFromProps(this.props); + const currentFontSize = ScalingInput.calculateFontSizeFromProps(this.props, currentPhase); + this.props.onFontSizeChange(currentFontSize); + } public componentDidUpdate( prevProps: ScalingInputProps, prevState: ScalingInputState, @@ -123,7 +131,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu } } public render(): React.ReactNode { - const { isDisabled, fontColor, onChange, placeholder, value, maxLength } = this.props; + const { hasAutofocus, isDisabled, fontColor, onChange, placeholder, value, maxLength } = this.props; const phase = ScalingInput.getPhaseFromProps(this.props); return ( <Input @@ -136,6 +144,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu width={this._calculateWidth(phase)} maxLength={maxLength} disabled={isDisabled} + autoFocus={hasAutofocus} /> ); } diff --git a/packages/instant/src/components/standard_panel_content.tsx b/packages/instant/src/components/standard_panel_content.tsx index 582b3318e..79b7bff24 100644 --- a/packages/instant/src/components/standard_panel_content.tsx +++ b/packages/instant/src/components/standard_panel_content.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { ColorOption } from '../style/theme'; +import { util } from '../util/util'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; @@ -9,6 +10,7 @@ import { Text } from './ui/text'; export interface MoreInfoSettings { text: string; href: string; + onClick?: () => 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<StandardPanelContentProps> = ({ image, title, @@ -50,7 +61,7 @@ export const StandardPanelContent: React.StatelessComponent<StandardPanelContent fontSize="13px" textDecorationLine="underline" fontColor={ColorOption.lightGrey} - href={moreInfoSettings.href} + onClick={onMoreInfoClick(moreInfoSettings.href, moreInfoSettings.onClick)} > {moreInfoSettings.text} </Text> diff --git a/packages/instant/src/components/standard_sliding_panel.tsx b/packages/instant/src/components/standard_sliding_panel.tsx index f587ff79a..9f517d273 100644 --- a/packages/instant/src/components/standard_sliding_panel.tsx +++ b/packages/instant/src/components/standard_sliding_panel.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { SlideAnimationState, StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types'; +import { StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types'; import { InstallWalletPanelContent } from './install_wallet_panel_content'; import { SlidingPanel } from './sliding_panel'; diff --git a/packages/instant/src/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<ProgressBarProps & React.ClassAttributes<{}>> = React.forwardRef( (props, ref) => ( - <Container width="100%" backgroundColor={ColorOption.lightGrey} borderRadius="6px"> - <Progress {...props} ref={ref as any} /> - </Container> + <ThemeConsumer> + {theme => ( + <Container + width="100%" + borderRadius="6px" + rawBackgroundColor={transparentize(0.5, theme[ColorOption.primaryColor])} + > + <Progress {...props} ref={ref as any} /> + </Container> + )} + </ThemeConsumer> ), ); diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 4dafe1386..e7d909d92 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -27,7 +27,9 @@ export interface ContainerProps { borderBottom?: string; className?: string; backgroundColor?: ColorOption; + rawBackgroundColor?: string; hasBoxShadow?: boolean; + isHidden?: boolean; zIndex?: number; whiteSpace?: string; opacity?: number; @@ -38,6 +40,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 +82,8 @@ export const Container = ${props => props.width && stylesForMedia<string>('width', props.width)} ${props => props.height && stylesForMedia<string>('height', props.height)} ${props => props.borderRadius && stylesForMedia<string>('border-radius', props.borderRadius)} - background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; + ${props => (props.isHidden ? 'visibility: hidden;' : '')} + 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/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<DropdownProps, DropdownState> { 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/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx index fd14cc4d1..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'; @@ -11,6 +10,7 @@ export interface TextProps { fontSize?: string; opacity?: number; letterSpacing?: string; + textAlign?: string; textTransform?: string; lineHeight?: string; className?: string; @@ -22,6 +22,7 @@ export interface TextProps { noWrap?: boolean; display?: string; href?: string; + width?: string; } export const Text: React.StatelessComponent<TextProps> = ({ href, onClick, ...rest }) => { @@ -29,7 +30,7 @@ export const Text: React.StatelessComponent<TextProps> = ({ href, onClick, ...re return <StyledText {...rest} onClick={computedOnClick} />; }; -const darkenOnHoverAmount = 0.3; +const opacityOnHoverAmount = 0.5; export const StyledText = styled.div < TextProps > @@ -51,9 +52,10 @@ 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'])}` : ''}; + ${props => (props.onClick ? `opacity: ${opacityOnHoverAmount};` : '')}; } } `; diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 47c938472..8a809ee31 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -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', }); diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index 2856ea3e3..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<ZeroExInstantOverlay const { onClose, zIndex, ...rest } = props; return ( <ZeroExInstantProvider {...rest}> - <Overlay zIndex={zIndex}> + <Overlay zIndex={zIndex} className={OVERLAY_DIV_CLASS}> <Flex height="100vh"> <Container position="absolute" top="0px" right="0px" display={{ default: 'initial', sm: 'none' }}> <Icon @@ -30,7 +31,11 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay padding="2em 2em" /> </Container> - <Container width={{ default: 'auto', sm: '100%' }} height={{ default: 'auto', sm: '100%' }}> + <Container + width={{ default: 'auto', sm: '100%' }} + height={{ default: 'auto', sm: '100%' }} + className={MAIN_CONTAINER_DIV_CLASS} + > <ZeroExInstantContainer /> </Container> </Flex> diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 1f53f2d96..46488fcc4 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, QuoteFetchOrigin } from '../types'; import { analytics, disableAnalytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; @@ -117,7 +117,9 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider this._buyQuoteHeartbeat.start(BUY_QUOTE_UPDATE_INTERVAL_TIME_MS); // Trigger first buyquote fetch // tslint:disable-next-line:no-floating-promises - asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, { updateSilently: false }); + asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, QuoteFetchOrigin.Manual, { + updateSilently: false, + }); // warm up the gas price estimator cache just in case we can't // grab the gas price estimate when submitting the transaction // tslint:disable-next-line:no-floating-promises @@ -127,14 +129,16 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider // Analytics disableAnalytics(this.props.shouldDisableAnalyticsTracking || false); - analytics.addEventProperties({ - 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, - }); + analytics.addEventProperties( + analytics.generateEventProperties( + state.network, + this.props.orderSource, + state.providerState, + window, + state.selectedAsset, + this.props.affiliateInfo, + ), + ); analytics.trackInstantOpened(); } public componentWillUnmount(): void { |