From c935c1805c567b4555bf256ef4cec27e37d53b37 Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Tue, 3 Jul 2018 22:39:09 +0200 Subject: [PATCH 1/2] wip 2 modals for analytics details --- src/components/Onboarding/index.js | 2 + src/components/Onboarding/steps/Analytics.js | 46 ++++++-- src/components/modals/ReportBugs.js | 106 +++++++++++++++++++ src/components/modals/TechnicalData.js | 100 +++++++++++++++++ src/config/constants.js | 2 + src/reducers/onboarding.js | 2 +- static/i18n/en/app.yml | 1 + static/i18n/en/onboarding.yml | 24 ++++- 8 files changed, 272 insertions(+), 11 deletions(-) create mode 100644 src/components/modals/ReportBugs.js create mode 100644 src/components/modals/TechnicalData.js diff --git a/src/components/Onboarding/index.js b/src/components/Onboarding/index.js index 19d5790a..10399526 100644 --- a/src/components/Onboarding/index.js +++ b/src/components/Onboarding/index.js @@ -96,6 +96,7 @@ export type StepProps = { savePassword: Function, getDeviceInfo: Function, updateGenuineCheck: Function, + openModal: string => void, isLedgerNano: Function, flowType: Function, } @@ -145,6 +146,7 @@ class Onboarding extends PureComponent { onboarding, settings, updateGenuineCheck, + openModal, isLedgerNano, flowType, prevStep, diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 72705880..1dcd91c6 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -8,12 +8,17 @@ import Box from 'components/base/Box' import Switch from 'components/base/Switch' import TrackPage from 'analytics/TrackPage' import Track from 'analytics/Track' +import { openModal } from 'reducers/modals' +import { MODAL_REPORT_BUGS, MODAL_TECHNICAL_DATA } from 'config/constants' +import ReportBugs from '../../modals/ReportBugs' +import TechnicalData from '../../modals/TechnicalData' +import FakeLink from '../../base/FakeLink' import { Title, Description, FixedTopContainer, StepContainerInner } from '../helperComponents' import OnboardingFooter from '../OnboardingFooter' import type { StepProps } from '..' -const mapDispatchToProps = { saveSettings } +const mapDispatchToProps = { saveSettings, openModal } type State = { analyticsToggle: boolean, @@ -46,7 +51,12 @@ class Analytics extends PureComponent { savePassword(undefined) prevStep() } - + handleBugsModal = () => { + this.props.openModal(MODAL_REPORT_BUGS) + } + handleTechnicalDataModal = () => { + this.props.openModal(MODAL_TECHNICAL_DATA) + } render() { const { nextStep, t, onboarding } = this.props const { analyticsToggle, sentryLogsToggle } = this.state @@ -65,7 +75,19 @@ class Analytics extends PureComponent { - {t('onboarding:analytics.sentryLogs.title')} + + {t('onboarding:analytics.sentryLogs.title')} + + {t('app:common.learnMore')} + + + {t('onboarding:analytics.sentryLogs.desc')} @@ -82,7 +104,19 @@ class Analytics extends PureComponent { - {t('onboarding:analytics.shareAnalytics.title')} + + {t('onboarding:analytics.shareAnalytics.title')} + + {t('app:common.learnMore')} + + + {t('onboarding:analytics.shareAnalytics.desc')} @@ -129,9 +163,7 @@ export const AnalyticsTitle = styled(Box).attrs({ ff: 'Open Sans|SemiBold', fontSize: 4, textAlign: 'left', -})` - margin-bottom: 5px; -` +})`` const Container = styled(Box).attrs({ horizontal: true, p: 3, diff --git a/src/components/modals/ReportBugs.js b/src/components/modals/ReportBugs.js new file mode 100644 index 00000000..a35c016e --- /dev/null +++ b/src/components/modals/ReportBugs.js @@ -0,0 +1,106 @@ +// @flow +import React, { PureComponent } from 'react' +import { translate } from 'react-i18next' +import styled from 'styled-components' + +import { MODAL_REPORT_BUGS } from 'config/constants' +import Modal, { ModalBody, ModalTitle, ModalContent, ModalFooter } from 'components/base/Modal' + +import Button from 'components/base/Button' +import Box from 'components/base/Box' +import Text from 'components/base/Text' + +import type { T } from 'types/common' + +const Title = styled(Text).attrs({ + ff: 'Museo Sans', + fontSize: 5, + color: 'dark', +})`` + +type Props = { + t: T, +} +class ReportBugs extends PureComponent { + render() { + const { t } = this.props + const steps = [ + { + key: 'item1', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item1'), + }, + { + key: 'item2', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item2'), + }, + { + key: 'item3', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item3'), + }, + { + key: 'item4', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item4'), + }, + { + key: 'item5', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item5'), + }, + { + key: 'item6', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item6'), + }, + { + key: 'item7', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item7'), + }, + { + key: 'item8', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item8'), + }, + { + key: 'item9', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item9'), + }, + { + key: 'item10', + desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item10'), + }, + ] + return ( + ( + + {t('onboarding:analytics.sentryLogs.title')} + {t('onboarding:analytics.sentryLogs.desc')} + +
    {steps.map(step =>
  • {step.desc}
  • )}
+
+ + + +
+ )} + /> + ) + } +} + +export default translate()(ReportBugs) + +export const Ul = styled.ul.attrs({ + ff: 'Open Sans|Regular', +})` + margin-top: 15px; + font-size: 13px; + color: ${p => p.theme.colors.graphite}; + line-height: 1.69; +` +export const InlineDesc = styled(Box).attrs({ + ff: 'Open Sans|SemiBold', + fontSize: 4, + color: 'dark', + mx: '45px', +})`` diff --git a/src/components/modals/TechnicalData.js b/src/components/modals/TechnicalData.js new file mode 100644 index 00000000..1f65c932 --- /dev/null +++ b/src/components/modals/TechnicalData.js @@ -0,0 +1,100 @@ +// @flow +import React, { PureComponent } from 'react' +import { translate } from 'react-i18next' +import ReactMarkdown from 'react-markdown' +import styled from 'styled-components' +import network from 'api/network' + +import { MODAL_TECHNICAL_DATA } from 'config/constants' +import Modal, { ModalBody, ModalTitle, ModalContent, ModalFooter } from 'components/base/Modal' + +import Button from 'components/base/Button' +import Box from 'components/base/Box' +import GrowScroll from 'components/base/GrowScroll' +import Text from 'components/base/Text' +import Spinner from 'components/base/Spinner' +import GradientBox from 'components/GradientBox' +import IconChevronRight from 'icons/ChevronRight' +import { OptionRow } from 'components/Onboarding/helperComponents' + +import type { T } from 'types/common' + +const Title = styled(Text).attrs({ + ff: 'Museo Sans', + fontSize: 5, + color: 'dark', +})`` + +type Props = { + t: T, +} + +class TechnicalData extends PureComponent { + render() { + const { t } = this.props + + const steps = [ + { + key: 'item1', + desc: t('onboarding:analytics.technicalData.mandatoryContextual.item1'), + }, + { + key: 'item2', + desc: t('onboarding:analytics.technicalData.mandatoryContextual.item2'), + }, + { + key: 'item3', + desc: t('onboarding:analytics.technicalData.mandatoryContextual.item3'), + }, + { + key: 'item4', + desc: t('onboarding:analytics.technicalData.mandatoryContextual.item4'), + }, + { + key: 'item5', + desc: t('onboarding:analytics.technicalData.mandatoryContextual.item5'), + }, + { + key: 'item6', + desc: t('onboarding:analytics.technicalData.mandatoryContextual.item6'), + }, + ] + + return ( + ( + + {t('onboarding:analytics.technicalData.title')} + {t('onboarding:analytics.technicalData.desc')} + +
    {steps.map(step =>
  • {step.desc}
  • )}
