Browse Source

Merge pull request #840 from gre/fix-analytics-events

Use more properties instead of context
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
de02be7342
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 44
      src/analytics/segment.js
  2. 2
      src/components/DashboardPage/AccountsOrder.js
  3. 6
      src/components/ExchangePage/ExchangeCard.js
  4. 1
      src/components/IsUnlocked.js
  5. 8
      src/components/Onboarding/steps/Finish.js
  6. 4
      src/components/Onboarding/steps/GenuineCheck/index.js
  7. 8
      src/components/Onboarding/steps/NoDevice.js
  8. 2
      src/components/OperationsList/index.js
  9. 24
      src/components/PillsDaysCount.js
  10. 6
      src/components/RenderError.js
  11. 37
      src/components/SelectExchange.js
  12. 4
      src/components/SettingsPage/AboutRowItem.js
  13. 1
      src/components/SettingsPage/CleanButton.js
  14. 24
      src/components/SettingsPage/CounterValueExchangeSelect.js
  15. 3
      src/components/SettingsPage/CounterValueSelect.js
  16. 6
      src/components/SettingsPage/LanguageSelect.js
  17. 8
      src/components/SettingsPage/MarketIndicatorRadio.js
  18. 2
      src/components/SettingsPage/RegionSelect.js
  19. 4
      src/components/SettingsPage/ReleaseNotesButton.js
  20. 1
      src/components/SettingsPage/ResetButton.js
  21. 2
      src/components/SettingsPage/sections/Currencies.js
  22. 2
      src/components/SettingsPage/sections/CurrencyRows.js
  23. 2
      src/components/StickyBackToTop.js
  24. 2
      src/components/TopBar/ActivityIndicator.js
  25. 4
      src/components/base/Modal/ConfirmModal.js
  26. 1
      src/components/base/Modal/stories.js
  27. 12
      src/components/modals/AccountSettingRenderBody.js
  28. 6
      src/components/modals/OperationDetails.js
  29. 2
      src/components/modals/ReleaseNotes.js
  30. 2
      src/components/modals/UpdateFirmware/Disclaimer.js
  31. 2
      src/components/modals/UpdateFirmware/steps/01-step-install-full-firmware.js
  32. 2
      src/components/modals/UpdateFirmware/steps/02-step-flash-mcu.js
  33. 2
      src/components/modals/UpdateFirmware/steps/03-step-confirmation.js
  34. 12
      src/helpers/linking.js

44
src/analytics/segment.js

@ -16,12 +16,15 @@ if (!process.env.STORYBOOK_ENV) {
const sessionId = uuid() const sessionId = uuid()
const getContext = store => { const getContext = _store => ({
ip: '0.0.0.0',
})
const extraProperties = store => {
const state = store.getState() const state = store.getState()
const { language, region } = langAndRegionSelector(state) const { language, region } = langAndRegionSelector(state)
const systemLocale = getSystemLocale() const systemLocale = getSystemLocale()
return { return {
ip: '0.0.0.0',
appVersion: __APP_VERSION__, appVersion: __APP_VERSION__,
language, language,
region, region,
@ -45,13 +48,9 @@ export const start = (store: *) => {
return return
} }
load() load()
analytics.identify( analytics.identify(id, extraProperties(store), {
id, context: getContext(store),
{}, })
{
context: getContext(store),
},
)
} }
export const stop = () => { export const stop = () => {
@ -75,9 +74,16 @@ export const track = (event: string, properties: ?Object) => {
logger.error('analytics is not available') logger.error('analytics is not available')
return return
} }
analytics.track(event, properties, { analytics.track(
context: getContext(storeInstance), event,
}) {
...extraProperties(storeInstance),
...properties,
},
{
context: getContext(storeInstance),
},
)
} }
export const page = (category: string, name: ?string, properties: ?Object) => { export const page = (category: string, name: ?string, properties: ?Object) => {
@ -90,7 +96,15 @@ export const page = (category: string, name: ?string, properties: ?Object) => {
logger.error('analytics is not available') logger.error('analytics is not available')
return return
} }
analytics.page(category, name, properties, { analytics.page(
context: getContext(storeInstance), category,
}) name,
{
...extraProperties(storeInstance),
...properties,
},
{
context: getContext(storeInstance),
},
)
} }

2
src/components/DashboardPage/AccountsOrder.js

