From f72c3d58c483e2f07cd9fb358ead99b8c98b7e77 Mon Sep 17 00:00:00 2001 From: meriadec Date: Wed, 4 Jul 2018 17:32:24 +0200 Subject: [PATCH 1/7] Rename About => Help --- .../SettingsPage/ReleaseNotesButton.js | 2 +- src/components/SettingsPage/index.js | 8 ++++---- .../sections/{About.js => Help.js} | 20 +++++++++---------- static/i18n/en/app.yml | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) rename src/components/SettingsPage/sections/{About.js => Help.js} (77%) diff --git a/src/components/SettingsPage/ReleaseNotesButton.js b/src/components/SettingsPage/ReleaseNotesButton.js index d6864d05..336d8e52 100644 --- a/src/components/SettingsPage/ReleaseNotesButton.js +++ b/src/components/SettingsPage/ReleaseNotesButton.js @@ -32,7 +32,7 @@ class ReleaseNotesButton extends PureComponent { openModal(MODAL_RELEASES_NOTES, version) }} > - {t('app:settings.about.releaseNotesBtn')} + {t('app:settings.help.releaseNotesBtn')} ) } diff --git a/src/components/SettingsPage/index.js b/src/components/SettingsPage/index.js index 51faedbf..a4f31813 100644 --- a/src/components/SettingsPage/index.js +++ b/src/components/SettingsPage/index.js @@ -13,7 +13,7 @@ import Pills from 'components/base/Pills' import Box from 'components/base/Box' import SectionDisplay from './sections/Display' import SectionCurrencies from './sections/Currencies' -import SectionAbout from './sections/About' +import SectionHelp from './sections/Help' import SectionTools from './sections/Tools' const mapStateToProps = state => ({ @@ -48,9 +48,9 @@ class SettingsPage extends PureComponent { value: SectionCurrencies, }, { - key: 'about', - label: props.t('app:settings.tabs.about'), - value: SectionAbout, + key: 'help', + label: props.t('app:settings.tabs.help'), + value: SectionHelp, }, ] diff --git a/src/components/SettingsPage/sections/About.js b/src/components/SettingsPage/sections/Help.js similarity index 77% rename from src/components/SettingsPage/sections/About.js rename to src/components/SettingsPage/sections/Help.js index 4e89356e..583523ae 100644 --- a/src/components/SettingsPage/sections/About.js +++ b/src/components/SettingsPage/sections/Help.js @@ -25,23 +25,23 @@ type Props = { t: T, } -class SectionAbout extends PureComponent { +class SectionHelp extends PureComponent { render() { const { t } = this.props const version = __APP_VERSION__ return (
- +
} - title={t('app:settings.tabs.about')} - desc={t('app:settings.about.desc')} + title={t('app:settings.tabs.help')} + desc={t('app:settings.help.desc')} /> - + @@ -65,14 +65,14 @@ class SectionAbout extends PureComponent { @@ -81,4 +81,4 @@ class SectionAbout extends PureComponent { } } -export default translate()(SectionAbout) +export default translate()(SectionHelp) diff --git a/static/i18n/en/app.yml b/static/i18n/en/app.yml index 2edb6b3c..2871d629 100644 --- a/static/i18n/en/app.yml +++ b/static/i18n/en/app.yml @@ -310,7 +310,7 @@ settings: # Always ensure descriptions carry full stops (.) display: General currencies: Currencies profile: Profile - about: Help + help: Help display: desc: Change settings that affect Ledger Live in general. language: Display language @@ -354,7 +354,7 @@ settings: # Always ensure descriptions carry full stops (.) analyticsDesc: Enable analytics of anonymous data to help Ledger improve the user experience. This includes the operating system, language, firmware versions and the number of added accounts. reportErrors: Report bugs reportErrorsDesc: Share anonymous usage and diagnostics data to help improve Ledger products, services and security features. - about: + help: desc: Learn about Ledger Live features or get help. version: Version releaseNotesBtn: Details # Close button instead of continue. From a689e41c720d2a5c0091bcce223456cf15c92154 Mon Sep 17 00:00:00 2001 From: meriadec Date: Wed, 4 Jul 2018 17:50:01 +0200 Subject: [PATCH 2/7] Add About section in Settings, and move some items --- .../SettingsPage/SettingsSection.js | 4 +- src/components/SettingsPage/index.js | 6 ++ src/components/SettingsPage/sections/About.js | 57 +++++++++++++++++++ src/components/SettingsPage/sections/Help.js | 12 ---- static/i18n/en/app.yml | 3 + 5 files changed, 68 insertions(+), 14 deletions(-) create mode 100644 src/components/SettingsPage/sections/About.js diff --git a/src/components/SettingsPage/SettingsSection.js b/src/components/SettingsPage/SettingsSection.js index 03d9678c..de34dee1 100644 --- a/src/components/SettingsPage/SettingsSection.js +++ b/src/components/SettingsPage/SettingsSection.js @@ -24,8 +24,8 @@ const RoundIconContainer = styled(Box).attrs({ bg: p => rgba(p.theme.colors.wallet, 0.2), color: 'wallet', })` - height: 30px; - width: 30px; + height: 34px; + width: 34px; border-radius: 50%; ` diff --git a/src/components/SettingsPage/index.js b/src/components/SettingsPage/index.js index a4f31813..dd8ed640 100644 --- a/src/components/SettingsPage/index.js +++ b/src/components/SettingsPage/index.js @@ -14,6 +14,7 @@ import Box from 'components/base/Box' import SectionDisplay from './sections/Display' import SectionCurrencies from './sections/Currencies' import SectionHelp from './sections/Help' +import SectionAbout from './sections/About' import SectionTools from './sections/Tools' const mapStateToProps = state => ({ @@ -47,6 +48,11 @@ class SettingsPage extends PureComponent { label: props.t('app:settings.tabs.currencies'), value: SectionCurrencies, }, + { + key: 'about', + label: props.t('app:settings.tabs.about'), + value: SectionAbout, + }, { key: 'help', label: props.t('app:settings.tabs.help'), diff --git a/src/components/SettingsPage/sections/About.js b/src/components/SettingsPage/sections/About.js new file mode 100644 index 00000000..14592b54 --- /dev/null +++ b/src/components/SettingsPage/sections/About.js @@ -0,0 +1,57 @@ +// @flow + +import React, { PureComponent } from 'react' +import { translate } from 'react-i18next' + +import type { T } from 'types/common' + +import TrackPage from 'analytics/TrackPage' +import { urls } from 'config/support' +import IconLoader from 'icons/Loader' + +import ReleaseNotesButton from '../ReleaseNotesButton' +import AboutRowItem from '../AboutRowItem' + +import { + SettingsSection as Section, + SettingsSectionHeader as Header, + SettingsSectionBody as Body, + SettingsSectionRow as Row, +} from '../SettingsSection' + +type Props = { + t: T, +} + +class SectionHelp extends PureComponent { + render() { + const { t } = this.props + const version = __APP_VERSION__ + + return ( +
+ + +
} + title={t('app:settings.tabs.about')} + desc={t('app:settings.about.desc')} + /> + + + + + + + + +
+ ) + } +} + +export default translate()(SectionHelp) diff --git a/src/components/SettingsPage/sections/Help.js b/src/components/SettingsPage/sections/Help.js index 583523ae..cfd1ceb6 100644 --- a/src/components/SettingsPage/sections/Help.js +++ b/src/components/SettingsPage/sections/Help.js @@ -11,7 +11,6 @@ import { urls } from 'config/support' import ExportLogsBtn from 'components/ExportLogsBtn' import CleanButton from '../CleanButton' import ResetButton from '../ResetButton' -import ReleaseNotesButton from '../ReleaseNotesButton' import AboutRowItem from '../AboutRowItem' import { @@ -28,7 +27,6 @@ type Props = { class SectionHelp extends PureComponent { render() { const { t } = this.props - const version = __APP_VERSION__ return (
@@ -41,10 +39,6 @@ class SectionHelp extends PureComponent { /> - - - - { desc={t('app:settings.help.faqDesc')} url={urls.faq} /> - -
) diff --git a/static/i18n/en/app.yml b/static/i18n/en/app.yml index 2871d629..a2fc5c8e 100644 --- a/static/i18n/en/app.yml +++ b/static/i18n/en/app.yml @@ -311,6 +311,7 @@ settings: # Always ensure descriptions carry full stops (.) currencies: Currencies profile: Profile help: Help + about: About display: desc: Change settings that affect Ledger Live in general. language: Display language @@ -354,6 +355,8 @@ settings: # Always ensure descriptions carry full stops (.) analyticsDesc: Enable analytics of anonymous data to help Ledger improve the user experience. This includes the operating system, language, firmware versions and the number of added accounts. reportErrors: Report bugs reportErrorsDesc: Share anonymous usage and diagnostics data to help improve Ledger products, services and security features. + about: + desc: Learn about Ledger Live features help: desc: Learn about Ledger Live features or get help. version: Version From cf184cd26e662794a6f0bcc28cf3909e1cd49b0e Mon Sep 17 00:00:00 2001 From: meriadec Date: Wed, 4 Jul 2018 14:53:09 +0200 Subject: [PATCH 3/7] Libcore handling of splitted currencies --- .../AddAccounts/steps/03-step-import.js | 15 +++- src/config/constants.js | 2 +- src/helpers/accountName.js | 3 +- src/helpers/bip32.js | 17 ++++ src/helpers/libcore.js | 86 ++++++++++++++++--- static/i18n/en/app.yml | 2 + 6 files changed, 107 insertions(+), 18 deletions(-) diff --git a/src/components/modals/AddAccounts/steps/03-step-import.js b/src/components/modals/AddAccounts/steps/03-step-import.js index b74046fa..1142c7e4 100644 --- a/src/components/modals/AddAccounts/steps/03-step-import.js +++ b/src/components/modals/AddAccounts/steps/03-step-import.js @@ -70,10 +70,21 @@ class StepImport extends PureComponent { const { t } = this.props let { name } = account + const isLegacy = name.indexOf('legacy') !== -1 + const isUnsplit = name.indexOf('unsplit') !== -1 + if (name === 'New Account') { name = t('app:addAccounts.newAccount') - } else if (name.indexOf('legacy') !== -1) { - name = t('app:addAccounts.legacyAccount', { accountName: name.replace(' (legacy)', '') }) + } else if (isLegacy) { + if (isUnsplit) { + name = t('app:addAccounts.legacyUnsplitAccount', { + accountName: name.replace(' (legacy)', '').replace(' (unsplit)', ''), + }) + } else { + name = t('app:addAccounts.legacyAccount', { accountName: name.replace(' (legacy)', '') }) + } + } else if (isUnsplit) { + name = t('app:addAccounts.unsplitAccount', { accountName: name.replace(' (unsplit)', '') }) } return { diff --git a/src/config/constants.js b/src/config/constants.js index 7396c0f5..2d42e5a3 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -88,7 +88,7 @@ export const EXPERIMENTAL_MARKET_INDICATOR_SETTINGS = boolFromEnv( // Other constants -export const MAX_ACCOUNT_NAME_SIZE = 30 +export const MAX_ACCOUNT_NAME_SIZE = 50 export const MODAL_ADD_ACCOUNTS = 'MODAL_ADD_ACCOUNTS' export const MODAL_OPERATION_DETAILS = 'MODAL_OPERATION_DETAILS' diff --git a/src/helpers/accountName.js b/src/helpers/accountName.js index dd319a5e..ce9d2d36 100644 --- a/src/helpers/accountName.js +++ b/src/helpers/accountName.js @@ -6,7 +6,8 @@ export const getAccountPlaceholderName = ( c: CryptoCurrency, index: number, isLegacy: boolean = false, -) => `${c.name} ${index + 1}${isLegacy ? ' (legacy)' : ''}` + isUnsplit: boolean = false, +) => `${c.name} ${index + 1}${isLegacy ? ' (legacy)' : ''}${isUnsplit ? ' (unsplit)' : ''}` export const getNewAccountPlaceholderName = getAccountPlaceholderName // same naming // export const getNewAccountPlaceholderName = (_c: CryptoCurrency, _index: number) => `New Account` diff --git a/src/helpers/bip32.js b/src/helpers/bip32.js index 12438290..665f4422 100644 --- a/src/helpers/bip32.js +++ b/src/helpers/bip32.js @@ -1,7 +1,24 @@ // @flow + import type { Account, AccountRaw } from '@ledgerhq/live-common/lib/types' +type SplitConfig = { + coinType: number, +} + export const isSegwitPath = (path: string): boolean => path.startsWith("49'") export const isSegwitAccount = (account: Account | AccountRaw): boolean => isSegwitPath(account.freshAddressPath) + +export const isUnsplitPath = (path: string, splitConfig: SplitConfig) => { + try { + const coinType = parseInt(path.split('/')[1], 10) + return coinType === splitConfig.coinType + } catch (e) { + return false + } +} + +export const isUnsplitAccount = (account: Account | AccountRaw, splitConfig: ?SplitConfig) => + !!splitConfig && isUnsplitPath(account.freshAddressPath, splitConfig) diff --git a/src/helpers/libcore.js b/src/helpers/libcore.js index 7c5c1913..b4148c49 100644 --- a/src/helpers/libcore.js +++ b/src/helpers/libcore.js @@ -9,13 +9,23 @@ import { SHOW_LEGACY_NEW_ACCOUNT } from 'config/constants' import type { AccountRaw, OperationRaw, OperationType } from '@ledgerhq/live-common/lib/types' import type { NJSAccount, NJSOperation } from '@ledgerhq/ledger-core/src/ledgercore_doc' -import { isSegwitAccount } from 'helpers/bip32' +import { isSegwitAccount, isUnsplitAccount } from 'helpers/bip32' import * as accountIdHelper from 'helpers/accountId' import { createCustomErrorClass, deserializeError } from './errors' import { getAccountPlaceholderName, getNewAccountPlaceholderName } from './accountName' const NoAddressesFound = createCustomErrorClass('NoAddressesFound') +// TODO: put that info inside currency itself +const SPLITTED_CURRENCIES = { + bitcoin_cash: { + coinType: 0, + }, + bitcoin_gold: { + coinType: 0, + }, +} + export function isValidAddress(core: *, currency: *, address: string): boolean { const addr = new core.NJSAddress(address, currency) return addr.isValid(address, currency) @@ -48,6 +58,7 @@ export function scanAccountsOnDevice(props: Props): Promise { ...commonParams, showNewAccount: !!SHOW_LEGACY_NEW_ACCOUNT || !currency.supportsSegwit, isSegwit: false, + isUnsplit: false, }) allAccounts = allAccounts.concat(nonSegwitAccounts) @@ -56,10 +67,32 @@ export function scanAccountsOnDevice(props: Props): Promise { ...commonParams, showNewAccount: true, isSegwit: true, + isUnsplit: false, }) allAccounts = allAccounts.concat(segwitAccounts) } + // TODO: put that info inside currency itself + if (currencyId in SPLITTED_CURRENCIES) { + const splittedAccounts = await scanAccountsOnDeviceBySegwit({ + ...commonParams, + isSegwit: false, + showNewAccount: false, + isUnsplit: true, + }) + allAccounts = allAccounts.concat(splittedAccounts) + + if (currency.supportsSegwit) { + const segwitAccounts = await scanAccountsOnDeviceBySegwit({ + ...commonParams, + showNewAccount: false, + isUnsplit: true, + isSegwit: true, + }) + allAccounts = allAccounts.concat(segwitAccounts) + } + } + return allAccounts }) } @@ -68,12 +101,15 @@ function encodeWalletName({ publicKey, currencyId, isSegwit, + isUnsplit, }: { publicKey: string, currencyId: string, isSegwit: boolean, + isUnsplit: boolean, }) { - return `${publicKey}__${currencyId}${isSegwit ? '_segwit' : ''}` + const splitConfig = isUnsplit ? SPLITTED_CURRENCIES[currencyId] || null : null + return `${publicKey}__${currencyId}${isSegwit ? '_segwit' : ''}${splitConfig ? '_unsplit' : ''}` } async function scanAccountsOnDeviceBySegwit({ @@ -82,6 +118,7 @@ async function scanAccountsOnDeviceBySegwit({ currencyId, onAccountScanned, isSegwit, + isUnsplit, showNewAccount, }: { core: *, @@ -90,17 +127,20 @@ async function scanAccountsOnDeviceBySegwit({ onAccountScanned: AccountRaw => void, isSegwit: boolean, // FIXME all segwit to change to 'purpose' showNewAccount: boolean, + isUnsplit: boolean, }): Promise { - const { coinType } = getCryptoCurrencyById(currencyId) - const { publicKey } = await hwApp.getWalletPublicKey( - `${isSegwit ? '49' : '44'}'/${coinType}'`, - false, - isSegwit, - ) - const walletName = encodeWalletName({ publicKey, currencyId, isSegwit }) + const customOpts = + isUnsplit && SPLITTED_CURRENCIES[currencyId] ? SPLITTED_CURRENCIES[currencyId] : null + const { coinType } = customOpts ? customOpts.coinType : getCryptoCurrencyById(currencyId) + + const path = `${isSegwit ? '49' : '44'}'/${coinType}'` + + const { publicKey } = await hwApp.getWalletPublicKey(path, false, isSegwit) + + const walletName = encodeWalletName({ publicKey, currencyId, isSegwit, isUnsplit }) // retrieve or create the wallet - const wallet = await getOrCreateWallet(core, walletName, currencyId, isSegwit) + const wallet = await getOrCreateWallet(core, walletName, currencyId, isSegwit, isUnsplit) const accountsCount = await wallet.getAccountCount() // recursively scan all accounts on device on the given app @@ -115,6 +155,7 @@ async function scanAccountsOnDeviceBySegwit({ accounts: [], onAccountScanned, isSegwit, + isUnsplit, showNewAccount, }) @@ -188,6 +229,7 @@ async function scanNextAccount(props: { accounts: AccountRaw[], onAccountScanned: AccountRaw => void, isSegwit: boolean, + isUnsplit: boolean, showNewAccount: boolean, }): Promise { const { @@ -200,6 +242,7 @@ async function scanNextAccount(props: { accounts, onAccountScanned, isSegwit, + isUnsplit, showNewAccount, } = props @@ -222,6 +265,7 @@ async function scanNextAccount(props: { const account = await buildAccountRaw({ njsAccount, isSegwit, + isUnsplit, accountIndex, wallet, currencyId, @@ -259,6 +303,7 @@ async function getOrCreateWallet( WALLET_IDENTIFIER: string, currencyId: string, isSegwit: boolean, + isUnsplit: boolean, ): NJSWallet { const pool = core.getPoolInstance() try { @@ -266,12 +311,18 @@ async function getOrCreateWallet( return wallet } catch (err) { const currency = await pool.getCurrency(currencyId) + const splitConfig = isUnsplit ? SPLITTED_CURRENCIES[currencyId] || null : null + const coinType = splitConfig ? splitConfig.coinType : '' const walletConfig = isSegwit ? { KEYCHAIN_ENGINE: 'BIP49_P2SH', - KEYCHAIN_DERIVATION_SCHEME: "49'/'/'//
", + KEYCHAIN_DERIVATION_SCHEME: `49'/${coinType}'/'//
`, } - : undefined + : splitConfig + ? { + KEYCHAIN_DERIVATION_SCHEME: `44'/${coinType}'/'//
`, + } + : undefined const njsWalletConfig = createWalletConfig(core, walletConfig) const wallet = await core .getPoolInstance() @@ -283,6 +334,7 @@ async function getOrCreateWallet( async function buildAccountRaw({ njsAccount, isSegwit, + isUnsplit, wallet, currencyId, core, @@ -291,6 +343,7 @@ async function buildAccountRaw({ }: { njsAccount: NJSAccount, isSegwit: boolean, + isUnsplit: boolean, wallet: NJSWallet, currencyId: string, accountIndex: number, @@ -336,6 +389,7 @@ async function buildAccountRaw({ currency, accountIndex, (currency.supportsSegwit && !isSegwit) || false, + isUnsplit, ) const rawAccount: AccountRaw = { @@ -411,6 +465,8 @@ function buildOperationRaw({ export async function syncAccount({ rawAccount, core }: { core: *, rawAccount: AccountRaw }) { const decodedAccountId = accountIdHelper.decode(rawAccount.id) + const isSegwit = isSegwitAccount(rawAccount) + const isUnsplit = isUnsplitAccount(rawAccount, SPLITTED_CURRENCIES[rawAccount.currencyId]) let njsWallet try { njsWallet = await core.getPoolInstance().getWallet(decodedAccountId.walletName) @@ -420,7 +476,8 @@ export async function syncAccount({ rawAccount, core }: { core: *, rawAccount: A core, decodedAccountId.walletName, rawAccount.currencyId, - isSegwitAccount(rawAccount), + isSegwit, + isUnsplit, ) } @@ -443,7 +500,8 @@ export async function syncAccount({ rawAccount, core }: { core: *, rawAccount: A const syncedRawAccount = await buildAccountRaw({ njsAccount, - isSegwit: isSegwitAccount(rawAccount), + isSegwit, + isUnsplit, accountIndex: rawAccount.index, wallet: njsWallet, currencyId: rawAccount.currencyId, diff --git a/static/i18n/en/app.yml b/static/i18n/en/app.yml index 2edb6b3c..89e0c339 100644 --- a/static/i18n/en/app.yml +++ b/static/i18n/en/app.yml @@ -168,6 +168,8 @@ addAccounts: editName: Edit name newAccount: New account legacyAccount: '{{accountName}} (legacy)' + legacyUnsplitAccount: '{{accountName}} (legacy) (unsplit)' + unsplitAccount: '{{accountName}} (unsplit)' noAccountToImport: No existing {{currencyName}} accounts to add success: Account successfully added to your portfolio success_plural: Accounts successfully added to your portfolio From ebb244164730701e024e5516470b5800190eb1dc Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Wed, 4 Jul 2018 18:10:43 +0200 Subject: [PATCH 4/7] add tracking to the send modal --- src/components/FeesField/GenericContainer.js | 6 +++++- src/components/Onboarding/steps/Analytics.js | 2 +- src/components/RecipientAddress/index.js | 6 +++++- src/components/base/LabelWithExternalIcon.js | 2 +- src/components/modals/Send/fields/RecipientField.js | 2 ++ src/components/modals/Send/steps/01-step-amount.js | 2 ++ src/components/modals/Send/steps/02-step-connect-device.js | 2 +- src/components/modals/Send/steps/03-step-verification.js | 2 +- src/components/modals/Send/steps/04-step-confirmation.js | 4 ++-- 9 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/components/FeesField/GenericContainer.js b/src/components/FeesField/GenericContainer.js index 164888c5..aa4a857d 100644 --- a/src/components/FeesField/GenericContainer.js +++ b/src/components/FeesField/GenericContainer.js @@ -7,11 +7,15 @@ import LabelWithExternalIcon from 'components/base/LabelWithExternalIcon' import { translate } from 'react-i18next' import { openURL } from 'helpers/linking' import { urls } from 'config/support' +import { track } from 'analytics/segment' export default translate()(({ children, t }: { children: React$Node, t: * }) => ( openURL(urls.feesMoreInfo)} + onClick={() => { + openURL(urls.feesMoreInfo) + track('Send Flow Fees Help Requested') + }} label={t('app:send.steps.amount.fees')} /> diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 1b78af73..71f1d1f6 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -6,13 +6,13 @@ import { connect } from 'react-redux' import { saveSettings } from 'actions/settings' import Box from 'components/base/Box' import Switch from 'components/base/Switch' +import FakeLink from 'components/base/FakeLink' import TrackPage from 'analytics/TrackPage' import Track from 'analytics/Track' import { openModal } from 'reducers/modals' import { MODAL_SHARE_ANALYTICS, MODAL_TECHNICAL_DATA } from 'config/constants' import ShareAnalytics from '../../modals/ShareAnalytics' import TechnicalData from '../../modals/TechnicalData' -import FakeLink from '../../base/FakeLink' import { Title, Description, FixedTopContainer, StepContainerInner } from '../helperComponents' import OnboardingFooter from '../OnboardingFooter' diff --git a/src/components/RecipientAddress/index.js b/src/components/RecipientAddress/index.js index f96205c3..598190e0 100644 --- a/src/components/RecipientAddress/index.js +++ b/src/components/RecipientAddress/index.js @@ -11,6 +11,7 @@ import { radii } from 'styles/theme' import QRCodeCameraPickerCanvas from 'components/QRCodeCameraPickerCanvas' import Box from 'components/base/Box' import Input from 'components/base/Input' +import { track } from 'analytics/segment' import IconQrCode from 'icons/QrCode' @@ -64,10 +65,13 @@ class RecipientAddress extends PureComponent { qrReaderOpened: false, } - handleClickQrCode = () => + handleClickQrCode = () => { + const { qrReaderOpened } = this.state this.setState(prev => ({ qrReaderOpened: !prev.qrReaderOpened, })) + !qrReaderOpened ? track('Send Flow QR Code Opened') : track('Send Flow QR Code Closed') + } handleOnPick = (code: string) => { const { address, ...rest } = decodeURIScheme(code) diff --git a/src/components/base/LabelWithExternalIcon.js b/src/components/base/LabelWithExternalIcon.js index 68d83a4d..8251dbf2 100644 --- a/src/components/base/LabelWithExternalIcon.js +++ b/src/components/base/LabelWithExternalIcon.js @@ -8,7 +8,7 @@ import Box from 'components/base/Box' import IconExternalLink from 'icons/ExternalLink' // can add more dynamic options if needed -export function LabelWithExternalIcon({ onClick, label }: { onClick: () => void, label: string }) { +export function LabelWithExternalIcon({ onClick, label }: { onClick: ?() => void, label: string }) { return ( {label} diff --git a/src/components/modals/Send/fields/RecipientField.js b/src/components/modals/Send/fields/RecipientField.js index c7df23ba..1313d0aa 100644 --- a/src/components/modals/Send/fields/RecipientField.js +++ b/src/components/modals/Send/fields/RecipientField.js @@ -8,6 +8,7 @@ import { urls } from 'config/support' import Box from 'components/base/Box' import LabelWithExternalIcon from 'components/base/LabelWithExternalIcon' import RecipientAddress from 'components/RecipientAddress' +import { track } from 'analytics/segment' type Props = { t: T, @@ -63,6 +64,7 @@ class RecipientField extends Component, { isVali handleRecipientAddressHelp = () => { openURL(urls.recipientAddressInfo) + track('Send Flow Recipient Address Help Requested') } render() { const { bridge, account, transaction, t, autoFocus } = this.props diff --git a/src/components/modals/Send/steps/01-step-amount.js b/src/components/modals/Send/steps/01-step-amount.js index 3461a4d7..b551f04a 100644 --- a/src/components/modals/Send/steps/01-step-amount.js +++ b/src/components/modals/Send/steps/01-step-amount.js @@ -10,6 +10,7 @@ import FormattedVal from 'components/base/FormattedVal' import Text from 'components/base/Text' import CounterValue from 'components/CounterValue' import Spinner from 'components/base/Spinner' +import TrackPage from 'analytics/TrackPage' import RecipientField from '../fields/RecipientField' import AmountField from '../fields/AmountField' @@ -34,6 +35,7 @@ export default ({ return ( + diff --git a/src/components/modals/Send/steps/02-step-connect-device.js b/src/components/modals/Send/steps/02-step-connect-device.js index 47352a2d..876ba1d1 100644 --- a/src/components/modals/Send/steps/02-step-connect-device.js +++ b/src/components/modals/Send/steps/02-step-connect-device.js @@ -11,7 +11,7 @@ import type { StepProps } from '../index' export default function StepConnectDevice({ account, onChangeAppOpened }: StepProps<*>) { return ( - + > { const { t } = this.props return ( - + {multiline(t('app:send.steps.verification.warning'))} {t('app:send.steps.verification.body')} diff --git a/src/components/modals/Send/steps/04-step-confirmation.js b/src/components/modals/Send/steps/04-step-confirmation.js index 1b28ffb8..6e308795 100644 --- a/src/components/modals/Send/steps/04-step-confirmation.js +++ b/src/components/modals/Send/steps/04-step-confirmation.js @@ -60,7 +60,7 @@ export default function StepConfirmation({ t, optimisticOperation, error }: Step const translatedErrDesc = error ? || '' : '' return ( - + @@ -88,10 +88,10 @@ export function StepConfirmationFooter({ {optimisticOperation ? ( - // TODO: actually go to operations details url ? (