+
+ + + +
+ )} + /> + ) + } +} + +export default translate()(TechnicalData) + +export const Ul = styled.ul.attrs({ + ff: 'Open Sans|Regular', +})` + margin-top: 15px; + font-size: 13px; + color: ${p => p.theme.colors.graphite}; + line-height: 1.69; +` +export const InlineDesc = styled(Box).attrs({ + ff: 'Open Sans|SemiBold', + fontSize: 4, + color: 'dark', + mx: '45px', +})`` diff --git a/src/config/constants.js b/src/config/constants.js index b9a4b4ce..707badf7 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -96,6 +96,8 @@ export const MODAL_RECEIVE = 'MODAL_RECEIVE' export const MODAL_SEND = 'MODAL_SEND' export const MODAL_SETTINGS_ACCOUNT = 'MODAL_SETTINGS_ACCOUNT' export const MODAL_RELEASES_NOTES = 'MODAL_RELEASES_NOTES' +export const MODAL_REPORT_BUGS = 'MODAL_REPORT_BUGS' +export const MODAL_TECHNICAL_DATA = 'MODAL_TECHNICAL_DATA' export const MODAL_DISCLAIMER = 'MODAL_DISCLAIMER' export const MODAL_DISCLAIMER_DELAY = 1 * 1000 diff --git a/src/reducers/onboarding.js b/src/reducers/onboarding.js index 6484e9a5..fb7f1603 100644 --- a/src/reducers/onboarding.js +++ b/src/reducers/onboarding.js @@ -32,7 +32,7 @@ export type OnboardingState = { const state: OnboardingState = { stepIndex: 0, // FIXME is this used at all? dup with stepName? - stepName: SKIP_ONBOARDING ? 'analytics' : 'start', + stepName: 'analytics', genuine: { pinStepPass: false, recoveryStepPass: false, diff --git a/static/i18n/en/app.yml b/static/i18n/en/app.yml index 98ece127..ac2bf5c0 100644 --- a/static/i18n/en/app.yml +++ b/static/i18n/en/app.yml @@ -7,6 +7,7 @@ common: cancel: Cancel delete: Delete continue: Continue + learnMore: Learn More skipThisStep: Skip this step chooseWalletPlaceholder: Choose a wallet... currency: Currency diff --git a/static/i18n/en/onboarding.yml b/static/i18n/en/onboarding.yml index 357b8f5d..27a611a9 100644 --- a/static/i18n/en/onboarding.yml +++ b/static/i18n/en/onboarding.yml @@ -134,9 +134,27 @@ analytics: sentryLogs: title: Report bugs desc: Automatically send reports to help Ledger fix bugs - # mandatoryContextual: - # title: Technical data - # desc: Ledger will automatically collect technical information to help improve user experience. This information is fully anonymized. + mandatoryContextual: + item1: Page visits + item2: Actions (send, receive, logout) + item3: Clicks + item4: Redirections to webpages + item5: Scrolled to end of page + item6: Install/Uninstall + item7: Number of accounts, currencies and operations + item8: Overall and page session duration + item9: Device product ID + item10: Device firmware and app versions + technicalData: + title: Report bugs + desc: Automatically send reports to help Ledger fix bugs + mandatoryContextual: + item1: Active unique users + item2: OS name + item3: OS versions + item4: Ledger Live application version + item5: App Language/Region + item6: OS Language/Region finish: title: Your device is ready! desc: Proceed to your portfolio and start adding your accounts... From 1cc9a4a62fe0bdddb46c9a52182afea7462f3774 Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Wed, 4 Jul 2018 11:25:32 +0200 Subject: [PATCH 2/2] analytics page onboarding 2 modals for additional reqs --- src/components/Onboarding/index.js | 2 +- src/components/Onboarding/steps/Analytics.js | 57 +++++++++++++------ src/components/base/Switch/index.js | 3 +- .../{ReportBugs.js => ShareAnalytics.js} | 45 +++++++-------- src/components/modals/TechnicalData.js | 43 +++----------- src/config/constants.js | 2 +- src/reducers/onboarding.js | 2 +- static/i18n/en/onboarding.yml | 12 ++-- 8 files changed, 77 insertions(+), 89 deletions(-) rename src/components/modals/{ReportBugs.js => ShareAnalytics.js} (52%) diff --git a/src/components/Onboarding/index.js b/src/components/Onboarding/index.js index 10399526..7efec2ae 100644 --- a/src/components/Onboarding/index.js +++ b/src/components/Onboarding/index.js @@ -96,7 +96,7 @@ export type StepProps = { savePassword: Function, getDeviceInfo: Function, updateGenuineCheck: Function, - openModal: string => void, + openModal: Function, isLedgerNano: Function, flowType: Function, } diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 1dcd91c6..84d95aea 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -9,8 +9,8 @@ import Switch from 'components/base/Switch' import TrackPage from 'analytics/TrackPage' import Track from 'analytics/Track' import { openModal } from 'reducers/modals' -import { MODAL_REPORT_BUGS, MODAL_TECHNICAL_DATA } from 'config/constants' -import ReportBugs from '../../modals/ReportBugs' +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' @@ -51,8 +51,8 @@ class Analytics extends PureComponent { savePassword(undefined) prevStep() } - handleBugsModal = () => { - this.props.openModal(MODAL_REPORT_BUGS) + handleShareAnalyticsModal = () => { + this.props.openModal(MODAL_SHARE_ANALYTICS) } handleTechnicalDataModal = () => { this.props.openModal(MODAL_TECHNICAL_DATA) @@ -75,18 +75,8 @@ class Analytics extends PureComponent { - + {t('onboarding:analytics.sentryLogs.title')} - - {t('app:common.learnMore')} - - {t('onboarding:analytics.sentryLogs.desc')} @@ -104,19 +94,19 @@ class Analytics extends PureComponent { - + {t('onboarding:analytics.shareAnalytics.title')} {t('app:common.learnMore')} + - {t('onboarding:analytics.shareAnalytics.desc')} @@ -131,6 +121,30 @@ class Analytics extends PureComponent { + + + + {t('onboarding:analytics.technicalData.title')} + + {t('app:common.learnMore')} + + + + {t('onboarding:analytics.technicalData.desc')} + + {t('onboarding:analytics.technicalData.mandatoryText')} + + + + + + (p.disabled ? 0.3 : 1)}; transition: 250ms linear background-color; - cursor: pointer; + cursor: ${p => (p.disabled ? 'cursor' : 'pointer')}; &:focus { outline: none; } diff --git a/src/components/modals/ReportBugs.js b/src/components/modals/ShareAnalytics.js similarity index 52% rename from src/components/modals/ReportBugs.js rename to src/components/modals/ShareAnalytics.js index a35c016e..4365ac97 100644 --- a/src/components/modals/ReportBugs.js +++ b/src/components/modals/ShareAnalytics.js @@ -3,82 +3,75 @@ import React, { PureComponent } from 'react' import { translate } from 'react-i18next' import styled from 'styled-components' -import { MODAL_REPORT_BUGS } from 'config/constants' +import { MODAL_SHARE_ANALYTICS } from 'config/constants' import Modal, { ModalBody, ModalTitle, ModalContent, ModalFooter } from 'components/base/Modal' import Button from 'components/base/Button' import Box from 'components/base/Box' -import Text from 'components/base/Text' import type { T } from 'types/common' -const Title = styled(Text).attrs({ - ff: 'Museo Sans', - fontSize: 5, - color: 'dark', -})`` - type Props = { t: T, } -class ReportBugs extends PureComponent { +class ShareAnalytics extends PureComponent { render() { const { t } = this.props - const steps = [ + const items = [ { key: 'item1', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item1'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item1'), }, { key: 'item2', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item2'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item2'), }, { key: 'item3', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item3'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item3'), }, { key: 'item4', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item4'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item4'), }, { key: 'item5', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item5'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item5'), }, { key: 'item6', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item6'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item6'), }, { key: 'item7', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item7'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item7'), }, { key: 'item8', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item8'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item8'), }, { key: 'item9', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item9'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item9'), }, { key: 'item10', - desc: t('onboarding:analytics.sentryLogs.mandatoryContextual.item10'), + desc: t('onboarding:analytics.shareAnalytics.mandatoryContextual.item10'), }, ] return ( ( - {t('onboarding:analytics.sentryLogs.title')} - {t('onboarding:analytics.sentryLogs.desc')} + {t('onboarding:analytics.shareAnalytics.title')} + {t('onboarding:analytics.shareAnalytics.desc')} -
    {steps.map(step =>
  • {step.desc}
  • )}
+
    {items.map(item =>
  • {item.desc}
  • )}
@@ -88,7 +81,7 @@ class ReportBugs extends PureComponent { } } -export default translate()(ReportBugs) +export default translate()(ShareAnalytics) export const Ul = styled.ul.attrs({ ff: 'Open Sans|Regular', diff --git a/src/components/modals/TechnicalData.js b/src/components/modals/TechnicalData.js index 1f65c932..43e4ed04 100644 --- a/src/components/modals/TechnicalData.js +++ b/src/components/modals/TechnicalData.js @@ -1,29 +1,13 @@ // @flow import React, { PureComponent } from 'react' import { translate } from 'react-i18next' -import ReactMarkdown from 'react-markdown' -import styled from 'styled-components' -import network from 'api/network' import { MODAL_TECHNICAL_DATA } from 'config/constants' import Modal, { ModalBody, ModalTitle, ModalContent, ModalFooter } from 'components/base/Modal' - import Button from 'components/base/Button' -import Box from 'components/base/Box' -import GrowScroll from 'components/base/GrowScroll' -import Text from 'components/base/Text' -import Spinner from 'components/base/Spinner' -import GradientBox from 'components/GradientBox' -import IconChevronRight from 'icons/ChevronRight' -import { OptionRow } from 'components/Onboarding/helperComponents' import type { T } from 'types/common' - -const Title = styled(Text).attrs({ - ff: 'Museo Sans', - fontSize: 5, - color: 'dark', -})`` +import { Ul, InlineDesc } from './ShareAnalytics' type Props = { t: T, @@ -33,7 +17,7 @@ class TechnicalData extends PureComponent { render() { const { t } = this.props - const steps = [ + const items = [ { key: 'item1', desc: t('onboarding:analytics.technicalData.mandatoryContextual.item1'), @@ -65,14 +49,16 @@ class TechnicalData extends PureComponent { name={MODAL_TECHNICAL_DATA} render={({ onClose }) => ( - {t('onboarding:analytics.technicalData.title')} + + {t('onboarding:analytics.technicalData.mandatoryContextual.title')} + {t('onboarding:analytics.technicalData.desc')} -
    {steps.map(step =>
  • {step.desc}
  • )}
+
    {items.map(item =>
  • {item.desc}
  • )}
@@ -83,18 +69,3 @@ class TechnicalData extends PureComponent { } export default translate()(TechnicalData) - -export const Ul = styled.ul.attrs({ - ff: 'Open Sans|Regular', -})` - margin-top: 15px; - font-size: 13px; - color: ${p => p.theme.colors.graphite}; - line-height: 1.69; -` -export const InlineDesc = styled(Box).attrs({ - ff: 'Open Sans|SemiBold', - fontSize: 4, - color: 'dark', - mx: '45px', -})`` diff --git a/src/config/constants.js b/src/config/constants.js index 707badf7..7396c0f5 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -96,7 +96,7 @@ export const MODAL_RECEIVE = 'MODAL_RECEIVE' export const MODAL_SEND = 'MODAL_SEND' export const MODAL_SETTINGS_ACCOUNT = 'MODAL_SETTINGS_ACCOUNT' export const MODAL_RELEASES_NOTES = 'MODAL_RELEASES_NOTES' -export const MODAL_REPORT_BUGS = 'MODAL_REPORT_BUGS' +export const MODAL_SHARE_ANALYTICS = 'MODAL_SHARE_ANALYTICS' export const MODAL_TECHNICAL_DATA = 'MODAL_TECHNICAL_DATA' export const MODAL_DISCLAIMER = 'MODAL_DISCLAIMER' diff --git a/src/reducers/onboarding.js b/src/reducers/onboarding.js index fb7f1603..6484e9a5 100644 --- a/src/reducers/onboarding.js +++ b/src/reducers/onboarding.js @@ -32,7 +32,7 @@ export type OnboardingState = { const state: OnboardingState = { stepIndex: 0, // FIXME is this used at all? dup with stepName? - stepName: 'analytics', + stepName: SKIP_ONBOARDING ? 'analytics' : 'start', genuine: { pinStepPass: false, recoveryStepPass: false, diff --git a/static/i18n/en/onboarding.yml b/static/i18n/en/onboarding.yml index 27a611a9..58724913 100644 --- a/static/i18n/en/onboarding.yml +++ b/static/i18n/en/onboarding.yml @@ -131,9 +131,6 @@ analytics: shareAnalytics: title: Share usage data desc: 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. - sentryLogs: - title: Report bugs - desc: Automatically send reports to help Ledger fix bugs mandatoryContextual: item1: Page visits item2: Actions (send, receive, logout) @@ -145,10 +142,15 @@ analytics: item8: Overall and page session duration item9: Device product ID item10: Device firmware and app versions + sentryLogs: + title: Report bugs + desc: Automatically send reports to help Ledger fix bugs technicalData: - title: Report bugs - desc: Automatically send reports to help Ledger fix bugs + title: Technical data * + desc: Ledger will automatically collect technical information to help improve user experience. This information is fully anonymized. + mandatoryText: '* mandatory' mandatoryContextual: + title: Technical data item1: Active unique users item2: OS name item3: OS versions