diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..f97490fb --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +## What is the type of this PR? + + + +## Any background context and/or relevant tickets/issues you want to provide with? + + + +## Short description on what this PR suppose to do? + + + +## Any special conditions required for testing? + + + +## Screenshots (if appropriate) diff --git a/build/windows/app.ico b/build/windows/app.ico new file mode 100644 index 00000000..7942e513 Binary files /dev/null and b/build/windows/app.ico differ diff --git a/build/windows/installerSidebar.bmp b/build/windows/installerSidebar.bmp index 89beb76e..68a0a857 100644 Binary files a/build/windows/installerSidebar.bmp and b/build/windows/installerSidebar.bmp differ diff --git a/build/windows/uninstaller.ico b/build/windows/uninstaller.ico new file mode 100644 index 00000000..d04d483a Binary files /dev/null and b/build/windows/uninstaller.ico differ diff --git a/build/windows/uninstallerSidebar.bmp b/build/windows/uninstallerSidebar.bmp index 24170b46..d56a3f14 100644 Binary files a/build/windows/uninstallerSidebar.bmp and b/build/windows/uninstallerSidebar.bmp differ diff --git a/electron-builder.yml b/electron-builder.yml index fd198935..e65d9321 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -27,6 +27,7 @@ linux: win: artifactName: ${name}-${version}-${os}-${arch}.${ext} + icon: build/windows/app.ico certificateSubjectName: Ledger SAS certificateSha1: 7dd9acb2ef0402883c65901ebbafd06e5293d391 signingHashAlgorithms: @@ -45,6 +46,7 @@ nsis: allowToChangeInstallationDirectory: true installerIcon: build/windows/installer.ico installerSidebar: build/windows/installerSidebar.bmp + uninstallerIcon: build/windows/uninstaller.ico uninstallerSidebar: build/windows/uninstallerSidebar.bmp files: diff --git a/scripts/compile.sh b/scripts/compile.sh index d5c892d3..c91606cd 100644 --- a/scripts/compile.sh +++ b/scripts/compile.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash set -e diff --git a/scripts/dist-dir.sh b/scripts/dist-dir.sh index ccdd63ec..64097c15 100644 --- a/scripts/dist-dir.sh +++ b/scripts/dist-dir.sh @@ -1,3 +1,3 @@ -#/bin/bash +#!/bin/bash yarn compile && DEBUG=electron-builder electron-builder --dir -c.compression=store -c.mac.identity=null diff --git a/scripts/dist.sh b/scripts/dist.sh index 1f21e6c1..8650e8f3 100755 --- a/scripts/dist.sh +++ b/scripts/dist.sh @@ -1,3 +1,3 @@ -#/bin/bash +#!/bin/bash yarn compile && DEBUG=electron-builder electron-builder diff --git a/scripts/hash-utils.sh b/scripts/hash-utils.sh index 7210614a..2458428d 100644 --- a/scripts/hash-utils.sh +++ b/scripts/hash-utils.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash function GET_HASH_PATH { HASH_NAME=$1 diff --git a/scripts/install-ci-deps.sh b/scripts/install-ci-deps.sh index c0ecbae2..7b842885 100644 --- a/scripts/install-ci-deps.sh +++ b/scripts/install-ci-deps.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash source scripts/hash-utils.sh diff --git a/scripts/postinstall.sh b/scripts/postinstall.sh index 0b9faffb..5c919a72 100755 --- a/scripts/postinstall.sh +++ b/scripts/postinstall.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash source scripts/hash-utils.sh diff --git a/scripts/release.sh b/scripts/release.sh index 1bea97ab..29efdf21 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -21,4 +21,4 @@ fi # TODO check if local git HEAD is EXACTLY our remote master HEAD yarn compile -build +DEBUG=electron-builder yarn run electron-builder build --publish always diff --git a/scripts/start.sh b/scripts/start.sh index bff53db4..01a7084e 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash concurrently --raw --kill-others \ "cross-env NODE_ENV=development webpack-cli --mode development --watch --config webpack/internals.config.js" \ diff --git a/src/analytics/Track.js b/src/analytics/Track.js index 9c5d82e2..997fa783 100644 --- a/src/analytics/Track.js +++ b/src/analytics/Track.js @@ -1,3 +1,4 @@ +import logger from 'logger' import { PureComponent } from 'react' import { track } from './segment' @@ -6,9 +7,11 @@ class Track extends PureComponent<{ onUnmount?: boolean, onUpdate?: boolean, event: string, - properties?: Object, }> { componentDidMount() { + if (typeof this.props.event !== 'string') { + logger.warn('analytics Track: invalid event=', this.props.event) + } if (this.props.onMount) this.track() } componentDidUpdate() { @@ -18,7 +21,7 @@ class Track extends PureComponent<{ if (this.props.onUnmount) this.track() } track = () => { - const { event, properties } = this.props + const { event, onMount, onUnmount, onUpdate, ...properties } = this.props track(event, properties) } render() { diff --git a/src/analytics/TrackPage.js b/src/analytics/TrackPage.js index 2e18e868..f1b5537a 100644 --- a/src/analytics/TrackPage.js +++ b/src/analytics/TrackPage.js @@ -1,9 +1,9 @@ import { PureComponent } from 'react' import { page } from './segment' -class TrackPage extends PureComponent<{ category: string, name?: string, properties?: Object }> { +class TrackPage extends PureComponent<{ category: string, name?: string }> { componentDidMount() { - const { category, name, properties } = this.props + const { category, name, ...properties } = this.props page(category, name, properties) } render() { diff --git a/src/components/AccountPage/EmptyStateAccount.js b/src/components/AccountPage/EmptyStateAccount.js index b4457fb8..9dbaae0e 100644 --- a/src/components/AccountPage/EmptyStateAccount.js +++ b/src/components/AccountPage/EmptyStateAccount.js @@ -43,11 +43,11 @@ class EmptyStateAccount extends PureComponent { {t('app:account.emptyState.title')} - Make sure the + {'Make sure the'} {account.currency.name} - app is installed to receive funds. + {'app is installed to receive funds.'} ) diff --git a/src/components/ManagerPage/FlashMcu.js b/src/components/ManagerPage/FlashMcu.js index 0cb9905d..76a9b77d 100644 --- a/src/components/ManagerPage/FlashMcu.js +++ b/src/components/ManagerPage/FlashMcu.js @@ -40,8 +40,8 @@ class FlashMcu extends PureComponent { render() { return (
-