@ -21,6 +21,7 @@ import { reorderAccounts } from 'actions/accounts'
import { accountsSelector } from 'reducers/accounts' import { accountsSelector } from 'reducers/accounts'
import { saveSettings } from 'actions/settings' import { saveSettings } from 'actions/settings'
import Track from 'analytics/Track'
import BoldToggle from 'components/base/BoldToggle' import BoldToggle from 'components/base/BoldToggle'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import DropDown, { DropDownItem } from 'components/base/DropDown' import DropDown, { DropDownItem } from 'components/base/DropDown'
@ -202,6 +203,7 @@ class AccountsOrder extends Component<Props> {
onStateChange={this.onStateChange} onStateChange={this.onStateChange}
value={sortItems.find(item => item.key === orderAccounts)} value={sortItems.find(item => item.key === orderAccounts)}
> >
<Track onUpdate event="ChangeSort" orderAccounts={orderAccounts} />
<Text ff="Open Sans|SemiBold" fontSize={4}> <Text ff="Open Sans|SemiBold" fontSize={4}>
{t('app:common.sortBy')} {t('app:common.sortBy')}
</Text> </Text>

6
src/components/ExchangePage/ExchangeCard.js

@ -1,8 +1,7 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { shell } from 'electron' import { openURL } from 'helpers/linking'
import { track } from 'analytics/segment'
import type { T } from 'types/common' import type { T } from 'types/common'
@ -19,8 +18,7 @@ type CardType = {
export default class ExchangeCard extends PureComponent<{ t: T, card: CardType }> { export default class ExchangeCard extends PureComponent<{ t: T, card: CardType }> {
onClick = () => { onClick = () => {
const { card } = this.props const { card } = this.props
shell.openExternal(card.url) openURL(card.url, 'VisitExchange', { id: card.id })
track('VisitExchange', { id: card.id, url: card.url })
} }
render() { render() {
const { const {

1
src/components/IsUnlocked.js

@ -186,6 +186,7 @@ class IsUnlocked extends Component<Props, State> {
</Box> </Box>
</form> </form>
<ConfirmModal <ConfirmModal
analyticsName="HardReset"
isDanger isDanger
isLoading={isHardResetting} isLoading={isHardResetting}
isOpened={isHardResetModalOpened} isOpened={isHardResetModalOpened}

8
src/components/Onboarding/steps/Finish.js

@ -1,7 +1,7 @@
// @flow // @flow
import React, { Component } from 'react' import React, { Component } from 'react'
import { shell } from 'electron' import { openURL } from 'helpers/linking'
import styled from 'styled-components' import styled from 'styled-components'
import { i } from 'helpers/staticPath' import { i } from 'helpers/staticPath'
import { urls } from 'config/support' import { urls } from 'config/support'
@ -35,19 +35,19 @@ const socialMedia = [
key: 'twitter', key: 'twitter',
url: urls.twitter, url: urls.twitter,
icon: <IconSocialTwitter size={24} />, icon: <IconSocialTwitter size={24} />,
onClick: url => shell.openExternal(url), onClick: url => openURL(url),
}, },
{ {
key: 'github', key: 'github',
url: urls.github, url: urls.github,
icon: <IconSocialGithub size={24} />, icon: <IconSocialGithub size={24} />,
onClick: url => shell.openExternal(url), onClick: url => openURL(url),
}, },
{ {
key: 'reddit', key: 'reddit',
url: urls.reddit, url: urls.reddit,
icon: <IconSocialReddit size={24} />, icon: <IconSocialReddit size={24} />,
onClick: url => shell.openExternal(url), onClick: url => openURL(url),
}, },
] ]

4
src/components/Onboarding/steps/GenuineCheck/index.js

@ -1,7 +1,7 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { shell } from 'electron' import { openURL } from 'helpers/linking'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import styled from 'styled-components' import styled from 'styled-components'
import { colors } from 'styles/theme' import { colors } from 'styles/theme'
@ -144,7 +144,7 @@ class GenuineCheck extends PureComponent<StepProps, State> {
} }
contactSupport = () => { contactSupport = () => {
shell.openExternal(urls.genuineCheckContactSupport) openURL(urls.genuineCheckContactSupport)
} }
handlePrevStep = () => { handlePrevStep = () => {

8
src/components/Onboarding/steps/NoDevice.js

@ -1,7 +1,7 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { shell } from 'electron' import { openURL } from 'helpers/linking'
import { i } from 'helpers/staticPath' import { i } from 'helpers/staticPath'
import Box from 'components/base/Box' import Box from 'components/base/Box'
@ -27,7 +27,7 @@ class NoDevice extends PureComponent<StepProps, *> {
icon: <IconCart size={20} />, icon: <IconCart size={20} />,
title: t('onboarding:noDevice.buyNew.title'), title: t('onboarding:noDevice.buyNew.title'),
onClick: () => { onClick: () => {
shell.openExternal(urls.noDeviceBuyNew) openURL(urls.noDeviceBuyNew)
}, },
}, },
{ {
@ -35,7 +35,7 @@ class NoDevice extends PureComponent<StepProps, *> {
icon: <IconTruck size={20} />, icon: <IconTruck size={20} />,
title: t('onboarding:noDevice.trackOrder.title'), title: t('onboarding:noDevice.trackOrder.title'),
onClick: () => { onClick: () => {
shell.openExternal(urls.noDeviceTrackOrder) openURL(urls.noDeviceTrackOrder)
}, },
}, },
{ {
@ -43,7 +43,7 @@ class NoDevice extends PureComponent<StepProps, *> {
icon: <IconInfoCircle size={20} />, icon: <IconInfoCircle size={20} />,
title: t('onboarding:noDevice.learnMore.title'), title: t('onboarding:noDevice.learnMore.title'),
onClick: () => { onClick: () => {
shell.openExternal(urls.noDeviceLearnMore) openURL(urls.noDeviceLearnMore)
}, },
}, },
] ]

2
src/components/OperationsList/index.js

@ -25,6 +25,7 @@ import IconAngleDown from 'icons/AngleDown'
import Box, { Card } from 'components/base/Box' import Box, { Card } from 'components/base/Box'
import Text from 'components/base/Text' import Text from 'components/base/Text'
import Track from 'analytics/Track' import Track from 'analytics/Track'
import { track } from 'analytics/segment'
import SectionTitle from './SectionTitle' import SectionTitle from './SectionTitle'
import OperationC from './Operation' import OperationC from './Operation'
@ -81,6 +82,7 @@ export class OperationsList extends PureComponent<Props, State> {
// TODO: convert of async/await if fetching with the api // TODO: convert of async/await if fetching with the api
fetchMoreOperations = () => { fetchMoreOperations = () => {
track('FetchMoreOperations')
this.setState({ nbToShow: this.state.nbToShow + 20 }) this.setState({ nbToShow: this.state.nbToShow + 20 })
} }

24
src/components/PillsDaysCount.js

@ -1,11 +1,12 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { Fragment, PureComponent } from 'react'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import type { T } from 'types/common' import type { T } from 'types/common'
import Pills from 'components/base/Pills' import Pills from 'components/base/Pills'
import { timeRangeDaysByKey } from 'reducers/settings' import { timeRangeDaysByKey } from 'reducers/settings'
import type { TimeRange } from 'reducers/settings' import type { TimeRange } from 'reducers/settings'
import Track from 'analytics/Track'
type Props = { type Props = {
selected: string, selected: string,
@ -17,15 +18,18 @@ class PillsDaysCount extends PureComponent<Props> {
render() { render() {
const { selected, onChange, t } = this.props const { selected, onChange, t } = this.props
return ( return (
<Pills <Fragment>
items={Object.keys(timeRangeDaysByKey).map((key: TimeRange) => ({ <Track onUpdate event="PillsDaysChange" selected={selected} />
key, <Pills
value: timeRangeDaysByKey[key], items={Object.keys(timeRangeDaysByKey).map((key: TimeRange) => ({
label: t(`app:time.${key}`), key,
}))} value: timeRangeDaysByKey[key],
activeKey={selected} label: t(`app:time.${key}`),
onChange={onChange} }))}
/> activeKey={selected}
onChange={onChange}
/>
</Fragment>
) )
} }
} }

6
src/components/RenderError.js

@ -2,7 +2,8 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { shell, remote } from 'electron' import { openURL } from 'helpers/linking'
import { remote } from 'electron'
import qs from 'querystring' import qs from 'querystring'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
@ -60,7 +61,7 @@ ${error.stack}
\`\`\` \`\`\`
`, `,
}) })
shell.openExternal(`https://github.com/LedgerHQ/ledger-live-desktop/issues/new?${q}`) openURL(`https://github.com/LedgerHQ/ledger-live-desktop/issues/new?${q}`)
} }
handleRestart = () => { handleRestart = () => {
@ -112,6 +113,7 @@ ${error.stack}
</Button> </Button>
</Box> </Box>
<ConfirmModal <ConfirmModal
analyticsName="HardReset"
isDanger isDanger
isLoading={isHardResetting} isLoading={isHardResetting}
isOpened={isHardResetModalOpened} isOpened={isHardResetModalOpened}

37
src/components/SelectExchange.js

@ -1,11 +1,12 @@
// @flow // @flow
import React, { Component } from 'react' import React, { Fragment, Component } from 'react'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import LRU from 'lru-cache' import LRU from 'lru-cache'
import type { Currency } from '@ledgerhq/live-common/lib/types' import type { Currency } from '@ledgerhq/live-common/lib/types'
import type { Exchange } from '@ledgerhq/live-common/lib/countervalues/types' import type { Exchange } from '@ledgerhq/live-common/lib/countervalues/types'
import logger from 'logger' import logger from 'logger'
import Track from 'analytics/Track'
import Select from 'components/base/Select' import Select from 'components/base/Select'
import Text from 'components/base/Text' import Text from 'components/base/Text'
import CounterValues from 'helpers/countervalues' import CounterValues from 'helpers/countervalues'
@ -91,27 +92,37 @@ class SelectExchange extends Component<
} }
render() { render() {
const { onChange, exchangeId, style, t, ...props } = this.props const { onChange, exchangeId, style, t, from, to, ...props } = this.props
const { exchanges, error } = this.state const { exchanges, error } = this.state
const options = exchanges ? exchanges.map(e => ({ value: e.id, label: e.name, ...e })) : [] const options = exchanges ? exchanges.map(e => ({ value: e.id, label: e.name, ...e })) : []
const value = options.find(e => e.id === exchangeId)
return error ? ( return error ? (
<Text ff="Open Sans|SemiBold" color="dark" fontSize={4}> <Text ff="Open Sans|SemiBold" color="dark" fontSize={4}>
{t('app:common.error.load')} {t('app:common.error.load')}
</Text> </Text>
) : ( ) : (
<Select <Fragment>
value={options.find(e => e.id === exchangeId)} <Track
options={options} onUpdate
onChange={onChange} event="SelectExchange"
isLoading={options.length === 0} exchangeName={value && value.id}
placeholder={t('app:common.selectExchange')} fromCurrency={from.ticker}
noOptionsMessage={({ inputValue }) => toCurrency={to.ticker}
t('app:common.selectExchangeNoOption', { exchangeName: inputValue }) />
} <Select
{...props} value={value}
/> options={options}
onChange={onChange}
isLoading={options.length === 0}
placeholder={t('app:common.selectExchange')}
noOptionsMessage={({ inputValue }) =>
t('app:common.selectExchangeNoOption', { exchangeName: inputValue })
}
{...props}
/>
</Fragment>
) )
} }
} }

4
src/components/SettingsPage/AboutRowItem.js

@ -1,6 +1,6 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { shell } from 'electron' import { openURL } from 'helpers/linking'
import IconExternalLink from 'icons/ExternalLink' import IconExternalLink from 'icons/ExternalLink'
import { Tabbable } from 'components/base/Box' import { Tabbable } from 'components/base/Box'
import { SettingsSectionRow } from './SettingsSection' import { SettingsSectionRow } from './SettingsSection'
@ -10,7 +10,7 @@ export default class AboutRowItem extends PureComponent<{
title: string, title: string,
desc: string, desc: string,
}> { }> {
onClick = () => shell.openExternal(this.props.url) onClick = () => openURL(this.props.url)
render() { render() {
const { title, desc } = this.props const { title, desc } = this.props

1
src/components/SettingsPage/CleanButton.js

@ -50,6 +50,7 @@ class CleanButton extends PureComponent<Props, State> {
</Button> </Button>
<ConfirmModal <ConfirmModal
analyticsName="CleanCache"
isDanger isDanger
isOpened={opened} isOpened={opened}
onClose={this.close} onClose={this.close}

24
src/components/SettingsPage/CounterValueExchangeSelect.js

@ -11,6 +11,7 @@ import {
import { setCounterValueExchange } from 'actions/settings' import { setCounterValueExchange } from 'actions/settings'
import type { Currency } from '@ledgerhq/live-common/lib/types' import type { Currency } from '@ledgerhq/live-common/lib/types'
import SelectExchange from 'components/SelectExchange' import SelectExchange from 'components/SelectExchange'
import Track from 'analytics/Track'
type Props = { type Props = {
counterValueCurrency: Currency, counterValueCurrency: Currency,
@ -25,20 +26,19 @@ class CounterValueExchangeSelect extends PureComponent<Props> {
render() { render() {
const { counterValueCurrency, counterValueExchange } = this.props const { counterValueCurrency, counterValueExchange } = this.props
return ( return counterValueCurrency ? (
<Fragment> <Fragment>
{counterValueCurrency ? ( <Track onUpdate event="CounterValueExchangeSelect" exchangeId={counterValueExchange} />
<SelectExchange <SelectExchange
small small
from={intermediaryCurrency} from={intermediaryCurrency}
to={counterValueCurrency} to={counterValueCurrency}
exchangeId={counterValueExchange} exchangeId={counterValueExchange}
onChange={this.handleChangeExchange} onChange={this.handleChangeExchange}
minWidth={200} minWidth={200}
/> />
) : null}
</Fragment> </Fragment>
) ) : null
} }
} }

3
src/components/SettingsPage/CounterValueSelect.js

@ -8,6 +8,7 @@ import type { Currency } from '@ledgerhq/live-common/lib/types'
import { setCounterValue } from 'actions/settings' import { setCounterValue } from 'actions/settings'
import { counterValueCurrencySelector } from 'reducers/settings' import { counterValueCurrencySelector } from 'reducers/settings'
import Select from 'components/base/Select' import Select from 'components/base/Select'
import Track from 'analytics/Track'
const fiats = listFiatCurrencies() const fiats = listFiatCurrencies()
.map(f => f.units[0]) .map(f => f.units[0])
@ -35,7 +36,7 @@ class CounterValueSelect extends PureComponent<Props> {
return ( return (
<Fragment> <Fragment>
{/* TODO Track */} <Track onUpdate event="CounterValueSelect" counterValue={cvOption && cvOption.value} />
<Select <Select
small small
minWidth={250} minWidth={250}

6
src/components/SettingsPage/LanguageSelect.js

@ -8,6 +8,7 @@ import { connect } from 'react-redux'
import { setLanguage } from 'actions/settings' import { setLanguage } from 'actions/settings'
import { langAndRegionSelector } from 'reducers/settings' import { langAndRegionSelector } from 'reducers/settings'
import languageKeys from 'config/languages' import languageKeys from 'config/languages'
import Track from 'analytics/Track'
import Select from 'components/base/Select' import Select from 'components/base/Select'
type Props = { type Props = {
@ -37,6 +38,11 @@ class LanguageSelect extends PureComponent<Props> {
: this.languages.find(l => l.value === language) : this.languages.find(l => l.value === language)
return ( return (
<Fragment> <Fragment>
<Track
onUpdate
event="LanguageSelect"
currentRegion={currentLanguage && currentLanguage.value}
/>
<Select <Select
small small
minWidth={250} minWidth={250}

8
src/components/SettingsPage/MarketIndicatorRadio.js

@ -1,6 +1,6 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { Fragment, PureComponent } from 'react'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import type { T } from 'types/common' import type { T } from 'types/common'
import { connect } from 'react-redux' import { connect } from 'react-redux'
@ -8,6 +8,7 @@ import { createStructuredSelector } from 'reselect'
import { setMarketIndicator } from 'actions/settings' import { setMarketIndicator } from 'actions/settings'
import { marketIndicatorSelector } from 'reducers/settings' import { marketIndicatorSelector } from 'reducers/settings'
import RadioGroup from 'components/base/RadioGroup' import RadioGroup from 'components/base/RadioGroup'
import Track from 'analytics/Track'
type Props = { type Props = {
t: T, t: T,
@ -35,7 +36,10 @@ class MarketIndicatorRadio extends PureComponent<Props> {
render() { render() {
const { marketIndicator } = this.props const { marketIndicator } = this.props
return ( return (
<RadioGroup items={this.indicators} activeKey={marketIndicator} onChange={this.onChange} /> <Fragment>
<Track onUpdate event="MarketIndicatorRadio" marketIndicator={marketIndicator} />
<RadioGroup items={this.indicators} activeKey={marketIndicator} onChange={this.onChange} />
</Fragment>
) )
} }
} }

2
src/components/SettingsPage/RegionSelect.js

@ -8,6 +8,7 @@ import { langAndRegionSelector, counterValueCurrencySelector } from 'reducers/se
import type { Currency } from '@ledgerhq/live-common/lib/types' import type { Currency } from '@ledgerhq/live-common/lib/types'
import type { T } from 'types/common' import type { T } from 'types/common'
import Track from 'analytics/Track'
import regionsByKey from 'helpers/regions.json' import regionsByKey from 'helpers/regions.json'
import Select from 'components/base/Select' import Select from 'components/base/Select'
@ -39,6 +40,7 @@ class RegionSelect extends PureComponent<Props> {
return ( return (
<Fragment> <Fragment>
<Track onUpdate event="RegionSelectChange" currentRegion={currentRegion.region} />
<Select <Select
small small
minWidth={250} minWidth={250}

4
src/components/SettingsPage/ReleaseNotesButton.js

@ -3,7 +3,7 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import type { T } from 'types/common' import type { T } from 'types/common'
import { shell } from 'electron' import { openURL } from 'helpers/linking'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { openModal } from 'reducers/modals' import { openModal } from 'reducers/modals'
import { MODAL_RELEASES_NOTES } from 'config/constants' import { MODAL_RELEASES_NOTES } from 'config/constants'
@ -19,7 +19,7 @@ const mapDispatchToProps = {
} }
class ReleaseNotesButton extends PureComponent<Props> { class ReleaseNotesButton extends PureComponent<Props> {
handleOpenLink = (url: string) => shell.openExternal(url) handleOpenLink = (url: string) => openURL(url)
render() { render() {
const { t, openModal } = this.props const { t, openModal } = this.props

1
src/components/SettingsPage/ResetButton.js

@ -49,6 +49,7 @@ class ResetButton extends PureComponent<Props, State> {
</Button> </Button>
<ConfirmModal <ConfirmModal
analyticsName="HardReset"
isDanger isDanger
isLoading={pending} isLoading={pending}
isOpened={opened} isOpened={opened}

2
src/components/SettingsPage/sections/Currencies.js

@ -44,7 +44,7 @@ class TabCurrencies extends PureComponent<Props, State> {
const { t, currencies } = this.props const { t, currencies } = this.props
return ( return (
<Section key={currency.id}> <Section key={currency.id}>
<TrackPage category="Settings" name="Currencies" /> <TrackPage category="Settings" name="Currencies" currencyId={currency.id} />
<Header <Header
icon={<IconCurrencies size={16} />} icon={<IconCurrencies size={16} />}
title={t('app:settings.tabs.currencies')} title={t('app:settings.tabs.currencies')}

2
src/components/SettingsPage/sections/CurrencyRows.js

@ -12,6 +12,7 @@ import type { SettingsState, CurrencySettings } from 'reducers/settings'
import { currencySettingsDefaults } from 'helpers/SettingsDefaults' import { currencySettingsDefaults } from 'helpers/SettingsDefaults'
import StepperNumber from 'components/base/StepperNumber' import StepperNumber from 'components/base/StepperNumber'
import ExchangeSelect from 'components/SelectExchange' import ExchangeSelect from 'components/SelectExchange'
import Track from 'analytics/Track'
import { SettingsSectionRow as Row } from '../SettingsSection' import { SettingsSectionRow as Row } from '../SettingsSection'
@ -87,6 +88,7 @@ class CurrencyRows extends PureComponent<Props> {
title={t('app:settings.currencies.confirmationsNb')} title={t('app:settings.currencies.confirmationsNb')}
desc={t('app:settings.currencies.confirmationsNbDesc')} desc={t('app:settings.currencies.confirmationsNbDesc')}
> >
<Track onUpdate event="ConfirmationsNb" confirmationsNb={confirmationsNb} />
<StepperNumber <StepperNumber
min={defaults.confirmationsNb.min} min={defaults.confirmationsNb.min}
max={defaults.confirmationsNb.max} max={defaults.confirmationsNb.max}

2
src/components/StickyBackToTop.js

@ -3,6 +3,7 @@ import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import styled from 'styled-components' import styled from 'styled-components'
import smoothscroll from 'smoothscroll-polyfill' import smoothscroll from 'smoothscroll-polyfill'
import { track } from 'analytics/segment'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import AngleUp from 'icons/AngleUp' import AngleUp from 'icons/AngleUp'
import { GrowScrollContext } from './base/GrowScroll' import { GrowScrollContext } from './base/GrowScroll'
@ -79,6 +80,7 @@ class StickyBackToTop extends PureComponent<Props, State> {
if (scrollContainer) { if (scrollContainer) {
// $FlowFixMe seems to be missing in flow // $FlowFixMe seems to be missing in flow
scrollContainer.scrollTo({ top: 0, behavior: 'smooth' }) scrollContainer.scrollTo({ top: 0, behavior: 'smooth' })
track('ScrollBackToTop')
} }
} }

2
src/components/TopBar/ActivityIndicator.js

@ -9,6 +9,7 @@ import { translate } from 'react-i18next'
import type { T } from 'types/common' import type { T } from 'types/common'
import type { AsyncState } from 'reducers/bridgeSync' import type { AsyncState } from 'reducers/bridgeSync'
import { track } from 'analytics/segment'
import { globalSyncStateSelector } from 'reducers/bridgeSync' import { globalSyncStateSelector } from 'reducers/bridgeSync'
import { isUpToDateSelector } from 'reducers/accounts' import { isUpToDateSelector } from 'reducers/accounts'
import { BridgeSyncConsumer } from 'bridge/BridgeSyncContext' import { BridgeSyncConsumer } from 'bridge/BridgeSyncContext'
@ -47,6 +48,7 @@ class ActivityIndicatorInner extends PureComponent<Props, { lastClickTime: numbe
this.props.cvPoll() this.props.cvPoll()
this.props.setSyncBehavior({ type: 'SYNC_ALL_ACCOUNTS', priority: 5 }) this.props.setSyncBehavior({ type: 'SYNC_ALL_ACCOUNTS', priority: 5 })
this.setState({ lastClickTime: Date.now() }) this.setState({ lastClickTime: Date.now() })
track('SyncRefreshClick')
} }
render() { render() {

4
src/components/base/Modal/ConfirmModal.js

@ -5,6 +5,7 @@ import { translate } from 'react-i18next'
import type { T } from 'types/common' import type { T } from 'types/common'
import TrackPage from 'analytics/TrackPage'
import Button from 'components/base/Button' import Button from 'components/base/Button'
import Box from 'components/base/Box' import Box from 'components/base/Box'
@ -23,6 +24,7 @@ type Props = {
onConfirm: Function, onConfirm: Function,
t: T, t: T,
isLoading?: boolean, isLoading?: boolean,
analyticsName: string,
} }
class ConfirmModal extends PureComponent<Props> { class ConfirmModal extends PureComponent<Props> {
@ -40,6 +42,7 @@ class ConfirmModal extends PureComponent<Props> {
isLoading, isLoading,
renderIcon, renderIcon,
t, t,
analyticsName,
...props ...props
} = this.props } = this.props
@ -52,6 +55,7 @@ class ConfirmModal extends PureComponent<Props> {
{...props} {...props}
render={({ onClose }) => ( render={({ onClose }) => (
<ModalBody onClose={isLoading ? undefined : onClose}> <ModalBody onClose={isLoading ? undefined : onClose}>
<TrackPage category="Modal" name={analyticsName} />
<ModalTitle>{title}</ModalTitle> <ModalTitle>{title}</ModalTitle>
<ModalContent> <ModalContent>
{subTitle && ( {subTitle && (

1
src/components/base/Modal/stories.js

@ -36,6 +36,7 @@ stories.add('Modal', () => (
stories.add('ConfirmModal', () => ( stories.add('ConfirmModal', () => (
<ConfirmModal <ConfirmModal
categoryName=""
isOpened isOpened
isDanger={boolean('isDanger', false)} isDanger={boolean('isDanger', false)}
title={text('title', 'Hard reset')} title={text('title', 'Hard reset')}

12
src/components/modals/AccountSettingRenderBody.js

@ -17,6 +17,7 @@ import { setDataModal } from 'reducers/modals'
import { getBridgeForCurrency } from 'bridge' import { getBridgeForCurrency } from 'bridge'
import TrackPage from 'analytics/TrackPage'
import Spoiler from 'components/base/Spoiler' import Spoiler from 'components/base/Spoiler'
import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon' import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon'
import Box from 'components/base/Box' import Box from 'components/base/Box'
@ -197,6 +198,7 @@ class HelperComp extends PureComponent<Props, State> {
return ( return (
<ModalBody onClose={onClose}> <ModalBody onClose={onClose}>
<form onSubmit={this.handleSubmit(account, onClose)}> <form onSubmit={this.handleSubmit(account, onClose)}>
<TrackPage category="Modal" name="AccountSettings" />
<ModalTitle>{t('app:account.settings.title')}</ModalTitle> <ModalTitle>{t('app:account.settings.title')}</ModalTitle>
<ModalContent mb={3}> <ModalContent mb={3}>
<Container> <Container>
@ -275,15 +277,21 @@ class HelperComp extends PureComponent<Props, State> {
</Spoiler> </Spoiler>
</ModalContent> </ModalContent>
<ModalFooter horizontal> <ModalFooter horizontal>
<Button danger type="button" onClick={this.handleOpenRemoveAccountModal}> <Button
event="OpenAccountDelete"
danger
type="button"
onClick={this.handleOpenRemoveAccountModal}
>
{t('app:common.delete')} {t('app:common.delete')}
</Button> </Button>
<Button ml="auto" type="submit" primary> <Button event="DoneEditingAccount" ml="auto" type="submit" primary>
{t('app:common.apply')} {t('app:common.apply')}
</Button> </Button>
</ModalFooter> </ModalFooter>
</form> </form>
<ConfirmModal <ConfirmModal
analyticsName="RemoveAccount"
isDanger isDanger
isOpened={isRemoveAccountModalOpen} isOpened={isRemoveAccountModalOpen}
onClose={this.handleCloseRemoveAccountModal} onClose={this.handleCloseRemoveAccountModal}

6
src/components/modals/OperationDetails.js

@ -2,13 +2,14 @@
import React, { Fragment, Component } from 'react' import React, { Fragment, Component } from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { shell } from 'electron' import { openURL } from 'helpers/linking'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import moment from 'moment' import moment from 'moment'
import { getOperationAmountNumber } from '@ledgerhq/live-common/lib/helpers/operation' import { getOperationAmountNumber } from '@ledgerhq/live-common/lib/helpers/operation'
import { getAccountOperationExplorer } from '@ledgerhq/live-common/lib/explorers' import { getAccountOperationExplorer } from '@ledgerhq/live-common/lib/explorers'
import TrackPage from 'analytics/TrackPage'
import type { Account, Operation } from '@ledgerhq/live-common/lib/types' import type { Account, Operation } from '@ledgerhq/live-common/lib/types'
import type { T, CurrencySettings } from 'types/common' import type { T, CurrencySettings } from 'types/common'
@ -128,6 +129,7 @@ const OperationDetails = connect(mapStateToProps)((props: Props) => {
return ( return (
<ModalBody onClose={onClose}> <ModalBody onClose={onClose}>
<TrackPage category="Modal" name="OperationDetails" />
<ModalTitle>{t('app:operationDetails.title')}</ModalTitle> <ModalTitle>{t('app:operationDetails.title')}</ModalTitle>
<ModalContent relative style={{ height: 500 }} px={0} pb={0}> <ModalContent relative style={{ height: 500 }} px={0} pb={0}>
<GrowScroll px={5} pt={1} pb={8}> <GrowScroll px={5} pt={1} pb={8}>
@ -229,7 +231,7 @@ const OperationDetails = connect(mapStateToProps)((props: Props) => {
{url && ( {url && (
<ModalFooter horizontal justify="flex-end" flow={2}> <ModalFooter horizontal justify="flex-end" flow={2}>
<Button primary onClick={() => shell.openExternal(url)}> <Button primary onClick={() => openURL(url)}>
{t('app:operationDetails.viewOperation')} {t('app:operationDetails.viewOperation')}
</Button> </Button>
</ModalFooter> </ModalFooter>

2
src/components/modals/ReleaseNotes.js

@ -14,6 +14,7 @@ import GrowScroll from 'components/base/GrowScroll'
import Text from 'components/base/Text' import Text from 'components/base/Text'
import Spinner from 'components/base/Spinner' import Spinner from 'components/base/Spinner'
import GradientBox from 'components/GradientBox' import GradientBox from 'components/GradientBox'
import TrackPage from 'analytics/TrackPage'
import type { T } from 'types/common' import type { T } from 'types/common'
@ -220,6 +221,7 @@ class ReleaseNotes extends PureComponent<Props, State> {
return ( return (
<ModalBody onClose={onClose}> <ModalBody onClose={onClose}>
<TrackPage category="Modal" name="ReleaseNotes" />
<ModalTitle>{t('app:releaseNotes.title')}</ModalTitle> <ModalTitle>{t('app:releaseNotes.title')}</ModalTitle>
<ModalContent relative style={{ height: 500 }} px={0} pb={0}> <ModalContent relative style={{ height: 500 }} px={0} pb={0}>
<GrowScroll px={5} pb={8}> <GrowScroll px={5} pb={8}>

2
src/components/modals/UpdateFirmware/Disclaimer.js

@ -13,6 +13,7 @@ import Button from 'components/base/Button'
import GrowScroll from 'components/base/GrowScroll' import GrowScroll from 'components/base/GrowScroll'
import GradientBox from 'components/GradientBox' import GradientBox from 'components/GradientBox'
import { Notes } from 'components/modals/ReleaseNotes' import { Notes } from 'components/modals/ReleaseNotes'
import TrackPage from 'analytics/TrackPage'
import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate' import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate'
@ -42,6 +43,7 @@ class DisclaimerModal extends PureComponent<Props, State> {
onClose={onClose} onClose={onClose}
render={({ onClose }) => ( render={({ onClose }) => (
<ModalBody onClose={onClose} grow align="center" justify="center" mt={3}> <ModalBody onClose={onClose} grow align="center" justify="center" mt={3}>
<TrackPage category="Manager" name="DisclaimerModal" />
<Fragment> <Fragment>
<ModalTitle>{t('app:manager.firmware.update')}</ModalTitle> <ModalTitle>{t('app:manager.firmware.update')}</ModalTitle>
<ModalContent> <ModalContent>

2
src/components/modals/UpdateFirmware/steps/01-step-install-full-firmware.js

@ -11,6 +11,7 @@ import getDeviceInfo from 'commands/getDeviceInfo'
import { getCurrentDevice } from 'reducers/devices' import { getCurrentDevice } from 'reducers/devices'
import { createCancelablePolling, delay } from 'helpers/promise' import { createCancelablePolling, delay } from 'helpers/promise'
import TrackPage from 'analytics/TrackPage'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Text from 'components/base/Text' import Text from 'components/base/Text'
import Progress from 'components/base/Progress' import Progress from 'components/base/Progress'
@ -169,6 +170,7 @@ class StepFullFirmwareInstall extends PureComponent<Props, State> {
? t('app:manager.modal.installing') ? t('app:manager.modal.installing')
: t('app:manager.modal.confirmIdentifier')} : t('app:manager.modal.confirmIdentifier')}
</Title> </Title>
<TrackPage category="Manager" name="InstallFirmware" />
{this.renderBody()} {this.renderBody()}
</Container> </Container>
) )

2
src/components/modals/UpdateFirmware/steps/02-step-flash-mcu.js

@ -11,6 +11,7 @@ import { getCurrentDevice } from 'reducers/devices'
import { createCancelablePolling } from 'helpers/promise' import { createCancelablePolling } from 'helpers/promise'
import getDeviceInfo from 'commands/getDeviceInfo' import getDeviceInfo from 'commands/getDeviceInfo'
import TrackPage from 'analytics/TrackPage'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Text from 'components/base/Text' import Text from 'components/base/Text'
import Progress from 'components/base/Progress' import Progress from 'components/base/Progress'
@ -186,6 +187,7 @@ class StepFlashMcu extends PureComponent<Props, State> {
<Title> <Title>
{installing ? t('app:manager.modal.flashing') : t('app:manager.modal.mcuTitle')} {installing ? t('app:manager.modal.flashing') : t('app:manager.modal.mcuTitle')}
</Title> </Title>
<TrackPage category="Manager" name="FlashMCU" />
{this.renderBody()} {this.renderBody()}
</Container> </Container>
) )

2
src/components/modals/UpdateFirmware/steps/03-step-confirmation.js

@ -3,6 +3,7 @@
import React from 'react' import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import TrackPage from 'analytics/TrackPage'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Text from 'components/base/Text' import Text from 'components/base/Text'
import Button from 'components/base/Button' import Button from 'components/base/Button'
@ -27,6 +28,7 @@ const Title = styled(Box).attrs({
function StepConfirmation({ t }: StepProps) { function StepConfirmation({ t }: StepProps) {
return ( return (
<Container> <Container>
<TrackPage category="Manager" name="FirmwareConfirmation" />
<Box mx={7} color="positiveGreen" my={4}> <Box mx={7} color="positiveGreen" my={4}>
<CheckCircle size={44} /> <CheckCircle size={44} />
</Box> </Box>

12
src/helpers/linking.js

@ -0,0 +1,12 @@
// @flow
import { shell } from 'electron'
import { track } from 'analytics/segment'
export const openURL = (
url: string,
customEventName: string = 'OpenURL',
extraParams: Object = {},
) => {
track(customEventName, { ...extraParams, url })
shell.openExternal(url)
}
Loading…
Cancel
Save