Flashing MCU

- +

{'Flashing MCU'}

+
) } diff --git a/src/components/Onboarding/helperComponents.js b/src/components/Onboarding/helperComponents.js index 5f39897b..a45ca150 100644 --- a/src/components/Onboarding/helperComponents.js +++ b/src/components/Onboarding/helperComponents.js @@ -52,17 +52,31 @@ export const OnboardingFooterWrapper = styled(Box).attrs({ border-bottom-left-radius: ${radii[1]}px; border-bottom-right-radius: ${radii[1]}px; ` +// LIVE LOGO +export function LiveLogo({ icon, ...p }: { icon: any }) { + return {icon} +} +export const LiveLogoContainer = styled(Box).attrs({ + borderRadius: '50%', + alignItems: 'center', + justifyContent: 'center', +})` + box-shadow: 0 2px 24px 0 #00000014; + width: ${p => (p.width ? p.width : 80)} + height: ${p => (p.height ? p.height : 80)} + +` // INSTRUCTION LIST type StepType = { icon: any, - desc: string, + desc: any, } -export function OptionRow({ step }: { step: StepType }) { +export function OptionRow({ step, ...p }: { step: StepType }) { const { icon, desc } = step return ( - {icon} + {icon} {desc} @@ -91,7 +105,7 @@ export function DisclaimerBox({ disclaimerNotes, ...p }: { disclaimerNotes: any - {disclaimerNotes.map(note => )} + {disclaimerNotes.map(note => )} ) diff --git a/src/components/Onboarding/steps/Finish.js b/src/components/Onboarding/steps/Finish.js index e582d708..2fb41697 100644 --- a/src/components/Onboarding/steps/Finish.js +++ b/src/components/Onboarding/steps/Finish.js @@ -3,18 +3,19 @@ import React from 'react' import { shell } from 'electron' import styled from 'styled-components' +import { i } from 'helpers/staticPath' import Box from 'components/base/Box' import Button from 'components/base/Button' import ConfettiParty from 'components/ConfettiParty' -import IconCheckCircle from 'icons/CheckCircle' +import IconCheckFull from 'icons/CheckFull' import IconSocialTwitter from 'icons/Twitter' import IconSocialReddit from 'icons/Reddit' import IconSocialGithub from 'icons/Github' import type { StepProps } from '..' -import { Title, Description } from '../helperComponents' +import { Title, Description, LiveLogo } from '../helperComponents' const ConfettiLayer = styled.div` position: absolute; @@ -55,9 +56,16 @@ export default (props: StepProps) => { - - + + } + /> + + + + {t('onboarding:finish.title')} {t('onboarding:finish.desc')} diff --git a/src/components/Onboarding/steps/Init.js b/src/components/Onboarding/steps/Init.js index ea503497..90c53095 100644 --- a/src/components/Onboarding/steps/Init.js +++ b/src/components/Onboarding/steps/Init.js @@ -13,7 +13,7 @@ import IconCheck from 'icons/Check' import IconExternalLink from 'icons/ExternalLink' import IconChevronRight from 'icons/ChevronRight' import { i } from 'helpers/staticPath' -import { Title } from '../helperComponents' +import { Title, LiveLogo } from '../helperComponents' import type { StepProps } from '..' @@ -65,9 +65,10 @@ class Init extends PureComponent { return ( - - - + } + /> {t('onboarding:init.title')} diff --git a/src/components/Onboarding/steps/NoDevice.js b/src/components/Onboarding/steps/NoDevice.js index f63ad96f..c74c336c 100644 --- a/src/components/Onboarding/steps/NoDevice.js +++ b/src/components/Onboarding/steps/NoDevice.js @@ -2,14 +2,14 @@ import React, { PureComponent } from 'react' import { shell } from 'electron' +import { i } from 'helpers/staticPath' import Box from 'components/base/Box' -import IconUser from 'icons/User' import IconCart from 'icons/Cart' import IconTruck from 'icons/Truck' import IconInfoCircle from 'icons/InfoCircle' import Button from '../../base/Button/index' -import { Title, OnboardingFooterWrapper } from '../helperComponents' +import { Title, OnboardingFooterWrapper, LiveLogo } from '../helperComponents' import { OptionFlowCard } from './Init' import type { StepProps } from '..' @@ -48,9 +48,10 @@ class NoDevice extends PureComponent { return ( - - - + } + /> {t('onboarding:noDevice.title')} diff --git a/src/components/Onboarding/steps/SelectPIN/SelectPINblue.js b/src/components/Onboarding/steps/SelectPIN/SelectPINblue.js index 21611255..e612ee73 100644 --- a/src/components/Onboarding/steps/SelectPIN/SelectPINblue.js +++ b/src/components/Onboarding/steps/SelectPIN/SelectPINblue.js @@ -1,10 +1,11 @@ // @flow import React, { PureComponent } from 'react' -import { translate } from 'react-i18next' +import { translate, Trans } from 'react-i18next' import { colors } from 'styles/theme' import { i } from 'helpers/staticPath' import Box from 'components/base/Box' +import Text from 'components/base/Text' import type { T } from 'types/common' @@ -29,7 +30,16 @@ class SelectPIN extends PureComponent { { key: 'step2', icon: {'2.'}, - desc: t('onboarding:selectPIN.initialize.instructions.blue.step2'), + desc: ( + + + {'Tap on'} + + {'Configure as new device'} + + + + ), }, { key: 'step3', diff --git a/src/components/Onboarding/steps/SelectPIN/SelectPINnano.js b/src/components/Onboarding/steps/SelectPIN/SelectPINnano.js index 9db95c4e..00a35774 100644 --- a/src/components/Onboarding/steps/SelectPIN/SelectPINnano.js +++ b/src/components/Onboarding/steps/SelectPIN/SelectPINnano.js @@ -1,10 +1,11 @@ // @flow import React, { PureComponent } from 'react' -import { translate } from 'react-i18next' +import { translate, Trans } from 'react-i18next' import { colors } from 'styles/theme' import { i } from 'helpers/staticPath' import Box from 'components/base/Box' +import Text from 'components/base/Text' import type { T } from 'types/common' @@ -34,7 +35,16 @@ class SelectPINnano extends PureComponent { { key: 'step3', icon: {'3.'}, - desc: t('onboarding:selectPIN.initialize.instructions.nano.step3'), + desc: ( + + + {'Press the right button to select'} + + {'Configure as new device'} + + + + ), }, { key: 'step4', diff --git a/src/components/Onboarding/steps/SelectPIN/SelectPINrestoreBlue.js b/src/components/Onboarding/steps/SelectPIN/SelectPINrestoreBlue.js index 0ff30312..18566798 100644 --- a/src/components/Onboarding/steps/SelectPIN/SelectPINrestoreBlue.js +++ b/src/components/Onboarding/steps/SelectPIN/SelectPINrestoreBlue.js @@ -1,10 +1,11 @@ // @flow import React, { PureComponent } from 'react' -import { translate } from 'react-i18next' +import { translate, Trans } from 'react-i18next' import { colors } from 'styles/theme' import { i } from 'helpers/staticPath' import Box from 'components/base/Box' +import Text from 'components/base/Text' import type { T } from 'types/common' @@ -29,7 +30,16 @@ class SelectPINrestoreBlue extends PureComponent { { key: 'step2', icon: {'2.'}, - desc: t('onboarding:selectPIN.restore.instructions.blue.step2'), + desc: ( + + + {'Tap on'} + + {'Restore configuration'} + + + + ), }, { key: 'step3', diff --git a/src/components/Onboarding/steps/SelectPIN/SelectPINrestoreNano.js b/src/components/Onboarding/steps/SelectPIN/SelectPINrestoreNano.js index addacd63..1d3302f8 100644 --- a/src/components/Onboarding/steps/SelectPIN/SelectPINrestoreNano.js +++ b/src/components/Onboarding/steps/SelectPIN/SelectPINrestoreNano.js @@ -1,10 +1,11 @@ // @flow import React, { PureComponent } from 'react' -import { translate } from 'react-i18next' +import { translate, Trans } from 'react-i18next' import { colors } from 'styles/theme' import { i } from 'helpers/staticPath' import Box from 'components/base/Box' +import Text from 'components/base/Text' import type { T } from 'types/common' @@ -34,7 +35,20 @@ class SelectPINrestoreNano extends PureComponent { { key: 'step3', icon: {'3.'}, - desc: t('onboarding:selectPIN.restore.instructions.nano.step3'), + desc: ( + + + {'Press the left button to cancel'} + + {'Initialize as new device?'} + + {'Press the right button to select'} + + {'Restore configuration?'} + + + + ), }, { key: 'step4', diff --git a/src/components/Onboarding/steps/Start.js b/src/components/Onboarding/steps/Start.js index c419be90..97f62d50 100644 --- a/src/components/Onboarding/steps/Start.js +++ b/src/components/Onboarding/steps/Start.js @@ -7,15 +7,18 @@ import Box from 'components/base/Box' import Button from 'components/base/Button' import type { StepProps } from '..' -import { Title } from '../helperComponents' +import { Title, LiveLogo } from '../helperComponents' export default (props: StepProps) => { const { jumpStep, t } = props return ( - - + } + /> + {t('onboarding:start.title')} @@ -205,7 +210,7 @@ class TabProfile extends PureComponent { title={t('app:settings.profile.hardResetTitle')} desc={t('app:settings.profile.hardResetDesc')} > - diff --git a/src/components/UpdateNotifier/UpdateDownloaded.js b/src/components/UpdateNotifier/UpdateDownloaded.js index 5f0cb77a..7b38f32c 100644 --- a/src/components/UpdateNotifier/UpdateDownloaded.js +++ b/src/components/UpdateNotifier/UpdateDownloaded.js @@ -35,7 +35,8 @@ const Container = styled(Box).attrs({ px: 3, bg: 'wallet', color: 'white', - mt: '-35px', + mt: '-50px', + mb: '35px', style: p => ({ transform: `translate3d(0, ${p.offset}%, 0)`, }), diff --git a/src/components/base/Button/index.js b/src/components/base/Button/index.js index 8953eb31..ed745d14 100644 --- a/src/components/base/Button/index.js +++ b/src/components/base/Button/index.js @@ -4,6 +4,7 @@ import React from 'react' import styled from 'styled-components' import { space, fontSize, fontWeight, color } from 'styled-system' import noop from 'lodash/noop' +import { track } from 'analytics/segment' import { darken, lighten, rgba } from 'styles/helpers' import fontFamily from 'styles/styled/fontFamily' @@ -171,13 +172,24 @@ type Props = { small?: boolean, padded?: boolean, isLoading?: boolean, + event?: string, + eventProperties?: Object, } const Button = (props: Props) => { - const { onClick, children, disabled, isLoading } = props + const { disabled } = props + const { onClick, children, isLoading, event, eventProperties, ...rest } = props const isClickDisabled = disabled || isLoading + const onClickHandler = e => { + if (onClick) { + if (event) { + track(event, eventProperties) + } + onClick(e) + } + } return ( - + {isLoading ? : children} ) diff --git a/static/i18n/en/onboarding.yml b/static/i18n/en/onboarding.yml index 0dec341c..8e060bc7 100644 --- a/static/i18n/en/onboarding.yml +++ b/static/i18n/en/onboarding.yml @@ -44,11 +44,11 @@ selectPIN: nano: step1: Connect the Ledger Nano S to your computer. step2: Press both buttons simultaneously as instructed on the screen. - step3: Press the right button to select Configure as new device?. # Configure as new device?. + step3: Press the right button to select <1><0>Configure as new device? step4: 'Choose a PIN code between 4 and 8 digits long, followed by the checkmark (✓).' blue: step1: Connect the Ledger Blue to your computer. - step2: Tap on Configure as new device. + step2: Tap on <1><0>Configure as new device. step3: Choose a PIN code between 4 and 8 digits long. restore: title: Choose your PIN code @@ -56,31 +56,31 @@ selectPIN: nano: step1: Connect the Ledger Nano S to your computer. step2: Press both buttons simultaneously as instructed on the screen. - step3: Press the left button to cancel Initialize as new device?. Press the right button to select Restore configuration?. # Initialize as new device? Restore configuration?. + step3: Press the left button to cancel <1><0>Initialize as new device? Press the right button to select <3><0>Restore configuration? step4: 'Choose a PIN code between 4 and 8 digits long followed by the checkmark (✓).' blue: step1: Connect the Ledger Blue to your computer. - step2: Tap on Restore configuration. # Restore configuration. + step2: Tap on <1><0>Restore configuration. step3: Choose a PIN code between 4 and 8 digits long. writeSeed: initialize: title: Save your recovery phrase desc: Your device will generate a recovery phrase of 24 words, displayed only once. nano: - step1: 'Copy the word displayed below Word #1 in position 1 on a blank Recovery sheet.' # Word #1 Recovery sheet - step2: 'Press the right button to display Word #2 and repeat the process until all 24 words are copied on the Recovery sheet.' # Word #2 Recovery sheet + step1: 'Copy the word displayed below <1><0>Word #1 in position 1 on a blank Recovery sheet.' + step2: 'Press the right button to display <1><0>Word #2 and repeat the process until all 24 words are copied on the Recovery sheet.' #Recovery sheet step3: 'Confirm your recovery phrase: select each requested word and press both buttons to validate it.' blue: step1: Copy each word of the recovery phrase on a blank Recovery sheet. Copy the words in the same order. # Recovery sheet - step2: Tap Next to move to the next words. Repeat the process until the Confirmation screen appears. # Next Confirmation + step2: Tap <1><0>Next to move to the next words. Repeat the process until the <3><0>Confirmation screen appears. step3: Type each requested word to confirm your recovery phrase. restore: title: Enter your recovery phrase desc: Copy the 24-word recovery phrase from your Recovery sheet on your device. nano: step1: Select the length of your recovery phrase. Press both buttons to continue. - step2: 'Select the first letters of Word #1 by pressing the right or left button. Press both buttons to confirm each letter.' # Word #1 - step3: 'Select Word #1 from the suggested words. Press both buttons to continue.' # Word #1 + step2: 'Select the first letters of <1><0>Word #1 by pressing the right or left button. Press both buttons to confirm each letter.' + step3: 'Select <1><0>Word #1 from the suggested words. Press both buttons to continue.' step4: Repeat the process until the last word. blue: step1: Select the length of your recovery phrase. diff --git a/static/images/ledgerlive-logo.svg b/static/images/ledgerlive-logo.svg index c8c2c60b..84b28fcb 100644 --- a/static/images/ledgerlive-logo.svg +++ b/static/images/ledgerlive-logo.svg @@ -25,4 +25,4 @@ - \ No newline at end of file +