Browse Source

Merge pull request #1589 from LedgerHQ/develop

Prepare 1.2.1
master
Meriadec Pillet 6 years ago
committed by GitHub
parent
commit
e34f35f139
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      .circleci/config.yml
  2. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  3. 82
      babel.config.js
  4. 48
      package.json
  5. 50
      scripts/check-wordings.js
  6. 9
      scripts/cli/cli.sh
  7. 21
      scripts/cli/getDevice.js
  8. 106
      scripts/cli/txBetweenAccounts.js
  9. 49
      scripts/patch-appimage.sh
  10. 50
      scripts/release.sh
  11. 5
      scripts/shasums/patch-appimage-sums.txt
  12. 61
      scripts/upload-github-release-asset.sh
  13. 2
      src/__mocks__/storybook-state.js
  14. 2
      src/actions/general.js
  15. 2
      src/api/Ripple.js
  16. 46
      src/bridge/EthereumJSBridge.js
  17. 10
      src/bridge/LibcoreBridge.js
  18. 39
      src/bridge/RippleJSBridge.js
  19. 4
      src/bridge/makeMockBridge.js
  20. 2
      src/commands/debugAppInfosForCurrency.js
  21. 2
      src/commands/getAddress.js
  22. 3
      src/commands/index.js
  23. 29
      src/commands/libcoreGetFees.js
  24. 8
      src/commands/libcoreScanFromXPUB.js
  25. 66
      src/commands/libcoreSignAndBroadcast.js
  26. 16
      src/commands/libcoreSyncAccount.js
  27. 8
      src/components/AccountPage/AccountHeaderActions.js
  28. 6
      src/components/AccountPage/EmptyStateAccount.js
  29. 4
      src/components/AccountPage/index.js
  30. 8
      src/components/AdvancedOptions/BitcoinKind.js
  31. 4
      src/components/AdvancedOptions/EthereumKind.js
  32. 2
      src/components/AdvancedOptions/RippleKind.js
  33. 14
      src/components/BalanceSummary/BalanceInfos.js
  34. 2
      src/components/BalanceSummary/index.js
  35. 2
      src/components/BalanceSummary/stories.js
  36. 2
      src/components/CalculateBalance.js
  37. 2
      src/components/CounterValue/stories.js
  38. 20
      src/components/CurrentAddress/index.js
  39. 2
      src/components/DashboardPage/AccountCardListHeader.js
  40. 4
      src/components/DashboardPage/AccountCardPlaceholder.js
  41. 8
      src/components/DashboardPage/AccountsOrder.js
  42. 6
      src/components/DashboardPage/CurrentGreetings.js
  43. 8
      src/components/DashboardPage/EmptyState.js
  44. 2
      src/components/DashboardPage/SummaryDesc.js
  45. 2
      src/components/DashboardPage/index.js
  46. 14
      src/components/DevToolsPage/AccountImporter.js
  47. 4
      src/components/DeviceInteraction/components.js
  48. 15
      src/components/EnsureDeviceApp.js
  49. 4
      src/components/ExchangePage/ExchangeCard.js
  50. 4
      src/components/ExchangePage/index.js
  51. 2
      src/components/ExportLogsBtn.js
  52. 4
      src/components/FeesField/BitcoinKind.js
  53. 2
      src/components/FeesField/GenericContainer.js
  54. 2
      src/components/GenuineCheck.js
  55. 2
      src/components/GenuineCheckModal.js
  56. 2
      src/components/GlobalSearch.js
  57. 16
      src/components/IsUnlocked.js
  58. 23
      src/components/MainSideBar/index.js
  59. 12
      src/components/ManagerPage/AppsList.js
  60. 6
      src/components/ManagerPage/Dashboard.js
  61. 8
      src/components/ManagerPage/FirmwareUpdate.js
  62. 2
      src/components/ManagerPage/ManagerApp.js
  63. 4
      src/components/ManagerPage/ManagerGenuineCheck.js
  64. 6
      src/components/ManagerPage/PlugYourDevice.js
  65. 4
      src/components/ManagerPage/UpdateFirmwareButton.js
  66. 4
      src/components/Onboarding/OnboardingFooter.js
  67. 22
      src/components/Onboarding/steps/Analytics.js
  68. 6
      src/components/Onboarding/steps/Finish.js
  69. 16
      src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js
  70. 8
      src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js
  71. 20
      src/components/Onboarding/steps/GenuineCheck/index.js
  72. 10
      src/components/Onboarding/steps/Init.js
  73. 10
      src/components/Onboarding/steps/NoDevice.js
  74. 6
      src/components/Onboarding/steps/SelectDevice.js
  75. 12
      src/components/Onboarding/steps/SelectPIN/SelectPINblue.js
  76. 14
      src/components/Onboarding/steps/SelectPIN/SelectPINnano.js
  77. 12
      src/components/Onboarding/steps/SelectPIN/SelectPINrestoreBlue.js
  78. 14
      src/components/Onboarding/steps/SelectPIN/SelectPINrestoreNano.js
  79. 4
      src/components/Onboarding/steps/SelectPIN/index.js
  80. 16
      src/components/Onboarding/steps/SetPassword.js
  81. 4
      src/components/Onboarding/steps/Start.js
  82. 18
      src/components/Onboarding/steps/WriteSeed/WriteSeedBlue.js
  83. 18
      src/components/Onboarding/steps/WriteSeed/WriteSeedNano.js
  84. 26
      src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js
  85. 2
      src/components/OpenUserDataDirectoryBtn.js
  86. 2
      src/components/OperationsList/AmountCell.js
  87. 2
      src/components/OperationsList/ConfirmationCheck.js
  88. 2
      src/components/OperationsList/DateCell.js
  89. 6
      src/components/OperationsList/index.js
  90. 2
      src/components/PillsDaysCount.js
  91. 44
      src/components/QRCodeExporter.js
  92. 2
      src/components/RecipientAddress/index.js
  93. 23
      src/components/RenderError.js
  94. 2
      src/components/RequestAmount/index.js
  95. 4
      src/components/SelectAccount/index.js
  96. 5
      src/components/SelectCurrency/index.js
  97. 6
      src/components/SelectExchange.js
  98. 22
      src/components/SettingsPage/CleanButton.js
  99. 2
      src/components/SettingsPage/CounterValueSelect.js
  100. 10
      src/components/SettingsPage/DisablePasswordModal.js

11
.circleci/config.yml

@ -10,13 +10,20 @@ jobs:
<<: *defaults
steps:
- run: sudo apt-get install -y libudev-dev
- run:
name: Install latest yarn
command: |
curl -sS http://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - ;
echo "deb http://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list ;
sudo apt-get update && sudo apt-get install yarn
sudo rm /usr/local/bin/yarn # remove docker yarn
- checkout
- restore_cache:
keys:
- v10-yarn-packages-{{ checksum "yarn.lock" }}
- v11-yarn-packages-{{ checksum "yarn.lock" }}
- run: yarn install
- save_cache:
key: v10-yarn-packages-{{ checksum "yarn.lock" }}
key: v11-yarn-packages-{{ checksum "yarn.lock" }}
paths:
- node_modules
- run: yarn lint

2
.github/ISSUE_TEMPLATE/feature_request.md

@ -1,6 +1,6 @@
---
name: ✨ Feature Request
about: Any feature you find missing in Ledger Live? Discuss to suggest feature requests.
about: Any feature you find missing in Ledger Live? Discuss to suggest feature requests. For crypto asset support, please read Issue 1650.
---
- [ ] I have checked this feature was not yet requested.

82
babel.config.js

@ -1,32 +1,62 @@
const { NODE_ENV } = process.env
const { NODE_ENV, CLI } = process.env
const __TEST__ = NODE_ENV === 'test'
const __CLI__ = !!CLI
module.exports = () => ({
presets: [
[
require('@babel/preset-env'),
{
loose: true,
modules: __TEST__ ? 'commonjs' : false,
targets: {
electron: '1.8',
node: 'current',
module.exports = (api) => {
if (api) {
api.cache(true);
}
return {
presets: [
[
require('@babel/preset-env'),
{
loose: true,
modules: __TEST__ || __CLI__ ? 'commonjs' : false,
targets: {
electron: '1.8',
node: 'current',
},
},
},
],
require('@babel/preset-flow'),
require('@babel/preset-react'),
],
require('@babel/preset-flow'),
require('@babel/preset-react'),
require('@babel/preset-stage-0'),
],
plugins: [
[require('babel-plugin-module-resolver'), { root: ['src'] }],
[
require('babel-plugin-styled-components'),
{
displayName: true,
ssr: __TEST__,
},
plugins: [
[require('babel-plugin-module-resolver'), { root: ['src'] }],
[
require('babel-plugin-styled-components'),
{
displayName: true,
ssr: __TEST__,
},
],
// Stage 0
"@babel/plugin-proposal-function-bind",
// Stage 1
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-logical-assignment-operators",
["@babel/plugin-proposal-optional-chaining", { "loose": false }],
["@babel/plugin-proposal-pipeline-operator", { "proposal": "minimal" }],
["@babel/plugin-proposal-nullish-coalescing-operator", { "loose": false }],
"@babel/plugin-proposal-do-expressions",
// Stage 2
["@babel/plugin-proposal-decorators", { "legacy": true }],
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-throw-expressions",
// Stage 3
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
["@babel/plugin-proposal-class-properties", { "loose": false }],
"@babel/plugin-proposal-json-strings"
],
],
})
}
}

48
package.json

@ -13,6 +13,7 @@
"dist": "bash ./scripts/dist.sh",
"dist:dir": "bash ./scripts/dist-dir.sh",
"compile": "bash ./scripts/compile.sh",
"cli": "bash ./scripts/cli/cli.sh",
"lint": "eslint src webpack .storybook test-e2e",
"flow": "flow",
"test": "jest src",
@ -34,13 +35,13 @@
}
},
"dependencies": {
"@ledgerhq/hw-app-btc": "4.21.0",
"@ledgerhq/hw-app-eth": "^4.14.0",
"@ledgerhq/hw-app-xrp": "^4.13.0",
"@ledgerhq/hw-transport": "^4.13.0",
"@ledgerhq/hw-transport-node-hid": "4.22.0",
"@ledgerhq/ledger-core": "2.0.0-rc.7",
"@ledgerhq/live-common": "^3.7.1",
"@ledgerhq/hw-app-btc": "4.24.0",
"@ledgerhq/hw-app-eth": "^4.24.0",
"@ledgerhq/hw-app-xrp": "^4.24.0",
"@ledgerhq/hw-transport": "^4.24.0",
"@ledgerhq/hw-transport-node-hid": "4.24.0",
"@ledgerhq/ledger-core": "2.0.0-rc.8",
"@ledgerhq/live-common": "4.0.0-beta.1",
"animated": "^0.2.2",
"async": "^2.6.1",
"axios": "^0.18.0",
@ -69,6 +70,7 @@
"measure-scrollbar": "^1.1.0",
"moment": "^2.22.2",
"qrcode": "^1.2.0",
"qrloop": "^0.6.1",
"qs": "^6.5.1",
"raven": "^2.5.0",
"raven-js": "^3.24.2",
@ -114,12 +116,28 @@
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@babel/core": "7.0.0-beta.42",
"@babel/polyfill": "7.0.0-beta.42",
"@babel/preset-env": "7.0.0-beta.42",
"@babel/preset-flow": "7.0.0-beta.42",
"@babel/preset-react": "7.0.0-beta.42",
"@babel/preset-stage-0": "7.0.0-beta.42",
"@babel/core": "7.1.2",
"@babel/plugin-proposal-class-properties": "7.1.0",
"@babel/plugin-proposal-decorators": "7.1.2",
"@babel/plugin-proposal-do-expressions": "7.0.0",
"@babel/plugin-proposal-export-default-from": "7.0.0",
"@babel/plugin-proposal-export-namespace-from": "7.0.0",
"@babel/plugin-proposal-function-bind": "7.0.0",
"@babel/plugin-proposal-function-sent": "7.1.0",
"@babel/plugin-proposal-json-strings": "7.0.0",
"@babel/plugin-proposal-logical-assignment-operators": "7.0.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.0.0",
"@babel/plugin-proposal-numeric-separator": "7.0.0",
"@babel/plugin-proposal-optional-chaining": "7.0.0",
"@babel/plugin-proposal-pipeline-operator": "7.0.0",
"@babel/plugin-proposal-throw-expressions": "7.0.0",
"@babel/plugin-syntax-dynamic-import": "7.0.0",
"@babel/plugin-syntax-import-meta": "7.0.0",
"@babel/polyfill": "7.0.0",
"@babel/preset-env": "7.1.0",
"@babel/preset-flow": "7.0.0",
"@babel/preset-react": "7.0.0",
"@babel/register": "7.0.0",
"@octokit/rest": "^15.10.0",
"@storybook/addon-actions": "^3.4.7",
"@storybook/addon-knobs": "^3.4.7",
@ -167,5 +185,9 @@
"webpack-cli": "^2.0.14",
"yaml-loader": "^0.5.0"
},
"engines": {
"node": ">=8.9.0 <=8.12.0",
"yarn": "^1.10.1"
},
"private": true
}

50
scripts/check-wordings.js

@ -5,34 +5,34 @@ const { spawn } = require('child_process')
// those wordings are dynamically created, so they are detected
// as false positive
const WHITELIST = [
'app:operation.type.IN',
'app:operation.type.OUT',
'app:exchange.coinhouse',
'app:exchange.changelly',
'app:exchange.coinmama',
'app:exchange.simplex',
'app:exchange.paybis',
'app:addAccounts.accountToImportSubtitle_plural',
'app:dashboard.summary_plural',
'app:addAccounts.success_plural',
'app:addAccounts.successDescription_plural',
'app:time.since.day',
'app:time.since.week',
'app:time.since.month',
'app:time.since.year',
'app:time.day',
'app:time.week',
'app:time.month',
'app:time.year',
'app:addAccounts.cta.add_plural',
'app:manager.apps.installing',
'app:manager.apps.uninstalling',
'app:manager.apps.installSuccess',
'app:manager.apps.uninstallSuccess',
'operation.type.IN',
'operation.type.OUT',
'exchange.coinhouse',
'exchange.changelly',
'exchange.coinmama',
'exchange.simplex',
'exchange.paybis',
'addAccounts.accountToImportSubtitle_plural',
'dashboard.summary_plural',
'addAccounts.success_plural',
'addAccounts.successDescription_plural',
'time.since.day',
'time.since.week',
'time.since.month',
'time.since.year',
'time.day',
'time.week',
'time.month',
'time.year',
'addAccounts.cta.add_plural',
'manager.apps.installing',
'manager.apps.uninstalling',
'manager.apps.installSuccess',
'manager.apps.uninstallSuccess',
]
const WORDINGS = {
app: require('../static/i18n/en/app.json'),
require('../static/i18n/en/app.json'),
onboarding: require('../static/i18n/en/onboarding.json'),
// errors: require('../static/i18n/en/errors.json'),
// language: require('../static/i18n/en/language.json'),

9
scripts/cli/cli.sh

@ -0,0 +1,9 @@
#!/bin/bash
# TODO: os specific
export LEDGER_DATA_DIR="$HOME/.config/Electron"
export LEDGER_LOGS_DIRECTORY="$LEDGER_DATA_DIR/logs"
export LEDGER_LIVE_SQLITE_PATH="$LEDGER_DATA_DIR/sqlite"
export CLI=1
node -r @babel/register scripts/cli/txBetweenAccounts.js

21
scripts/cli/getDevice.js

@ -0,0 +1,21 @@
import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
export default function getDevice() {
return new Promise((resolve, reject) => {
const sub = CommNodeHid.listen({
error: err => {
sub.unsubscribe()
reject(err)
},
next: async e => {
if (!e.device) {
return
}
if (e.type === 'add') {
sub.unsubscribe()
resolve(e.device)
}
},
})
})
}

106
scripts/cli/txBetweenAccounts.js

@ -0,0 +1,106 @@
/* eslint-disable no-console */
import chalk from 'chalk'
import path from 'path'
import fs from 'fs'
import inquirer from 'inquirer'
import { createAccountModel } from '@ledgerhq/live-common/lib/models/account'
import { formatCurrencyUnit } from '@ledgerhq/live-common/lib/helpers/currencies'
import 'globals'
import withLibcore from 'helpers/withLibcore'
import { doSignAndBroadcast } from 'commands/libcoreSignAndBroadcast'
import getDevice from './getDevice'
const accountModel = createAccountModel()
async function main() {
try {
// GET ACCOUNTS
const app = await parseAppFile()
const accounts = app.accounts.map(accountModel.decode)
// GET SENDER ACCOUNT
const senderAccount = await chooseAccount(accounts, 'Choose sender account')
// GET RECIPIENT ACCOUNT
const recipientAccount = await chooseAccount(accounts, 'Choose recipient account')
// GET AMOUNT & FEE
const { amount, feePerByte } = await inquirer.prompt([
{
type: 'input',
name: 'amount',
message: 'Amount',
default: 0,
},
{
type: 'input',
name: 'feePerByte',
message: 'Fee per byte',
default: 0,
},
])
// GET DEVICE
console.log(chalk.blue(`Waiting for device...`))
const device = await getDevice()
console.log(chalk.blue(`Using device with path [${device.path}]`))
await withLibcore(async core =>
doSignAndBroadcast({
accountId: senderAccount.id,
currencyId: senderAccount.currency.id,
xpub: senderAccount.xpub,
freshAddress: senderAccount.freshAddress,
freshAddressPath: senderAccount.freshAddressPath,
index: senderAccount.index,
transaction: {
amount,
feePerByte,
recipient: recipientAccount.freshAddress,
},
deviceId: device.path,
core,
isCancelled: () => false,
onSigned: () => {
console.log(`>> signed`)
},
onOperationBroadcasted: operation => {
console.log(`>> broadcasted`, operation)
},
}),
)
} catch (err) {
console.log(`[ERROR]`, err)
}
}
async function parseAppFile() {
const appFilePath = path.resolve(process.env.LEDGER_DATA_DIR, 'app.json')
const appFileContent = fs.readFileSync(appFilePath, 'utf-8')
const parsedApp = JSON.parse(appFileContent)
return parsedApp.data
}
async function chooseAccount(accounts, msg) {
const { account } = await inquirer.prompt([
{
type: 'list',
choices: accounts.map(account => ({
name: `${account.name} | ${chalk.green(
formatCurrencyUnit(account.unit, account.balance, {
showCode: true,
}),
)}`,
value: account,
})),
name: 'account',
message: msg,
},
])
return account
}
main()

49
scripts/patch-appimage.sh

@ -0,0 +1,49 @@
#!/bin/bash
# Patch .AppImage to address libcore crash on some
# distributions, due to loading system libraries
# instead of embedded ones.
#
# see https://github.com/LedgerHQ/ledger-live-desktop/issues/1010
set -e
BASE_URL=http://mirrors.kernel.org/ubuntu/pool/main/k/krb5
PACKAGE_SUFFIX=-2build1_amd64.deb
TMP_DIR=$(mktemp -d)
LEDGER_LIVE_VERSION=$(grep version package.json | sed -E 's/.*: "(.*)",/\1/g')
cp "dist/ledger-live-desktop-$LEDGER_LIVE_VERSION-linux-x86_64.AppImage" "$TMP_DIR"
pushd "$TMP_DIR"
declare -a LIBRARIES=(
"libgssapi-krb5-2_1.16"
"libk5crypto3_1.16"
"libkrb5-3_1.16"
"libkrb5support0_1.16"
)
for PACKAGE in "${LIBRARIES[@]}"; do
curl -fOL "$BASE_URL/$PACKAGE$PACKAGE_SUFFIX"
ar p "$PACKAGE$PACKAGE_SUFFIX" data.tar.xz | tar xvJf >/dev/null - ./usr/lib/x86_64-linux-gnu/
rm "$PACKAGE$PACKAGE_SUFFIX"
done
curl -fOL "https://s3-eu-west-1.amazonaws.com/ledger-ledgerlive-resources-dev/public_resources/appimagetool-x86_64.AppImage"
cp "$OLDPWD/scripts/shasums/patch-appimage-sums.txt" .
sha512sum --quiet --check patch-appimage-sums.txt || exit 1
./ledger-live-desktop-"$LEDGER_LIVE_VERSION"-linux-x86_64.AppImage --appimage-extract
cp -a usr/lib/x86_64-linux-gnu/*.so.* squashfs-root/usr/lib
chmod +x appimagetool-x86_64.AppImage
./appimagetool-x86_64.AppImage squashfs-root "$OLDPWD/dist/ledger-live-desktop-$LEDGER_LIVE_VERSION-linux-x86_64.AppImage"
popd
MD5_SUM=$(sha512sum "dist/ledger-live-desktop-$LEDGER_LIVE_VERSION-linux-x86_64.AppImage" | cut -f1 -d\ | xxd -r -p | base64 | paste -sd "")
sed -i "s|sha512: .*|sha512: ${MD5_SUM}|g" dist/latest-linux.yml
SIZE=$(stat --printf="%s" "dist/ledger-live-desktop-$LEDGER_LIVE_VERSION-linux-x86_64.AppImage")
sed -i "s|size: .*|size: ${SIZE}|g" dist/latest-linux.yml

50
scripts/release.sh

@ -13,7 +13,9 @@ if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then
exit 0
fi
if ! git describe --exact-match --tags 2>/dev/null >/dev/null; then
GH_TAG=$(git describe --exact-match --tags 2>/dev/null || echo '')
if [[ $GH_TAG == "" ]]; then
echo "You are not on a tag. Exiting properly. (CI)"
exit 0
fi
@ -57,7 +59,6 @@ fi
# exit 1
# fi
if [[ $(uname) == 'Linux' ]]; then # only run it on one target, to prevent race conditions
runJob \
"node scripts/create-draft-release.js" \
@ -68,9 +69,48 @@ fi
runJob "yarn compile" "compiling..." "compiled" "failed to compile" "verbose"
# --------------------------------------------------------------------
# Linux: Internal process error (null)
#
# context: https://github.com/LedgerHQ/ledger-live-desktop/issues/1010
# Linux: Internal process error (null)
#
# The "fix" is not optimal, as it doesn't really solve the problem
# (electron loading system openssl before we can load our embedded one)
# Quick summary:
#
# - build without publishing
# - unpack the .AppImage
# - download reported working libs from ubuntu mirrors, put it inside
# - re-pack the .AppImage
# - checksum stuff
# - upload to gh
runJob \
"DEBUG=electron-builder electron-builder build --publish always" \
"building, packaging and publishing app..." \
"app built, packaged and published successfully" \
"DEBUG=electron-builder electron-builder build --publish never" \
"building and packaging app..." \
"app built and packaged successfully" \
"failed to build app" \
"verbose"
runJob \
"scripts/patch-appimage.sh" \
"patching AppImage..." \
"AppImage patched successfully" \
"failed to patch AppImage"
LEDGER_LIVE_VERSION=$(grep version package.json | sed -E 's/.*: "(.*)",/\1/g')
scripts/upload-github-release-asset.sh \
github_api_token="$GH_TOKEN" \
owner=LedgerHQ \
repo=ledger-live-desktop \
tag="$GH_TAG" \
filename="dist/ledger-live-desktop-$LEDGER_LIVE_VERSION-linux-x86_64.AppImage"
scripts/upload-github-release-asset.sh \
github_api_token="$GH_TOKEN" \
owner=LedgerHQ \
repo=ledger-live-desktop \
tag="$GH_TAG" \
filename="dist/latest-linux.yml"

5
scripts/shasums/patch-appimage-sums.txt

@ -0,0 +1,5 @@
bebb42401a43971cfe3e31f2c9ee4efee352ce0d29a8ccc95ca1356a58463afd4876b133d9f4295697f96b76eb21b50c1909a073db753569e8969065eb40b306 usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2.2
d7d2b38a46d65a06560241b226f61d81c4df28d56c6841dd34bb428802ace0fc80cf94de1e5117f0b85b2c69b550df61ac999184d5cfe8ecd3bea4d8394d1d21 usr/lib/x86_64-linux-gnu/libkrb5.so.3.3
b025b755eb9a64f0d03a8e92c9e4b4f95c2c506bf070cf037841ef8cdb9013e16390d0e17330f2ce8c98c3b1f05b917a3018109acfde7aab50bc9d9fa70ea12b usr/lib/x86_64-linux-gnu/libk5crypto.so.3.1
f181e41f306819c10054ff8ceebf4943858f2cd34dea5206b51141877e2f651be3c6435bb02538cbde2cc0415f38e476423a9fd6a428ca9d425e9c662483b9af usr/lib/x86_64-linux-gnu/libkrb5support.so.0.1
dd8d81d4c1485209a65a1446225428a1b919478a74fd5698aff64cb8a67992544e62455f849ad73392505707cb94739de00af5ab340a22a87bb752c3808a55d2 appimagetool-x86_64.AppImage

61
scripts/upload-github-release-asset.sh

@ -0,0 +1,61 @@
#!/usr/bin/env bash
#
# Author: Stefan Buck
# License: MIT
# https://gist.github.com/stefanbuck/ce788fee19ab6eb0b4447a85fc99f447
#
#
# This script accepts the following parameters:
#
# * owner
# * repo
# * filename
# * github_api_token
#
# Script to upload a release asset using the GitHub API v3.
#
# Example:
#
# upload-github-release-asset.sh github_api_token=TOKEN owner=stefanbuck repo=playground filename=./build.zip
#
# Check dependencies.
set -e
# Validate settings.
[ "$TRACE" ] && set -x
# shellcheck disable=SC2124
CONFIG=$@
for line in $CONFIG; do
eval "$line"
done
# Define variables.
GH_API="https://api.github.com"
# shellcheck disable=SC2154
GH_REPO="$GH_API/repos/$owner/$repo"
# shellcheck disable=SC2154
AUTH="Authorization: token $github_api_token"
# github_api_token=$GH_TOKEN owner=LedgerHQ repo=ledger-live-desktop tag=v1.2.2 filename=./dist/electron-builder-debug.yml
LATEST_RELEASE_ID=$(curl -sH "$AUTH" "$GH_API/repos/LedgerHQ/ledger-live-desktop/releases" | grep '"id":' | head -n 1 | sed -E 's/.*: (.*),/\1/')
# Validate token.
curl -o /dev/null -sH "$AUTH" "$GH_REPO" || { echo "Error: Invalid repo, token or network issue!"; exit 1; }
# Get ID of the asset based on given filename.
# shellcheck disable=SC2154
[ "$LATEST_RELEASE_ID" ] || { echo "Error: Failed to get release id"; exit 1; }
# Upload asset
echo "Uploading asset... "
# Construct url
# shellcheck disable=SC2154
GH_ASSET="https://uploads.github.com/repos/$owner/$repo/releases/$LATEST_RELEASE_ID/assets?name=$(basename "$filename")"
curl --data-binary @"$filename" -H "Authorization: token $github_api_token" -H "Content-Type: application/octet-stream" "$GH_ASSET"

2
src/__mocks__/storybook-state.js

@ -2,7 +2,7 @@ import { genStoreState } from '@ledgerhq/live-common/lib/countervalues/mock'
import {
getCryptoCurrencyById,
getFiatCurrencyByTicker,
} from '@ledgerhq/live-common/lib/helpers/currencies'
} from '@ledgerhq/live-common/lib/currencies'
export default {
countervalues: genStoreState([

2
src/actions/general.js

@ -8,7 +8,7 @@ import {
getOrderAccounts,
} from 'reducers/settings'
import { accountsSelector } from 'reducers/accounts'
import { sortAccounts } from 'helpers/accountOrdering'
import { sortAccounts } from '@ledgerhq/live-common/lib/account'
const accountsBtcBalanceSelector = createSelector(
accountsSelector,

2
src/api/Ripple.js

@ -6,7 +6,7 @@ import {
parseCurrencyUnit,
getCryptoCurrencyById,
formatCurrencyUnit,
} from '@ledgerhq/live-common/lib/helpers/currencies'
} from '@ledgerhq/live-common/lib/currencies'
const rippleUnit = getCryptoCurrencyById('ripple').units[0]

46
src/bridge/EthereumJSBridge.js

@ -8,14 +8,22 @@ import AdvancedOptions from 'components/AdvancedOptions/EthereumKind'
import throttle from 'lodash/throttle'
import flatMap from 'lodash/flatMap'
import uniqBy from 'lodash/uniqBy'
import {
getDerivationModesForCurrency,
getDerivationScheme,
runDerivationScheme,
getMandatoryEmptyAccountSkip,
} from '@ledgerhq/live-common/lib/derivation'
import {
getAccountPlaceholderName,
getNewAccountPlaceholderName,
} from '@ledgerhq/live-common/lib/account'
import type { Account, Operation } from '@ledgerhq/live-common/lib/types'
import eip55 from 'eip55'
import { apiForCurrency } from 'api/Ethereum'
import type { Tx } from 'api/Ethereum'
import { getDerivations } from 'helpers/derivations'
import getAddressCommand from 'commands/getAddress'
import signTransactionCommand from 'commands/signTransaction'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from 'helpers/accountName'
import { NotEnoughBalance, FeeNotLoaded, ETHAddressNonEIP } from 'config/errors'
import type { EditProps, WalletBridge } from './types'
@ -210,8 +218,8 @@ const EthereumBridge: WalletBridge<Transaction> = {
async function stepAddress(
index,
{ address, path: freshAddressPath, publicKey },
isStandard,
{ address, path: freshAddressPath },
derivationMode,
shouldSkipEmpty,
): { account?: Account, complete?: boolean } {
const balance = await api.getAccountBalance(address)
@ -222,19 +230,21 @@ const EthereumBridge: WalletBridge<Transaction> = {
if (finished) return { complete: true }
const freshAddress = address
const accountId = `ethereumjs:${currency.id}:${address}:${publicKey}`
const accountId = `ethereumjs:2:${currency.id}:${address}:${derivationMode}`
if (txs.length === 0 && balance.isZero()) {
// this is an empty account
if (isStandard) {
if (derivationMode === '') {
// is standard derivation
if (newAccountCount === 0) {
// first zero account will emit one account as opportunity to create a new account..
const account: $Exact<Account> = {
id: accountId,
xpub: '',
seedIdentifier: freshAddress,
freshAddress,
freshAddressPath,
name: getNewAccountPlaceholderName(currency, index),
derivationMode,
name: getNewAccountPlaceholderName({ currency, index, derivationMode }),
balance,
blockHeight: currentBlock.height,
index,
@ -258,10 +268,11 @@ const EthereumBridge: WalletBridge<Transaction> = {
const account: $Exact<Account> = {
id: accountId,
xpub: '',
seedIdentifier: freshAddress,
freshAddress,
freshAddressPath,
name: getAccountPlaceholderName(currency, index, !isStandard),
derivationMode,
name: getAccountPlaceholderName({ currency, index, derivationMode }),
balance,
blockHeight: currentBlock.height,
index,
@ -288,21 +299,22 @@ const EthereumBridge: WalletBridge<Transaction> = {
async function main() {
try {
const derivations = getDerivations(currency)
const last = derivations[derivations.length - 1]
for (const derivation of derivations) {
const isStandard = last === derivation
const derivationModes = getDerivationModesForCurrency(currency)
for (const derivationMode of derivationModes) {
let emptyCount = 0
const mandatoryEmptyAccountSkip = derivation.mandatoryEmptyAccountSkip || 0
const mandatoryEmptyAccountSkip = getMandatoryEmptyAccountSkip(derivationMode)
const derivationScheme = getDerivationScheme({ derivationMode, currency })
for (let index = 0; index < 255; index++) {
const freshAddressPath = derivation({ currency, x: index, segwit: false })
const freshAddressPath = runDerivationScheme(derivationScheme, currency, {
account: index,
})
const res = await getAddressCommand
.send({ currencyId: currency.id, devicePath: deviceId, path: freshAddressPath })
.toPromise()
const r = await stepAddress(
index,
res,
isStandard,
derivationMode,
emptyCount < mandatoryEmptyAccountSkip,
)
logger.log(

10
src/bridge/LibcoreBridge.js

@ -129,7 +129,9 @@ const LibcoreBridge: WalletBridge<Transaction> = {
libcoreSyncAccount
.send({
accountId: account.id,
freshAddressPath: account.freshAddressPath,
derivationMode: account.derivationMode,
xpub: account.xpub || '',
seedIdentifier: account.seedIdentifier,
index: account.index,
currencyId: account.currency.id,
})
@ -218,9 +220,9 @@ const LibcoreBridge: WalletBridge<Transaction> = {
.send({
accountId: account.id,
currencyId: account.currency.id,
xpub: account.xpub,
freshAddress: account.freshAddress,
freshAddressPath: account.freshAddressPath,
xpub: account.xpub || '', // FIXME only reason is to build the op id. we need to consider another id for making op id.
derivationMode: account.derivationMode,
seedIdentifier: account.seedIdentifier,
index: account.index,
transaction: serializeTransaction(transaction),
deviceId,

39
src/bridge/RippleJSBridge.js

@ -7,7 +7,15 @@ import bs58check from 'ripple-bs58check'
import { computeBinaryTransactionHash } from 'ripple-hashes'
import throttle from 'lodash/throttle'
import type { Account, Operation } from '@ledgerhq/live-common/lib/types'
import { getDerivations } from 'helpers/derivations'
import {
getDerivationModesForCurrency,
getDerivationScheme,
runDerivationScheme,
} from '@ledgerhq/live-common/lib/derivation'
import {
getAccountPlaceholderName,
getNewAccountPlaceholderName,
} from '@ledgerhq/live-common/lib/account'
import getAddress from 'commands/getAddress'
import signTransaction from 'commands/signTransaction'
import {
@ -19,7 +27,6 @@ import {
} from 'api/Ripple'
import FeesRippleKind from 'components/FeesField/RippleKind'
import AdvancedOptionsRippleKind from 'components/AdvancedOptions/RippleKind'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from 'helpers/accountName'
import {
NotEnoughBalance,
FeeNotLoaded,
@ -211,7 +218,7 @@ const txToOperation = (account: Account) => ({
}
const op: $Exact<Operation> = {
id,
id: `${account.id}-${id}-${type}`,
hash: id,
accountId: account.id,
type,
@ -289,17 +296,19 @@ const RippleJSBridge: WalletBridge<Transaction> = {
const minLedgerVersion = Number(ledgers[0])
const maxLedgerVersion = Number(ledgers[1])
const derivations = getDerivations(currency)
for (const derivation of derivations) {
const legacy = derivation !== derivations[derivations.length - 1]
const derivationModes = getDerivationModesForCurrency(currency)
for (const derivationMode of derivationModes) {
const derivationScheme = getDerivationScheme({ derivationMode, currency })
for (let index = 0; index < 255; index++) {
const freshAddressPath = derivation({ currency, x: index, segwit: false })
const { address, publicKey } = await await getAddress
const freshAddressPath = runDerivationScheme(derivationScheme, currency, {
account: index,
})
const { address } = await await getAddress
.send({ currencyId: currency.id, devicePath: deviceId, path: freshAddressPath })
.toPromise()
if (finished) return
const accountId = `ripplejs:${currency.id}:${address}:${publicKey}`
const accountId = `ripplejs:2:${currency.id}:${address}:${derivationMode}`
let info
try {
@ -316,11 +325,12 @@ const RippleJSBridge: WalletBridge<Transaction> = {
if (!info) {
// account does not exist in Ripple server
// we are generating a new account locally
if (!legacy) {
if (derivationMode === '') {
o.next({
id: accountId,
xpub: '',
name: getNewAccountPlaceholderName(currency, index),
seedIdentifier: freshAddress,
derivationMode,
name: getNewAccountPlaceholderName({ currency, index, derivationMode }),
freshAddress,
freshAddressPath,
balance: BigNumber(0),
@ -353,8 +363,9 @@ const RippleJSBridge: WalletBridge<Transaction> = {
const account: $Exact<Account> = {
id: accountId,
xpub: '',
name: getAccountPlaceholderName(currency, index, legacy),
seedIdentifier: freshAddress,
derivationMode,
name: getAccountPlaceholderName({ currency, index, derivationMode }),
freshAddress,
freshAddressPath,
balance,

4
src/bridge/makeMockBridge.js

@ -6,11 +6,11 @@ import {
genAddingOperationsInAccount,
genOperation,
} from '@ledgerhq/live-common/lib/mock/account'
import { getOperationAmountNumber } from '@ledgerhq/live-common/lib/helpers/operation'
import { getOperationAmountNumber } from '@ledgerhq/live-common/lib/operation'
import Prando from 'prando'
import { BigNumber } from 'bignumber.js'
import type { Operation } from '@ledgerhq/live-common/lib/types'
import { validateNameEdition } from 'helpers/accountName'
import { validateNameEdition } from '@ledgerhq/live-common/lib/account'
import { MOCK_DATA_SEED } from 'config/constants'
import type { WalletBridge } from './types'

2
src/commands/debugAppInfosForCurrency.js

@ -1,6 +1,6 @@
// @flow
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/currencies'
import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise'
import { withDevice } from 'helpers/deviceAccess'

2
src/commands/getAddress.js

@ -1,6 +1,6 @@
// @flow
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/currencies'
import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise'
import { withDevice } from 'helpers/deviceAccess'

3
src/commands/index.js

@ -69,8 +69,11 @@ const all: Array<Command<any, any>> = [
uninstallApp,
]
export const commandsById = {}
all.forEach(cmd => {
invariant(!all.some(c => c !== cmd && c.id === cmd.id), `duplicate command '${cmd.id}'`)
commandsById[cmd.id] = cmd
})
export default all

29
src/commands/libcoreGetFees.js

@ -4,17 +4,16 @@ import { Observable } from 'rxjs'
import { BigNumber } from 'bignumber.js'
import withLibcore from 'helpers/withLibcore'
import { createCommand, Command } from 'helpers/ipc'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/currencies'
import { getWalletName } from '@ledgerhq/live-common/lib/account'
import type { Account } from '@ledgerhq/live-common/lib/types'
import * as accountIdHelper from 'helpers/accountId'
import {
isValidAddress,
libcoreAmountToBigNumber,
bigNumberToLibcoreAmount,
getOrCreateWallet,
} from 'helpers/libcore'
import { isSegwitPath, isUnsplitPath } from 'helpers/bip32'
import { InvalidAddress } from 'config/errors'
import { splittedCurrencies } from 'config/cryptocurrencies'
type BitcoinLikeTransaction = {
// TODO we rename this Transaction concept into transactionInput
@ -24,22 +23,20 @@ type BitcoinLikeTransaction = {
}
type Input = {
accountId: string,
accountIndex: number,
transaction: BitcoinLikeTransaction,
currencyId: string,
isSegwit: boolean,
isUnsplit: boolean,
derivationMode: string,
seedIdentifier: string,
}
export const extractGetFeesInputFromAccount = (a: Account) => {
const currencyId = a.currency.id
return {
accountId: a.id,
accountIndex: a.index,
currencyId,
isSegwit: isSegwitPath(a.freshAddressPath),
isUnsplit: isUnsplitPath(a.freshAddressPath, splittedCurrencies[currencyId]),
derivationMode: a.derivationMode,
seedIdentifier: a.seedIdentifier,
}
}
@ -47,17 +44,21 @@ type Result = { totalFees: string }
const cmd: Command<Input, Result> = createCommand(
'libcoreGetFees',
({ accountId, currencyId, isSegwit, isUnsplit, accountIndex, transaction }) =>
({ currencyId, derivationMode, seedIdentifier, accountIndex, transaction }) =>
Observable.create(o => {
let unsubscribed = false
const isCancelled = () => unsubscribed
const currency = getCryptoCurrencyById(currencyId)
withLibcore(async core => {
const { walletName } = accountIdHelper.decode(accountId)
const walletName = getWalletName({
currency,
derivationMode,
seedIdentifier,
})
const njsWallet = await getOrCreateWallet(core, walletName, {
currencyId,
isSegwit,
isUnsplit,
currency,
derivationMode,
})
if (isCancelled()) return
const njsAccount = await njsWallet.getAccount(accountIndex)

8
src/commands/libcoreScanFromXPUB.js

@ -10,18 +10,18 @@ import { scanAccountsFromXPUB } from 'helpers/libcore'
type Input = {
currencyId: string,
xpub: string,
isSegwit: boolean,
isUnsplit: boolean,
derivationMode: string,
seedIdentifier: string,
}
type Result = AccountRaw
const cmd: Command<Input, Result> = createCommand(
'libcoreScanFromXPUB',
({ currencyId, xpub, isSegwit, isUnsplit }) =>
({ currencyId, xpub, derivationMode, seedIdentifier }) =>
fromPromise(
withLibcore(async core =>
scanAccountsFromXPUB({ core, currencyId, xpub, isSegwit, isUnsplit }),
scanAccountsFromXPUB({ core, currencyId, xpub, derivationMode, seedIdentifier }),
),
),
)

66
src/commands/libcoreSignAndBroadcast.js

@ -2,22 +2,21 @@
import logger from 'logger'
import { BigNumber } from 'bignumber.js'
import type { OperationRaw } from '@ledgerhq/live-common/lib/types'
import Btc from '@ledgerhq/hw-app-btc'
import { Observable } from 'rxjs'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies'
import { isSegwitPath, isUnsplitPath } from 'helpers/bip32'
import { isSegwitDerivationMode } from '@ledgerhq/live-common/lib/derivation'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/currencies'
import type { OperationRaw, CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import { getWalletName } from '@ledgerhq/live-common/lib/account'
import {
libcoreAmountToBigNumber,
bigNumberToLibcoreAmount,
getOrCreateWallet,
} from 'helpers/libcore'
import { splittedCurrencies } from 'config/cryptocurrencies'
import withLibcore from 'helpers/withLibcore'
import { createCommand, Command } from 'helpers/ipc'
import { withDevice } from 'helpers/deviceAccess'
import * as accountIdHelper from 'helpers/accountId'
type BitcoinLikeTransaction = {
amount: string,
@ -28,9 +27,9 @@ type BitcoinLikeTransaction = {
type Input = {
accountId: string,
currencyId: string,
derivationMode: string,
seedIdentifier: string,
xpub: string,
freshAddress: string,
freshAddressPath: string,
index: number,
transaction: BitcoinLikeTransaction,
deviceId: string,
@ -42,17 +41,18 @@ type Result = { type: 'signed' } | { type: 'broadcasted', operation: OperationRa
const cmd: Command<Input, Result> = createCommand(
'libcoreSignAndBroadcast',
({ accountId, currencyId, xpub, freshAddress, freshAddressPath, index, transaction, deviceId }) =>
({ accountId, currencyId, derivationMode, seedIdentifier, xpub, index, transaction, deviceId }) =>
Observable.create(o => {
let unsubscribed = false
const currency = getCryptoCurrencyById(currencyId)
const isCancelled = () => unsubscribed
withLibcore(core =>
doSignAndBroadcast({
accountId,
currencyId,
currency,
derivationMode,
seedIdentifier,
xpub,
freshAddress,
freshAddressPath,
index,
transaction,
deviceId,
@ -78,28 +78,26 @@ const cmd: Command<Input, Result> = createCommand(
async function signTransaction({
hwApp,
currencyId,
currency,
transaction,
derivationMode,
sigHashType,
supportsSegwit,
isSegwit,
hasTimestamp,
}: {
hwApp: Btc,
currencyId: string,
currency: CryptoCurrency,
transaction: *,
derivationMode: string,
sigHashType: number,
supportsSegwit: boolean,
isSegwit: boolean,
hasTimestamp: boolean,
}) {
const additionals = []
let expiryHeight
if (currencyId === 'bitcoin_cash' || currencyId === 'bitcoin_gold') additionals.push('bip143')
if (currencyId === 'zcash') expiryHeight = Buffer.from([0x00, 0x00, 0x00, 0x00])
if (currency.id === 'bitcoin_cash' || currency.id === 'bitcoin_gold') additionals.push('bip143')
if (currency.id === 'zcash') expiryHeight = Buffer.from([0x00, 0x00, 0x00, 0x00])
const rawInputs = transaction.getInputs()
const hasExtraData = currencyId === 'zcash'
const hasExtraData = currency.id === 'zcash'
const inputs = await Promise.all(
rawInputs.map(async input => {
@ -107,7 +105,7 @@ async function signTransaction({
const hexPreviousTransaction = Buffer.from(rawPreviousTransaction).toString('hex')
const previousTransaction = hwApp.splitTransaction(
hexPreviousTransaction,
supportsSegwit,
currency.supportsSegwit,
hasTimestamp,
hasExtraData,
)
@ -156,7 +154,7 @@ async function signTransaction({
outputScriptHex,
lockTime,
sigHashType,
isSegwit,
isSegwitDerivationMode(derivationMode),
initialTimestamp,
additionals,
expiryHeight,
@ -167,9 +165,10 @@ async function signTransaction({
export async function doSignAndBroadcast({
accountId,
currencyId,
derivationMode,
seedIdentifier,
currency,
xpub,
freshAddressPath,
index,
transaction,
deviceId,
@ -179,10 +178,10 @@ export async function doSignAndBroadcast({
onOperationBroadcasted,
}: {
accountId: string,
currencyId: string,
derivationMode: string,
seedIdentifier: string,
currency: CryptoCurrency,
xpub: string,
freshAddress: string,
freshAddressPath: string,
index: number,
transaction: BitcoinLikeTransaction,
deviceId: string,
@ -191,11 +190,9 @@ export async function doSignAndBroadcast({
onSigned: () => void,
onOperationBroadcasted: (optimisticOp: $Exact<OperationRaw>) => void,
}): Promise<void> {
const { walletName } = accountIdHelper.decode(accountId)
const walletName = getWalletName({ currency, seedIdentifier, derivationMode })
const isSegwit = isSegwitPath(freshAddressPath)
const isUnsplit = isUnsplitPath(freshAddressPath, splittedCurrencies[currencyId])
const njsWallet = await getOrCreateWallet(core, walletName, { currencyId, isSegwit, isUnsplit })
const njsWallet = await getOrCreateWallet(core, walletName, { currency, derivationMode })
if (isCancelled()) return
const njsAccount = await njsWallet.getAccount(index)
if (isCancelled()) return
@ -221,17 +218,14 @@ export async function doSignAndBroadcast({
const hasTimestamp = !!njsWalletCurrency.bitcoinLikeNetworkParameters.UsesTimestampedTransaction
// TODO: const timestampDelay = njsWalletCurrency.bitcoinLikeNetworkParameters.TimestampDelay
const currency = getCryptoCurrencyById(currencyId)
const signedTransaction = await withDevice(deviceId)(async transport =>
signTransaction({
hwApp: new Btc(transport),
currencyId,
currency,
transaction: builded,
sigHashType: parseInt(sigHashType, 16),
supportsSegwit: !!currency.supportsSegwit,
isSegwit: isSegwitPath(freshAddressPath),
hasTimestamp,
derivationMode,
}),
)

16
src/commands/libcoreSyncAccount.js

@ -1,6 +1,7 @@
// @flow
import type { AccountRaw } from '@ledgerhq/live-common/lib/types'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/currencies'
import { fromPromise } from 'rxjs/observable/fromPromise'
import { createCommand, Command } from 'helpers/ipc'
@ -9,15 +10,24 @@ import withLibcore from 'helpers/withLibcore'
type Input = {
accountId: string,
freshAddressPath: string,
currencyId: string,
xpub: string,
derivationMode: string,
seedIdentifier: string,
index: number,
}
type Result = { rawAccount: AccountRaw, requiresCacheFlush: boolean }
const cmd: Command<Input, Result> = createCommand('libcoreSyncAccount', accountInfos =>
fromPromise(withLibcore(core => syncAccount({ ...accountInfos, core }))),
const cmd: Command<Input, Result> = createCommand(
'libcoreSyncAccount',
({ currencyId, ...accountInfos }) =>
fromPromise(
withLibcore(core => {
const currency = getCryptoCurrencyById(currencyId)
return syncAccount({ ...accountInfos, currency, core })
}),
),
)
export default cmd

8
src/components/AccountPage/AccountHeaderActions.js

@ -7,7 +7,7 @@ import { translate } from 'react-i18next'
import styled from 'styled-components'
import type { Account } from '@ledgerhq/live-common/lib/types'
import Tooltip from 'components/base/Tooltip'
import isAccountEmpty from 'helpers/isAccountEmpty'
import { isAccountEmpty } from '@ledgerhq/live-common/lib/account'
import { MODAL_SEND, MODAL_RECEIVE, MODAL_SETTINGS_ACCOUNT } from 'config/constants'
@ -67,19 +67,19 @@ class AccountHeaderActions extends PureComponent<Props> {
<Button small primary onClick={() => openModal(MODAL_SEND, { account })}>
<Box horizontal flow={1} alignItems="center">
<IconSend size={12} />
<Box>{t('app:send.title')}</Box>
<Box>{t('send.title')}</Box>
</Box>
</Button>
<Button small primary onClick={() => openModal(MODAL_RECEIVE, { account })}>
<Box horizontal flow={1} alignItems="center">
<IconReceive size={12} />
<Box>{t('app:receive.title')}</Box>
<Box>{t('receive.title')}</Box>
</Box>
</Button>
</Fragment>
) : null}
<Tooltip render={() => t('app:account.settings.title')}>
<Tooltip render={() => t('account.settings.title')}>
<ButtonSettings onClick={() => openModal(MODAL_SETTINGS_ACCOUNT, { account })}>
<Box justifyContent="center">
<IconAccountSettings size={16} />

6
src/components/AccountPage/EmptyStateAccount.js

@ -40,9 +40,9 @@ class EmptyStateAccount extends PureComponent<Props, *> {
height="89"
/>
<Box mt={5} alignItems="center">
<Title>{t('app:account.emptyState.title')}</Title>
<Title>{t('account.emptyState.title')}</Title>
<Description mt={3} style={{ display: 'block' }}>
<Trans i18nKey="app:account.emptyState.desc">
<Trans i18nKey="account.emptyState.desc">
{'Make sure the'}
<Text ff="Open Sans|SemiBold" color="dark">
{account.currency.managerAppName}
@ -53,7 +53,7 @@ class EmptyStateAccount extends PureComponent<Props, *> {
<Button mt={5} primary onClick={() => openModal(MODAL_RECEIVE, { account })}>
<Box horizontal flow={1} alignItems="center">
<IconReceive size={12} />
<Box>{t('app:account.emptyState.buttons.receiveFunds')}</Box>
<Box>{t('account.emptyState.buttons.receiveFunds')}</Box>
</Box>
</Button>
</Box>

4
src/components/AccountPage/index.js

@ -8,7 +8,7 @@ import { Redirect } from 'react-router'
import type { Currency, Account } from '@ledgerhq/live-common/lib/types'
import type { T } from 'types/common'
import { accountSelector } from 'reducers/accounts'
import isAccountEmpty from 'helpers/isAccountEmpty'
import { isAccountEmpty } from '@ledgerhq/live-common/lib/account'
import {
counterValueCurrencySelector,
localeSelector,
@ -97,7 +97,7 @@ class AccountPage extends PureComponent<Props> {
/>
</Box>
<OperationsList account={account} title={t('app:account.lastOperations')} />
<OperationsList account={account} title={t('account.lastOperations')} />
<StickyBackToTop />
</Fragment>

8
src/components/AdvancedOptions/BitcoinKind.js

@ -15,12 +15,12 @@ type Props = {
}
export default translate()(({ isRBF, onChangeRBF, t }: Props) => (
<Spoiler title={t('app:send.steps.amount.advancedOptions')}>
<Spoiler title={t('send.steps.amount.advancedOptions')}>
<Box horizontal align="center" flow={5}>
<Box style={{ width: 200 }}>
<Label>
<span>{t('app:send.steps.amount.useRBF')}</span>
<LabelInfoTooltip ml={1} text={t('app:send.steps.amount.useRBF')} />
<span>{t('send.steps.amount.useRBF')}</span>
<LabelInfoTooltip ml={1} text={t('send.steps.amount.useRBF')} />
</Label>
</Box>
<Box grow>
@ -32,7 +32,7 @@ export default translate()(({ isRBF, onChangeRBF, t }: Props) => (
<Box horizontal align="flex-start" flow={5}>
<Box style={{ width: 200 }}>
<Label>
<span>{t('app:send.steps.amount.message')}</span>
<span>{t('send.steps.amount.message')}</span>
</Label>
</Box>
<Box grow>

4
src/components/AdvancedOptions/EthereumKind.js

@ -15,11 +15,11 @@ type Props = {
}
export default translate()(({ gasLimit, onChangeGasLimit, t }: Props) => (
<Spoiler title={t('app:send.steps.amount.advancedOptions')}>
<Spoiler title={t('send.steps.amount.advancedOptions')}>
<Box horizontal align="center" flow={5}>
<Box style={{ width: 200 }}>
<Label>
<span>{t('app:send.steps.amount.ethereumGasLimit')}</span>
<span>{t('send.steps.amount.ethereumGasLimit')}</span>
</Label>
</Box>
<Box grow>

2
src/components/AdvancedOptions/RippleKind.js

@ -33,7 +33,7 @@ class RippleKind extends Component<Props> {
<Box vertical flow={5}>
<Box grow>
<Label>
<span>{t('app:send.steps.amount.rippleTag')}</span>
<span>{t('send.steps.amount.rippleTag')}</span>
</Label>
<Input value={String(tag || '')} onChange={this.onChange} />
</Box>

14
src/components/BalanceSummary/BalanceInfos.js

@ -56,11 +56,7 @@ export function BalanceSincePercent(props: BalanceSinceProps) {
withIcon
/>
)}
{!isAvailable ? (
<PlaceholderLine dark width={60} />
) : (
<Sub>{t(`app:time.since.${since}`)}</Sub>
)}
{!isAvailable ? <PlaceholderLine dark width={60} /> : <Sub>{t(`time.since.${since}`)}</Sub>}
</Box>
)
}
@ -82,11 +78,7 @@ export function BalanceSinceDiff(props: Props) {
withIcon
/>
)}
{!isAvailable ? (
<PlaceholderLine dark width={60} />
) : (
<Sub>{t(`app:time.since.${since}`)}</Sub>
)}
{!isAvailable ? <PlaceholderLine dark width={60} /> : <Sub>{t(`time.since.${since}`)}</Sub>}
</Box>
)
}
@ -127,7 +119,7 @@ function BalanceInfos(props: Props) {
isAvailable={isAvailable}
totalBalance={totalBalance}
>
<Sub>{t('app:dashboard.totalBalance')}</Sub>
<Sub>{t('dashboard.totalBalance')}</Sub>
</BalanceTotal>
<BalanceSincePercent
alignItems="flex-end"

2
src/components/BalanceSummary/index.js

@ -3,7 +3,7 @@
import React, { Fragment } from 'react'
import { BigNumber } from 'bignumber.js'
import moment from 'moment'
import { formatShort } from '@ledgerhq/live-common/lib/helpers/currencies'
import { formatShort } from '@ledgerhq/live-common/lib/currencies'
import type { Currency, Account } from '@ledgerhq/live-common/lib/types'
import Chart from 'components/base/Chart'

2
src/components/BalanceSummary/stories.js

@ -4,7 +4,7 @@ import React from 'react'
import { storiesOf } from '@storybook/react'
import { number } from '@storybook/addon-knobs'
import { translate } from 'react-i18next'
import { getFiatCurrencyByTicker } from '@ledgerhq/live-common/lib/helpers/currencies'
import { getFiatCurrencyByTicker } from '@ledgerhq/live-common/lib/currencies'
import BalanceInfos from './BalanceInfos'

2
src/components/CalculateBalance.js

@ -6,7 +6,7 @@ import { connect } from 'react-redux'
import { BigNumber } from 'bignumber.js'
import type { Account } from '@ledgerhq/live-common/lib/types'
import { getBalanceHistorySum } from '@ledgerhq/live-common/lib/helpers/account'
import { getBalanceHistorySum } from '@ledgerhq/live-common/lib/account'
import CounterValues from 'helpers/countervalues'
import {
exchangeSettingsForAccountSelector,

2
src/components/CounterValue/stories.js

@ -1,7 +1,7 @@
// @flow
import React from 'react'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/currencies'
import { storiesOf } from '@storybook/react'
import { number } from '@storybook/addon-knobs'

20
src/components/CurrentAddress/index.js

@ -3,7 +3,7 @@
import React, { PureComponent } from 'react'
import { Trans, translate } from 'react-i18next'
import styled from 'styled-components'
import { encodeURIScheme } from '@ledgerhq/live-common/lib/helpers/currencies'
import { encodeURIScheme } from '@ledgerhq/live-common/lib/currencies'
import type { Account } from '@ledgerhq/live-common/lib/types'
import noop from 'lodash/noop'
@ -152,7 +152,7 @@ class CurrentAddress extends PureComponent<Props, { copyFeedback: boolean }> {
return (
<FooterButton
icon={<IconCopy size={16} />}
label={t('app:common.copyAddress')}
label={t('common.copyAddress')}
onClick={() => {
this.setState({ copyFeedback: true })
this._timeout = setTimeout(() => this.setState({ copyFeedback: false }), 1e3)
@ -193,17 +193,17 @@ class CurrentAddress extends PureComponent<Props, { copyFeedback: boolean }> {
<Label>
<Box>
{accountName ? (
<Trans i18nKey="app:currentAddress.for" parent="div">
<Trans i18nKey="currentAddress.for" parent="div">
{'Address for '}
<strong>{accountName}</strong>
</Trans>
) : (
t('app:currentAddress.title')
t('currentAddress.title')
)}
</Box>
</Label>
<Address>
{copyFeedback && <CopyFeedback>{t('app:common.addressCopied')}</CopyFeedback>}
{copyFeedback && <CopyFeedback>{t('common.addressCopied')}</CopyFeedback>}
{address}
</Address>
<Box horizontal flow={2} mt={2} alignItems="center" style={{ maxWidth: 320 }}>
@ -217,19 +217,17 @@ class CurrentAddress extends PureComponent<Props, { copyFeedback: boolean }> {
ff="Open Sans"
>
{isAddressVerified === null
? t('app:currentAddress.messageIfUnverified', { currencyName })
? t('currentAddress.messageIfUnverified', { currencyName })
: isAddressVerified
? t('app:currentAddress.messageIfAccepted', { currencyName })
: t('app:currentAddress.messageIfSkipped', { currencyName })}
? t('currentAddress.messageIfAccepted', { currencyName })
: t('currentAddress.messageIfSkipped', { currencyName })}
</Box>
</Box>
<Footer>
{isAddressVerified !== null ? (
<FooterButton
icon={<IconRecheck size={16} />}
label={
isAddressVerified === false ? t('app:common.verify') : t('app:common.reverify')
}
label={isAddressVerified === false ? t('common.verify') : t('common.reverify')}
onClick={onVerify}
/>
) : null}

2
src/components/DashboardPage/AccountCardListHeader.js

@ -20,7 +20,7 @@ class AccountCardListHeader extends PureComponent<Props> {
return (
<Box horizontal alignItems="flex-end">
<Text color="dark" ff="Museo Sans" fontSize={6} data-e2e="dashboard_AccountCount">
{t('app:dashboard.accounts.title', { count: accountsLength })}
{t('dashboard.accounts.title', { count: accountsLength })}
</Text>
<Box ml="auto" horizontal flow={1}>
<AccountsOrder />

4
src/components/DashboardPage/AccountCardPlaceholder.js

@ -44,10 +44,10 @@ class AccountCardPlaceholder extends PureComponent<{
textAlign="center"
style={{ maxWidth: 150 }}
>
{t('app:dashboard.emptyAccountTile.desc')}
{t('dashboard.emptyAccountTile.desc')}
</Box>
<Button primary onClick={this.onAddAccounts}>
{t('app:dashboard.emptyAccountTile.createAccount')}
{t('dashboard.emptyAccountTile.createAccount')}
</Button>
</Wrapper>
)

8
src/components/DashboardPage/AccountsOrder.js

@ -91,11 +91,11 @@ class AccountsOrder extends Component<Props> {
return [
{
key: 'name',
label: t('app:dashboard.accountsOrder.name'),
label: t('dashboard.accountsOrder.name'),
},
{
key: 'balance',
label: t('app:dashboard.accountsOrder.balance'),
label: t('dashboard.accountsOrder.balance'),
},
].map(item => ({
...item,
@ -141,7 +141,7 @@ class AccountsOrder extends Component<Props> {
>
<Track onUpdate event="ChangeSort" orderAccounts={orderAccounts} />
<Text ff="Open Sans|SemiBold" fontSize={4}>
{t('app:common.sortBy')}
{t('common.sortBy')}
</Text>
<Box
alignItems="center"
@ -152,7 +152,7 @@ class AccountsOrder extends Component<Props> {
horizontal
>
<Text color="dark">
{t(`app:dashboard.accountsOrder.${this.getCurrentValue() || 'balance'}`)}
{t(`dashboard.accountsOrder.${this.getCurrentValue() || 'balance'}`)}
</Text>
<IconAngleDown size={16} />
</Box>

6
src/components/DashboardPage/CurrentGreetings.js

@ -10,11 +10,11 @@ const getCurrentGreetings = () => {
const afternoon_breakpoint = 12
const evening_breakpoint = 17
if (localTimeHour >= afternoon_breakpoint && localTimeHour < evening_breakpoint) {
return 'app:dashboard.greeting.afternoon'
return 'dashboard.greeting.afternoon'
} else if (localTimeHour >= evening_breakpoint) {
return 'app:dashboard.greeting.evening'
return 'dashboard.greeting.evening'
}
return 'app:dashboard.greeting.morning'
return 'dashboard.greeting.morning'
}
class CurrentGettings extends PureComponent<{ t: T }> {

8
src/components/DashboardPage/EmptyState.js

@ -45,9 +45,9 @@ class EmptyState extends PureComponent<Props, *> {
height="157"
/>
<Box mt={5} alignItems="center">
<Title data-e2e="dashboard_empty_title">{t('app:emptyState.dashboard.title')}</Title>
<Title data-e2e="dashboard_empty_title">{t('emptyState.dashboard.title')}</Title>
<Description mt={3} style={{ maxWidth: 600 }}>
{t('app:emptyState.dashboard.desc')}
{t('emptyState.dashboard.desc')}
</Description>
<Box mt={5} horizontal style={{ width: 300 }} flow={3} justify="center">
<Button
@ -56,7 +56,7 @@ class EmptyState extends PureComponent<Props, *> {
onClick={this.handleInstallApp}
data-e2e="dashboard_empty_OpenManager"
>
{t('app:emptyState.dashboard.buttons.installApp')}
{t('emptyState.dashboard.buttons.installApp')}
</Button>
<Button
outline
@ -64,7 +64,7 @@ class EmptyState extends PureComponent<Props, *> {
onClick={() => openModal(MODAL_ADD_ACCOUNTS)}
data-e2e="dashboard_empty_AddAccounts"
>
{t('app:emptyState.dashboard.buttons.addAccount')}
{t('emptyState.dashboard.buttons.addAccount')}
</Button>
</Box>
</Box>

2
src/components/DashboardPage/SummaryDesc.js

@ -18,7 +18,7 @@ class SummaryDesc extends PureComponent<{
ff="Museo Sans|Light"
data-e2e="dashboard_accountsSummaryDesc"
>
{t('app:dashboard.summary', { count: totalAccounts })}
{t('dashboard.summary', { count: totalAccounts })}
</Text>
)
}

2
src/components/DashboardPage/index.js

@ -129,7 +129,7 @@ class DashboardPage extends PureComponent<Props> {
<OperationsList
onAccountClick={this.onAccountClick}
accounts={accounts}
title={t('app:dashboard.recentActivity')}
title={t('dashboard.recentActivity')}
withAccount
/>
)}

14
src/components/DevToolsPage/AccountImporter.js

@ -21,7 +21,6 @@ import SelectCurrency from 'components/SelectCurrency'
import { CurrencyCircleIcon } from 'components/base/CurrencyBadge'
import { idleCallback } from 'helpers/promise'
import { splittedCurrencies } from 'config/cryptocurrencies'
import scanFromXPUB from 'commands/libcoreScanFromXPUB'
@ -80,12 +79,19 @@ class AccountImporter extends PureComponent<Props, State> {
try {
const { currency, xpub, isSegwit, isUnsplit } = this.state
invariant(currency, 'no currency')
const derivationMode = isSegwit
? isUnsplit
? 'segwit_unsplit'
: 'segwit'
: isUnsplit
? 'unsplit'
: ''
const rawAccount = await scanFromXPUB
.send({
seedIdentifier: 'dev_tool',
currencyId: currency.id,
xpub,
isSegwit,
isUnsplit,
derivationMode,
})
.toPromise()
const account = decodeAccount(rawAccount)
@ -107,7 +113,7 @@ class AccountImporter extends PureComponent<Props, State> {
render() {
const { currency, xpub, isSegwit, isUnsplit, status, account, error } = this.state
const supportsSplit = !!currency && !!splittedCurrencies[currency.id]
const supportsSplit = !!currency && !!currency.forkedFrom
return (
<Card title="Import from xpub" flow={3}>
{status === 'idle' ? (

4
src/components/DeviceInteraction/components.js

@ -144,11 +144,11 @@ export const ErrorDescContainer = translate()(
<Box ml="auto" horizontal flow={2}>
{!!errorHelpURL && (
<FakeLink underline color="alertRed" onClick={() => openURL(errorHelpURL)}>
{t('app:common.help')}
{t('common.help')}
</FakeLink>
)}
<FakeLink underline color="alertRed" onClick={onRetry}>
{t('app:common.retry')}
{t('common.retry')}
</FakeLink>
</Box>
</Box>

15
src/components/EnsureDeviceApp.js

@ -10,8 +10,11 @@ import { getCryptoCurrencyIcon } from '@ledgerhq/live-common/lib/react'
import logger from 'logger'
import getAddress from 'commands/getAddress'
import { createCancelablePolling } from 'helpers/promise'
import { standardDerivation } from 'helpers/derivations'
import { isSegwitPath } from 'helpers/bip32'
import {
isSegwitDerivationMode,
getDerivationScheme,
runDerivationScheme,
} from '@ledgerhq/live-common/lib/derivation'
import DeviceInteraction from 'components/DeviceInteraction'
import Text from 'components/base/Text'
@ -74,7 +77,7 @@ class EnsureDeviceApp extends Component<{
const cur = account ? account.currency : currency
invariant(cur, 'No currency given')
return (
<Trans i18nKey="app:deviceConnect.step2.open" parent="div">
<Trans i18nKey="deviceConnect.step2.open" parent="div">
{'Open the '}
<Bold>{cur.managerAppName}</Bold>
{' app on your device'}
@ -94,7 +97,7 @@ class EnsureDeviceApp extends Component<{
{
id: 'device',
title: (
<Trans i18nKey="app:deviceConnect.step1.connect" parent="div">
<Trans i18nKey="deviceConnect.step1.connect" parent="div">
{'Connect and unlock your '}
<Bold>{'Ledger device'}</Bold>
</Trans>
@ -122,8 +125,8 @@ async function getAddressFromAccountOrCurrency(device, account, currency) {
currencyId: currency.id,
path: account
? account.freshAddressPath
: standardDerivation({ currency, segwit: false, x: 0 }),
segwit: account ? isSegwitPath(account.freshAddressPath) : false,
: runDerivationScheme(getDerivationScheme({ currency, derivationMode: '' }), currency),
segwit: account ? isSegwitDerivationMode(account.derivationMode) : false,
})
.toPromise()
return address

4
src/components/ExchangePage/ExchangeCard.js

@ -31,9 +31,9 @@ export default class ExchangeCard extends PureComponent<{ t: T, card: CardType }
{logo}
</Box>
<Box shrink ff="Open Sans|Regular" fontSize={4} flow={3}>
<Box>{t(`app:exchange.${id}`)}</Box>
<Box>{t(`exchange.${id}`)}</Box>
<Box horizontal align="center" color="wallet" flow={1}>
<FakeLink onClick={this.onClick}>{t('app:exchange.visitWebsite')}</FakeLink>
<FakeLink onClick={this.onClick}>{t('exchange.visitWebsite')}</FakeLink>
<ExternalLinkIcon size={14} />
</Box>
</Box>

4
src/components/ExchangePage/index.js

@ -86,10 +86,10 @@ class ExchangePage extends PureComponent<Props> {
<Box pb={6} selectable>
<TrackPage category="Exchange" />
<Box ff="Museo Sans|Regular" fontSize={7} color="dark">
{t('app:exchange.title')}
{t('exchange.title')}
</Box>
<Box ff="Museo Sans|Light" fontSize={5} mb={5}>
{t('app:exchange.desc')}
{t('exchange.desc')}
</Box>
<Box flow={3}>{cards.map(card => <ExchangeCard key={card.key} t={t} card={card} />)}</Box>
</Box>

2
src/components/ExportLogsBtn.js

@ -78,7 +78,7 @@ class ExportLogsBtn extends Component<{
<KeyHandler keyValue="e" onKeyHandle={this.onKeyHandle} />
) : (
<Button small primary event="ExportLogs" onClick={this.handleExportLogs}>
{t('app:settings.exportLogs.btn')}
{t('settings.exportLogs.btn')}
</Button>
)
}

4
src/components/FeesField/BitcoinKind.js

@ -148,9 +148,7 @@ class FeesField extends Component<OwnProps, State> {
loading={!feePerByte && !error}
error={!feePerByte && error ? new FeeNotLoaded() : null}
renderRight={
<InputRight>
{t('app:send.steps.amount.unitPerByte', { unit: satoshi.code })}
</InputRight>
<InputRight>{t('send.steps.amount.unitPerByte', { unit: satoshi.code })}</InputRight>
}
allowZero
/>

2
src/components/FeesField/GenericContainer.js

@ -16,7 +16,7 @@ export default translate()(({ children, t }: { children: React$Node, t: * }) =>
openURL(urls.feesMoreInfo)
track('Send Flow Fees Help Requested')
}}
label={t('app:send.steps.amount.fees')}
label={t('send.steps.amount.fees')}
/>
<Box horizontal flow={5}>
{children}

2
src/components/GenuineCheck.js

@ -124,7 +124,7 @@ class GenuineCheck extends PureComponent<Props> {
{
id: 'device',
title: (
<Trans i18nKey="app:deviceConnect.step1.connect" parent="div">
<Trans i18nKey="deviceConnect.step1.connect" parent="div">
{'Connect and unlock your '}
<Bold>{'Ledger device'}</Bold>
</Trans>

2
src/components/GenuineCheckModal.js

@ -20,7 +20,7 @@ class GenuineCheckModal extends PureComponent<Props> {
const { t, onSuccess, onFail, onUnavailable } = this.props
return (
<ModalBody onClose={onClose}>
<ModalTitle>{t('app:genuinecheck.modal.title')}</ModalTitle>
<ModalTitle>{t('genuinecheck.modal.title')}</ModalTitle>
<ModalContent>
<GenuineCheck onSuccess={onSuccess} onFail={onFail} onUnavailable={onUnavailable} />
</ModalContent>

2
src/components/GlobalSearch.js

@ -66,7 +66,7 @@ class GlobalSearch extends PureComponent<Props, State> {
<IconSearch size={16} />
</Box>
<Input
placeholder={t('app:common.search')}
placeholder={t('common.search')}
innerRef={input => (this._input = input)}
onBlur={this.handleBlur}
onFocus={this.handleFocus}

16
src/components/IsUnlocked.js

@ -161,17 +161,17 @@ class IsUnlocked extends Component<Props, State> {
/>
}
/>
<PageTitle>{t('app:common.lockScreen.title')}</PageTitle>
<PageTitle>{t('common.lockScreen.title')}</PageTitle>
<LockScreenDesc>
{t('app:common.lockScreen.subTitle')}
{t('common.lockScreen.subTitle')}
<br />
{t('app:common.lockScreen.description')}
{t('common.lockScreen.description')}
</LockScreenDesc>
<Box horizontal align="center">
<Box style={{ width: 280 }}>
<InputPassword
autoFocus
placeholder={t('app:common.lockScreen.inputPlaceholder')}
placeholder={t('common.lockScreen.inputPlaceholder')}
type="password"
onChange={this.handleChangeInput('password')}
value={inputValue.password}
@ -187,7 +187,7 @@ class IsUnlocked extends Component<Props, State> {
</Box>
</Box>
<Button type="button" mt={3} small onClick={this.handleOpenHardResetModal}>
{t('app:common.lockScreen.lostPassword')}
{t('common.lockScreen.lostPassword')}
</Button>
</Box>
</form>
@ -199,9 +199,9 @@ class IsUnlocked extends Component<Props, State> {
onClose={this.handleCloseHardResetModal}
onReject={this.handleCloseHardResetModal}
onConfirm={this.handleHardReset}
confirmText={t('app:common.reset')}
title={t('app:settings.hardResetModal.title')}
desc={t('app:settings.hardResetModal.desc')}
confirmText={t('common.reset')}
title={t('settings.hardResetModal.title')}
desc={t('settings.hardResetModal.desc')}
renderIcon={this.hardResetIconRender}
/>
</Box>

23
src/components/MainSideBar/index.js

@ -90,7 +90,7 @@ class MainSideBar extends PureComponent<Props> {
ADD_ACCOUNT_EMPTY_STATE = (
<Box relative pr={3}>
<img style={{ position: 'absolute', top: -10, right: 5 }} alt="" src={i('arrow-add.svg')} />
{this.props.t('app:emptyState.sidebar.text')}
{this.props.t('emptyState.sidebar.text')}
</Box>
)
@ -107,10 +107,7 @@ class MainSideBar extends PureComponent<Props> {
const { pathname } = location
const addAccountButton = (
<AddAccountButton
tooltipText={t('app:addAccounts.title')}
onClick={this.handleOpenImportModal}
/>
<AddAccountButton tooltipText={t('addAccounts.title')} onClick={this.handleOpenImportModal} />
)
return (
@ -118,9 +115,9 @@ class MainSideBar extends PureComponent<Props> {
<TopGradient />
<GrowScroll>
<Space of={70} />
<SideBarList title={t('app:sidebar.menu')}>
<SideBarList title={t('sidebar.menu')}>
<SideBarListItem
label={t('app:dashboard.title')}
label={t('dashboard.title')}
icon={IconPieChart}
iconActiveColor="wallet"
onClick={this.handleClickDashboard}
@ -128,28 +125,28 @@ class MainSideBar extends PureComponent<Props> {
hasNotif={updateStatus === 'downloaded'}
/>
<SideBarListItem
label={t('app:send.title')}
label={t('send.title')}
icon={IconSend}
iconActiveColor="wallet"
onClick={this.handleOpenSendModal}
disabled={accounts.length === 0}
/>
<SideBarListItem
label={t('app:receive.title')}
label={t('receive.title')}
icon={IconReceive}
iconActiveColor="wallet"
onClick={this.handleOpenReceiveModal}
disabled={accounts.length === 0}
/>
<SideBarListItem
label={t('app:sidebar.manager')}
label={t('sidebar.manager')}
icon={IconManager}
iconActiveColor="wallet"
onClick={this.handleClickManager}
isActive={pathname === '/manager'}
/>
<SideBarListItem
label={t('app:sidebar.exchange')}
label={t('sidebar.exchange')}
icon={IconExchange}
iconActiveColor="wallet"
onClick={this.handleClickExchange}
@ -158,7 +155,7 @@ class MainSideBar extends PureComponent<Props> {
{developerMode && (
<KeyboardContent sequence="DEVTOOLS">
<SideBarListItem
label={t('app:sidebar.developer')}
label={t('sidebar.developer')}
icon={IconDev}
iconActiveColor="wallet"
onClick={this.handleClickDev}
@ -169,7 +166,7 @@ class MainSideBar extends PureComponent<Props> {
</SideBarList>
<Space of={40} />
<SideBarList
title={t('app:sidebar.accounts', { count: accounts.length })}
title={t('sidebar.accounts', { count: accounts.length })}
titleRight={addAccountButton}
emptyState={this.ADD_ACCOUNT_EMPTY_STATE}
>

12
src/components/ManagerPage/AppsList.js

@ -214,7 +214,7 @@ class AppsList extends PureComponent<Props, State> {
</ModalTitle>
<ModalContent>
<Text ff="Museo Sans|Regular" fontSize={6} color="dark">
{t(`app:manager.apps.${mode}`, { app })}
{t(`manager.apps.${mode}`, { app })}
</Text>
<Box mt={6}>
<Progress style={{ width: '100%' }} infinite />
@ -256,7 +256,7 @@ class AppsList extends PureComponent<Props, State> {
</ModalContent>
<ModalFooter horizontal justifyContent="flex-end" style={{ width: '100%' }}>
<Button primary onClick={this.handleCloseModal}>
{t('app:common.close')}
{t('common.close')}
</Button>
</ModalFooter>
</Fragment>
@ -275,7 +275,7 @@ class AppsList extends PureComponent<Props, State> {
style={{ maxWidth: 350 }}
>
{t(
`app:manager.apps.${
`manager.apps.${
mode === 'installing' ? 'installSuccess' : 'uninstallSuccess'
}`,
{ app },
@ -284,7 +284,7 @@ class AppsList extends PureComponent<Props, State> {
</ModalContent>
<ModalFooter horizontal justifyContent="flex-end" style={{ width: '100%' }}>
<Button primary onClick={this.handleCloseModal}>
{t('app:common.close')}
{t('common.close')}
</Button>
</ModalFooter>
</Fragment>
@ -342,11 +342,11 @@ class AppsList extends PureComponent<Props, State> {
<Box flow={6}>
<Box>
<Box mb={4} color="dark" ff="Museo Sans" fontSize={5} flow={2} horizontal align="center">
<span style={{ lineHeight: 1 }}>{t('app:manager.apps.all')}</span>
<span style={{ lineHeight: 1 }}>{t('manager.apps.all')}</span>
<Tooltip
render={() => (
<Box ff="Open Sans|SemiBold" fontSize={2}>
{t('app:manager.apps.help')}
{t('manager.apps.help')}
</Box>
)}
>

6
src/components/ManagerPage/Dashboard.js

@ -27,14 +27,14 @@ const Dashboard = ({ device, deviceInfo, t, handleHelpRequest }: Props) => (
<TrackPage category="Manager" name="Dashboard" />
<Box>
<Text ff="Museo Sans|Regular" fontSize={7} color="dark">
{t('app:manager.title')}
{t('manager.title')}
</Text>
<Box horizontal>
<Text ff="Museo Sans|Light" fontSize={5}>
{t('app:manager.subtitle')}
{t('manager.subtitle')}
</Text>
<HelpLink onClick={handleHelpRequest}>
<div style={{ textDecoration: 'underline' }}>{t('app:common.needHelp')}</div>
<div style={{ textDecoration: 'underline' }}>{t('common.needHelp')}</div>
<IconExternalLink size={14} />
</HelpLink>
</Box>

8
src/components/ManagerPage/FirmwareUpdate.js

@ -136,17 +136,17 @@ class FirmwareUpdate extends PureComponent<Props, State> {
<Box horizontal align="center">
<Text ff="Open Sans|SemiBold" fontSize={4} color="dark">
{device.product === 'Blue'
? t('app:manager.firmware.titleBlue')
: t('app:manager.firmware.titleNano')}
? t('manager.firmware.titleBlue')
: t('manager.firmware.titleNano')}
</Text>
<Box color="wallet" ml={2}>
<Tooltip render={() => t('app:manager.yourDeviceIsGenuine')}>
<Tooltip render={() => t('manager.yourDeviceIsGenuine')}>
<CheckFull size={13} color="wallet" />
</Tooltip>
</Box>
</Box>
<Text ff="Open Sans|SemiBold" fontSize={2}>
{t('app:manager.firmware.installed', {
{t('manager.firmware.installed', {
version: deviceInfo.fullVersion,
})}
</Text>

2
src/components/ManagerPage/ManagerApp.js

@ -74,7 +74,7 @@ function ManagerApp({ name, version, icon, onInstall, onUninstall, t }: Props) {
appVersion: version,
}}
>
{t('app:manager.apps.install')}
{t('manager.apps.install')}
</Button>
) : null}
<Button

4
src/components/ManagerPage/ManagerGenuineCheck.js

@ -31,10 +31,10 @@ class ManagerGenuineCheck extends PureComponent<Props> {
style={{ marginBottom: 30, maxWidth: 362, width: '100%' }}
/>
<Text ff="Museo Sans|Regular" fontSize={7} color="dark" style={{ marginBottom: 10 }}>
{t('app:manager.device.title')}
{t('manager.device.title')}
</Text>
<Text ff="Museo Sans|Light" fontSize={5} color="grey" align="center">
{t('app:manager.device.desc')}
{t('manager.device.desc')}
</Text>
</Box>
<Space of={40} />

6
src/components/ManagerPage/PlugYourDevice.js

@ -22,12 +22,12 @@ function PlugYourDevice(props: Props) {
<Box align="center" style={{ width: 365 }}>
<Box mb={5}>hey</Box>
<Box textAlign="center" mb={1} ff="Museo Sans|Regular" color="dark" fontSize={6}>
{t('app:manager.device.title')}
{t('manager.device.title')}
</Box>
<Box textAlign="center" mb={5} ff="Open Sans|Regular" color="smoke" fontSize={4}>
{t('app:manager.device.desc')}
{t('manager.device.desc')}
</Box>
<Button primary>{t('app:manager.device.cta')}</Button>
<Button primary>{t('manager.device.cta')}</Button>
</Box>
</Card>
)

4
src/components/ManagerPage/UpdateFirmwareButton.js

@ -23,7 +23,7 @@ const UpdateFirmwareButton = ({ t, firmware, onClick }: Props) =>
firmware ? (
<Fragment>
<Text ff="Open Sans|Regular" fontSize={4} style={{ marginLeft: 'auto', marginRight: 15 }}>
{t('app:manager.firmware.latest', { version: getCleanVersion(firmware.name) })}
{t('manager.firmware.latest', { version: getCleanVersion(firmware.name) })}
</Text>
<Button
primary
@ -33,7 +33,7 @@ const UpdateFirmwareButton = ({ t, firmware, onClick }: Props) =>
firmwareName: firmware.name,
}}
>
{t('app:manager.firmware.update')}
{t('manager.firmware.update')}
</Button>
</Fragment>
) : null

4
src/components/Onboarding/OnboardingFooter.js

@ -24,7 +24,7 @@ const OnboardingFooter = ({
}: Props) => (
<OnboardingFooterWrapper {...props}>
<Button outlineGrey onClick={() => prevStep()}>
{t('app:common.back')}
{t('common.back')}
</Button>
<Button
data-e2e="continue_button"
@ -33,7 +33,7 @@ const OnboardingFooter = ({
onClick={() => nextStep()}
ml="auto"
>
{t('app:common.continue')}
{t('common.continue')}
</Button>
</OnboardingFooterWrapper>
)

22
src/components/Onboarding/steps/Analytics.js

@ -70,14 +70,14 @@ class Analytics extends PureComponent<StepProps, State> {
deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'}
/>
<StepContainerInner>
<Title data-e2e="onboarding_title">{t('onboarding:analytics.title')}</Title>
<Description>{t('onboarding:analytics.desc')}</Description>
<Title data-e2e="onboarding_title">{t('onboarding.analytics.title')}</Title>
<Description>{t('onboarding.analytics.desc')}</Description>
<Box mt={5}>
<Container>
<Box>
<Box horizontal mb={1}>
<AnalyticsTitle data-e2e="analytics_techData">
{t('onboarding:analytics.technicalData.title')}
{t('onboarding.analytics.technicalData.title')}
</AnalyticsTitle>
<LearnMoreWrapper>
<FakeLink
@ -88,14 +88,14 @@ class Analytics extends PureComponent<StepProps, State> {
onClick={this.handleTechnicalDataModal}
data-e2e="analytics_techData_Link"
>
{t('app:common.learnMore')}
{t('common.learnMore')}
</FakeLink>
</LearnMoreWrapper>
</Box>
<TechnicalData />
<AnalyticsText>{t('onboarding:analytics.technicalData.desc')}</AnalyticsText>
<AnalyticsText>{t('onboarding.analytics.technicalData.desc')}</AnalyticsText>
<MandatoryText>
{t('onboarding:analytics.technicalData.mandatoryText')}
{t('onboarding.analytics.technicalData.mandatoryText')}
</MandatoryText>
</Box>
<Box justifyContent="center">
@ -106,7 +106,7 @@ class Analytics extends PureComponent<StepProps, State> {
<Box>
<Box horizontal mb={1}>
<AnalyticsTitle data-e2e="analytics_shareAnalytics">
{t('onboarding:analytics.shareAnalytics.title')}
{t('onboarding.analytics.shareAnalytics.title')}
</AnalyticsTitle>
<LearnMoreWrapper>
<FakeLink
@ -117,12 +117,12 @@ class Analytics extends PureComponent<StepProps, State> {
onClick={this.handleShareAnalyticsModal}
data-e2e="analytics_shareAnalytics_Link"
>
{t('app:common.learnMore')}
{t('common.learnMore')}
</FakeLink>
</LearnMoreWrapper>
<ShareAnalytics />
</Box>
<AnalyticsText>{t('onboarding:analytics.shareAnalytics.desc')}</AnalyticsText>
<AnalyticsText>{t('onboarding.analytics.shareAnalytics.desc')}</AnalyticsText>
</Box>
<Box justifyContent="center">
<Track
@ -140,10 +140,10 @@ class Analytics extends PureComponent<StepProps, State> {
<Box>
<Box mb={1}>
<AnalyticsTitle data-e2e="analytics_reportBugs">
{t('onboarding:analytics.sentryLogs.title')}
{t('onboarding.analytics.sentryLogs.title')}
</AnalyticsTitle>
</Box>
<AnalyticsText>{t('onboarding:analytics.sentryLogs.desc')}</AnalyticsText>
<AnalyticsText>{t('onboarding.analytics.sentryLogs.desc')}</AnalyticsText>
</Box>
<Box justifyContent="center">
<Track

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

@ -103,12 +103,12 @@ export default class Finish extends Component<StepProps, *> {
</Box>
<Box pt={5} align="center">
<Title data-e2e="finish_title">{t('onboarding:finish.title')}</Title>
<Description>{t('onboarding:finish.desc')}</Description>
<Title data-e2e="finish_title">{t('onboarding.finish.title')}</Title>
<Description>{t('onboarding.finish.desc')}</Description>
</Box>
<Box p={5}>
<Button primary onClick={() => finish()} data-e2e="continue_button">
{t('onboarding:finish.openAppButton')}
{t('onboarding.finish.openAppButton')}
</Button>
</Box>
<Box horizontal mt={3} flow={5} color="grey">

16
src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js

@ -40,21 +40,21 @@ class GenuineCheckErrorPage extends PureComponent<Props, *> {
{onboarding.genuine.isGenuineFail ? (
<Fragment>
{this.trackErrorPage('Not Genuine')}
<Title>{t('onboarding:genuineCheck.errorPage.title.isGenuineFail')}</Title>
<Description>{t('onboarding:genuineCheck.errorPage.desc.isGenuineFail')}</Description>
<Title>{t('onboarding.genuineCheck.errorPage.title.isGenuineFail')}</Title>
<Description>{t('onboarding.genuineCheck.errorPage.desc.isGenuineFail')}</Description>
</Fragment>
) : !onboarding.genuine.pinStepPass ? (
<Fragment>
{this.trackErrorPage('PIN Step')}
<Title>{t('onboarding:genuineCheck.errorPage.title.pinFailed')}</Title>
<Description>{t('onboarding:genuineCheck.errorPage.desc.pinFailed')}</Description>
<Title>{t('onboarding.genuineCheck.errorPage.title.pinFailed')}</Title>
<Description>{t('onboarding.genuineCheck.errorPage.desc.pinFailed')}</Description>
</Fragment>
) : (
<Fragment>
{this.trackErrorPage('Recovery Phase Step')}
<Title>{t('onboarding:genuineCheck.errorPage.title.recoveryPhraseFailed')}</Title>
<Title>{t('onboarding.genuineCheck.errorPage.title.recoveryPhraseFailed')}</Title>
<Description>
{t('onboarding:genuineCheck.errorPage.desc.recoveryPhraseFailed')}
{t('onboarding.genuineCheck.errorPage.desc.recoveryPhraseFailed')}
</Description>
</Fragment>
)}
@ -78,12 +78,12 @@ class GenuineCheckErrorPage extends PureComponent<Props, *> {
</Box>
<OnboardingFooterWrapper>
<Button outlineGrey onClick={() => redoGenuineCheck()}>
{t('app:common.back')}
{t('common.back')}
</Button>
<ExternalLinkButton
danger
ml="auto"
label={t('onboarding:genuineCheck.buttons.contactSupport')}
label={t('onboarding.genuineCheck.buttons.contactSupport')}
url={urls.contactSupport}
/>
</OnboardingFooterWrapper>

8
src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js

@ -27,7 +27,7 @@ export function GenuineCheckUnavailableFooter({
return (
<OnboardingFooterWrapper>
<Button outlineGrey onClick={() => prevStep()}>
{t('app:common.back')}
{t('common.back')}
</Button>
<Box horizontal ml="auto">
<Button
@ -36,10 +36,10 @@ export function GenuineCheckUnavailableFooter({
onClick={() => nextStep()}
mx={2}
>
{t('app:common.skipThisStep')}
{t('common.skipThisStep')}
</Button>
<Button onClick={nextStep} disabled primary>
{t('app:common.continue')}
{t('common.continue')}
</Button>
</Box>
</OnboardingFooterWrapper>
@ -81,7 +81,7 @@ export function GenuineCheckUnavailableMessage({
})
}}
>
{t('app:common.retry')}
{t('common.retry')}
</FakeLink>
</Box>
)

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

@ -59,12 +59,12 @@ class GenuineCheck extends PureComponent<StepProps, State> {
const { t } = this.props
return [
{
label: t('app:common.labelYes'),
label: t('common.labelYes'),
key: 'yes',
pass: true,
},
{
label: t('app:common.labelNo'),
label: t('common.labelNo'),
key: 'no',
pass: false,
},
@ -174,18 +174,18 @@ class GenuineCheck extends PureComponent<StepProps, State> {
deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'}
/>
<StepContainerInner>
<Title>{t('onboarding:genuineCheck.title')}</Title>
<Title>{t('onboarding.genuineCheck.title')}</Title>
{onboarding.flowType === 'restoreDevice' ? (
<Description>{t('onboarding:genuineCheck.descRestore')}</Description>
<Description>{t('onboarding.genuineCheck.descRestore')}</Description>
) : (
<Description>{t('onboarding:genuineCheck.descGeneric')}</Description>
<Description>{t('onboarding.genuineCheck.descGeneric')}</Description>
)}
<Box mt={5}>
<GenuineCheckCardWrapper>
<Box justify="center">
<Box horizontal>
<IconOptionRow>{'1.'}</IconOptionRow>
<CardTitle>{t('onboarding:genuineCheck.step1.title')}</CardTitle>
<CardTitle>{t('onboarding.genuineCheck.step1.title')}</CardTitle>
</Box>
</Box>
<Box justify="center">
@ -204,7 +204,7 @@ class GenuineCheck extends PureComponent<StepProps, State> {
<IconOptionRow color={!genuine.pinStepPass ? 'grey' : 'wallet'}>
{'2.'}
</IconOptionRow>
<CardTitle>{t('onboarding:genuineCheck.step2.title')}</CardTitle>
<CardTitle>{t('onboarding.genuineCheck.step2.title')}</CardTitle>
</Box>
</Box>
<Box justify="center">
@ -228,7 +228,7 @@ class GenuineCheck extends PureComponent<StepProps, State> {
<IconOptionRow color={!genuine.recoveryStepPass ? 'grey' : 'wallet'}>
{'3.'}
</IconOptionRow>
<CardTitle>{t('onboarding:genuineCheck.step3.title')}</CardTitle>
<CardTitle>{t('onboarding.genuineCheck.step3.title')}</CardTitle>
</Box>
</Box>
{genuine.recoveryStepPass && (
@ -237,7 +237,7 @@ class GenuineCheck extends PureComponent<StepProps, State> {
<Box horizontal align="center" flow={1} color={colors.wallet}>
<IconCheck size={16} />
<Box ff="Open Sans|SemiBold" fontSize={4}>
{t('onboarding:genuineCheck.isGenuinePassed')}
{t('onboarding.genuineCheck.isGenuinePassed')}
</Box>
</Box>
) : genuine.genuineCheckUnavailable ? (
@ -250,7 +250,7 @@ class GenuineCheck extends PureComponent<StepProps, State> {
disabled={!genuine.recoveryStepPass}
onClick={this.handleOpenGenuineCheckModal}
>
{t('onboarding:genuineCheck.buttons.genuineCheck')}
{t('onboarding.genuineCheck.buttons.genuineCheck')}
</Button>
)}
</Box>

10
src/components/Onboarding/steps/Init.js

@ -30,7 +30,7 @@ class Init extends PureComponent<StepProps, *> {
{
key: 'newDevice',
icon: <IconPlus size={20} />,
title: t('onboarding:init.newDevice.title'),
title: t('onboarding.init.newDevice.title'),
onClick: () => {
jumpStep('selectDevice')
flowType('newDevice')
@ -39,7 +39,7 @@ class Init extends PureComponent<StepProps, *> {
{
key: 'restoreDevice',
icon: <IconRecover size={20} />,
title: t('onboarding:init.restoreDevice.title'),
title: t('onboarding.init.restoreDevice.title'),
onClick: () => {
jumpStep('selectDevice')
flowType('restoreDevice')
@ -48,7 +48,7 @@ class Init extends PureComponent<StepProps, *> {
{
key: 'initializedDevice',
icon: <IconCheck size={20} />,
title: t('onboarding:init.initializedDevice.title'),
title: t('onboarding.init.initializedDevice.title'),
onClick: () => {
jumpStep('selectDevice')
flowType('initializedDevice')
@ -57,7 +57,7 @@ class Init extends PureComponent<StepProps, *> {
{
key: 'noDevice',
icon: <IconExternalLink size={20} />,
title: t('onboarding:noDevice.title'),
title: t('onboarding.noDevice.title'),
onClick: () => {
jumpStep('noDevice')
flowType('noDevice')
@ -77,7 +77,7 @@ class Init extends PureComponent<StepProps, *> {
}
/>
<Box m={5} style={{ maxWidth: 480 }}>
<Title>{t('onboarding:init.title')}</Title>
<Title>{t('onboarding.init.title')}</Title>
</Box>
<Box pt={4} flow={4}>
{optionCards.map(card => <OptionFlowCard key={card.key} card={card} />)}

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

@ -26,7 +26,7 @@ class NoDevice extends PureComponent<StepProps, *> {
{
key: 'buyNew',
icon: <IconCart size={20} />,
title: t('onboarding:noDevice.buyNew.title'),
title: t('onboarding.noDevice.buyNew.title'),
onClick: () => {
openURL(urls.noDeviceBuyNew)
},
@ -34,7 +34,7 @@ class NoDevice extends PureComponent<StepProps, *> {
{
key: 'trackOrder',
icon: <IconTruck size={20} />,
title: t('onboarding:noDevice.trackOrder.title'),
title: t('onboarding.noDevice.trackOrder.title'),
onClick: () => {
openURL(urls.noDeviceTrackOrder)
},
@ -42,7 +42,7 @@ class NoDevice extends PureComponent<StepProps, *> {
{
key: 'learnMore',
icon: <IconInfoCircle size={20} />,
title: t('onboarding:noDevice.learnMore.title'),
title: t('onboarding.noDevice.learnMore.title'),
onClick: () => {
openURL(urls.noDeviceLearnMore)
},
@ -68,7 +68,7 @@ class NoDevice extends PureComponent<StepProps, *> {
}
/>
<Box m={5} style={{ maxWidth: 480 }}>
<Title>{t('onboarding:noDevice.title')}</Title>
<Title>{t('onboarding.noDevice.title')}</Title>
</Box>
<Box pt={4} flow={4}>
{optionCards.map(card => <OptionFlowCard key={card.key} card={card} />)}
@ -77,7 +77,7 @@ class NoDevice extends PureComponent<StepProps, *> {
</GrowScroll>
<OnboardingFooterWrapper>
<Button outlineGrey onClick={() => prevStep()} mr="auto">
{t('app:common.back')}
{t('common.back')}
</Button>
</OnboardingFooterWrapper>
</Box>

6
src/components/Onboarding/steps/SelectDevice.js

@ -41,7 +41,7 @@ class SelectDevice extends PureComponent<StepProps, {}> {
<TrackPage category="Onboarding" name="Select Device" flowType={onboarding.flowType} />
<StepContainerInner>
<Box mb={5}>
<Title>{t('onboarding:selectDevice.title')}</Title>
<Title>{t('onboarding.selectDevice.title')}</Title>
</Box>
<Box pt={4}>
<Inner>
@ -53,7 +53,7 @@ class SelectDevice extends PureComponent<StepProps, {}> {
<DeviceIcon>
<img alt="" src={i('ledger-nano-onb.svg')} />
</DeviceIcon>
<BlockTitle>{t('onboarding:selectDevice.ledgerNanoCard.title')}</BlockTitle>
<BlockTitle>{t('onboarding.selectDevice.ledgerNanoCard.title')}</BlockTitle>
</DeviceContainer>
<DeviceContainer
isActive={!onboarding.isLedgerNano && onboarding.isLedgerNano !== null}
@ -63,7 +63,7 @@ class SelectDevice extends PureComponent<StepProps, {}> {
<DeviceIcon>
<img alt="" src={i('ledger-blue-onb.svg')} />
</DeviceIcon>
<BlockTitle>{t('onboarding:selectDevice.ledgerBlueCard.title')}</BlockTitle>
<BlockTitle>{t('onboarding.selectDevice.ledgerBlueCard.title')}</BlockTitle>
</DeviceContainer>
</Inner>
</Box>

12
src/components/Onboarding/steps/SelectPIN/SelectPINblue.js

@ -25,14 +25,14 @@ class SelectPIN extends PureComponent<Props, *> {
{
key: 'step1',
icon: <IconOptionRow>{'1.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.initialize.instructions.blue.step1'),
desc: t('onboarding.selectPIN.initialize.instructions.blue.step1'),
},
{
key: 'step2',
icon: <IconOptionRow>{'2.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:selectPIN.initialize.instructions.blue.step2">
<Trans i18nKey="onboarding.selectPIN.initialize.instructions.blue.step2">
{'Tap on'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Configure as new device'}
@ -44,7 +44,7 @@ class SelectPIN extends PureComponent<Props, *> {
{
key: 'step3',
icon: <IconOptionRow>{'3.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.initialize.instructions.blue.step3'),
desc: t('onboarding.selectPIN.initialize.instructions.blue.step3'),
},
]
@ -52,17 +52,17 @@ class SelectPIN extends PureComponent<Props, *> {
{
key: 'note1',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note1'),
desc: t('onboarding.selectPIN.disclaimer.note1'),
},
{
key: 'note2',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note2'),
desc: t('onboarding.selectPIN.disclaimer.note2'),
},
{
key: 'note3',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note3'),
desc: t('onboarding.selectPIN.disclaimer.note3'),
},
]

14
src/components/Onboarding/steps/SelectPIN/SelectPINnano.js

@ -25,19 +25,19 @@ class SelectPINnano extends PureComponent<Props, *> {
{
key: 'step1',
icon: <IconOptionRow>{'1.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.initialize.instructions.nano.step1'),
desc: t('onboarding.selectPIN.initialize.instructions.nano.step1'),
},
{
key: 'step2',
icon: <IconOptionRow>{'2.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.initialize.instructions.nano.step2'),
desc: t('onboarding.selectPIN.initialize.instructions.nano.step2'),
},
{
key: 'step3',
icon: <IconOptionRow>{'3.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:selectPIN.initialize.instructions.nano.step3">
<Trans i18nKey="onboarding.selectPIN.initialize.instructions.nano.step3">
{'Press the right button to select'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Configure as new device'}
@ -49,24 +49,24 @@ class SelectPINnano extends PureComponent<Props, *> {
{
key: 'step4',
icon: <IconOptionRow>{'4.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.initialize.instructions.nano.step4'),
desc: t('onboarding.selectPIN.initialize.instructions.nano.step4'),
},
]
const disclaimerNotes = [
{
key: 'note1',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note1'),
desc: t('onboarding.selectPIN.disclaimer.note1'),
},
{
key: 'note2',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note2'),
desc: t('onboarding.selectPIN.disclaimer.note2'),
},
{
key: 'note3',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note3'),
desc: t('onboarding.selectPIN.disclaimer.note3'),
},
]

12
src/components/Onboarding/steps/SelectPIN/SelectPINrestoreBlue.js

@ -25,14 +25,14 @@ class SelectPINrestoreBlue extends PureComponent<Props, *> {
{
key: 'step1',
icon: <IconOptionRow>{'1.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.restore.instructions.blue.step1'),
desc: t('onboarding.selectPIN.restore.instructions.blue.step1'),
},
{
key: 'step2',
icon: <IconOptionRow>{'2.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:selectPIN.restore.instructions.blue.step2">
<Trans i18nKey="onboarding.selectPIN.restore.instructions.blue.step2">
{'Tap on'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Restore configuration'}
@ -44,7 +44,7 @@ class SelectPINrestoreBlue extends PureComponent<Props, *> {
{
key: 'step3',
icon: <IconOptionRow>{'3.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.restore.instructions.blue.step3'),
desc: t('onboarding.selectPIN.restore.instructions.blue.step3'),
},
]
@ -52,17 +52,17 @@ class SelectPINrestoreBlue extends PureComponent<Props, *> {
{
key: 'note1',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note1'),
desc: t('onboarding.selectPIN.disclaimer.note1'),
},
{
key: 'note2',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note2'),
desc: t('onboarding.selectPIN.disclaimer.note2'),
},
{
key: 'note3',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note3'),
desc: t('onboarding.selectPIN.disclaimer.note3'),
},
]

14
src/components/Onboarding/steps/SelectPIN/SelectPINrestoreNano.js

@ -25,19 +25,19 @@ class SelectPINrestoreNano extends PureComponent<Props, *> {
{
key: 'step1',
icon: <IconOptionRow>{'1.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.restore.instructions.nano.step1'),
desc: t('onboarding.selectPIN.restore.instructions.nano.step1'),
},
{
key: 'step2',
icon: <IconOptionRow>{'2.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.restore.instructions.nano.step2'),
desc: t('onboarding.selectPIN.restore.instructions.nano.step2'),
},
{
key: 'step3',
icon: <IconOptionRow>{'3.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:selectPIN.restore.instructions.nano.step3">
<Trans i18nKey="onboarding.selectPIN.restore.instructions.nano.step3">
{'Press the left button to cancel'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Initialize as new device?'}
@ -53,24 +53,24 @@ class SelectPINrestoreNano extends PureComponent<Props, *> {
{
key: 'step4',
icon: <IconOptionRow>{'4.'}</IconOptionRow>,
desc: t('onboarding:selectPIN.restore.instructions.nano.step4'),
desc: t('onboarding.selectPIN.restore.instructions.nano.step4'),
},
]
const disclaimerNotes = [
{
key: 'note1',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note1'),
desc: t('onboarding.selectPIN.disclaimer.note1'),
},
{
key: 'note2',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note2'),
desc: t('onboarding.selectPIN.disclaimer.note2'),
},
{
key: 'note3',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:selectPIN.disclaimer.note3'),
desc: t('onboarding.selectPIN.disclaimer.note3'),
},
]

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

@ -29,14 +29,14 @@ export default (props: StepProps) => {
/>
{onboarding.flowType === 'restoreDevice' ? (
<Box grow alignItems="center">
<Title>{t('onboarding:selectPIN.restore.title')}</Title>
<Title>{t('onboarding.selectPIN.restore.title')}</Title>
<Box align="center" mt={7}>
{onboarding.isLedgerNano ? <SelectPINrestoreNano /> : <SelectPINrestoreBlue />}
</Box>
</Box>
) : (
<Box grow alignItems="center">
<Title>{t('onboarding:selectPIN.initialize.title')}</Title>
<Title>{t('onboarding.selectPIN.initialize.title')}</Title>
<Box align="center" mt={7}>
{onboarding.isLedgerNano ? <SelectPINnano /> : <SelectPINblue />}
</Box>

16
src/components/Onboarding/steps/SetPassword.js

@ -85,17 +85,17 @@ class SetPassword extends PureComponent<Props, State> {
{
key: 'note1',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:setPassword.disclaimer.note1'),
desc: t('onboarding.setPassword.disclaimer.note1'),
},
{
key: 'note2',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:setPassword.disclaimer.note2'),
desc: t('onboarding.setPassword.disclaimer.note2'),
},
{
key: 'note3',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:setPassword.disclaimer.note3'),
desc: t('onboarding.setPassword.disclaimer.note3'),
},
]
@ -110,9 +110,9 @@ class SetPassword extends PureComponent<Props, State> {
<StepContainerInner>
<Fragment>
<Box alignItems="center">
<Title>{t('onboarding:setPassword.title')}</Title>
<Title>{t('onboarding.setPassword.title')}</Title>
<Description style={{ maxWidth: 620 }}>
{t('onboarding:setPassword.desc')}
{t('onboarding.setPassword.desc')}
</Description>
</Box>
<Box align="center" mt={2}>
@ -134,7 +134,7 @@ class SetPassword extends PureComponent<Props, State> {
<OnboardingFooterWrapper>
<Button outlineGrey onClick={() => prevStep()}>
{t('app:common.back')}
{t('common.back')}
</Button>
<Box horizontal ml="auto">
<Button
@ -143,14 +143,14 @@ class SetPassword extends PureComponent<Props, State> {
disabled={false}
mx={2}
>
{t('app:common.skipThisStep')}
{t('common.skipThisStep')}
</Button>
<Button
onClick={this.handleSave}
disabled={!this.isValid() || !newPassword.length || !confirmPassword.length}
primary
>
{t('app:common.continue')}
{t('common.continue')}
</Button>
</Box>
</OnboardingFooterWrapper>

4
src/components/Onboarding/steps/Start.js

@ -21,10 +21,10 @@ export default (props: StepProps) => {
icon={<img src={i('ledgerlive-logo.svg')} alt="" width={50} height={50} />}
/>
<Box my={5}>
<Title>{t('onboarding:start.title')}</Title>
<Title>{t('onboarding.start.title')}</Title>
</Box>
<Button primary onClick={() => jumpStep('init')}>
{t('onboarding:start.startBtn')}
{t('onboarding.start.startBtn')}
</Button>
</Box>
</Box>

18
src/components/Onboarding/steps/WriteSeed/WriteSeedBlue.js

@ -31,14 +31,14 @@ class WriteSeedBlue extends PureComponent<Props, *> {
{
key: 'step1',
icon: <IconOptionRow>{'1.'}</IconOptionRow>,
desc: t('onboarding:writeSeed.initialize.blue.step1'),
desc: t('onboarding.writeSeed.initialize.blue.step1'),
},
{
key: 'step2',
icon: <IconOptionRow>{'2.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:writeSeed.initialize.blue.step2">
<Trans i18nKey="onboarding.writeSeed.initialize.blue.step2">
{'Tap'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Next'}
@ -55,37 +55,37 @@ class WriteSeedBlue extends PureComponent<Props, *> {
{
key: 'step3',
icon: <IconOptionRow>{'3.'}</IconOptionRow>,
desc: t('onboarding:writeSeed.initialize.blue.step3'),
desc: t('onboarding.writeSeed.initialize.blue.step3'),
},
]
const disclaimerNotes = [
{
key: 'note1',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note1'),
desc: t('onboarding.writeSeed.disclaimer.note1'),
},
{
key: 'note2',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note2'),
desc: t('onboarding.writeSeed.disclaimer.note2'),
},
{
key: 'note3',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note3'),
desc: t('onboarding.writeSeed.disclaimer.note3'),
},
{
key: 'note4',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note4'),
desc: t('onboarding.writeSeed.disclaimer.note4'),
},
]
return (
<Fragment>
<Box mb={3}>
<Title>{t('onboarding:writeSeed.initialize.title')}</Title>
<Description>{t('onboarding:writeSeed.initialize.desc')}</Description>
<Title>{t('onboarding.writeSeed.initialize.title')}</Title>
<Description>{t('onboarding.writeSeed.initialize.desc')}</Description>
</Box>
<Box align="center">
<Inner style={{ width: 760 }}>

18
src/components/Onboarding/steps/WriteSeed/WriteSeedNano.js

@ -33,7 +33,7 @@ class WriteSeedNano extends PureComponent<Props, *> {
icon: <IconOptionRow>{'1.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:writeSeed.initialize.nano.step1">
<Trans i18nKey="onboarding.writeSeed.initialize.nano.step1">
{'Copy the word displayed below'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Word #1'}
@ -48,7 +48,7 @@ class WriteSeedNano extends PureComponent<Props, *> {
icon: <IconOptionRow>{'2.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:writeSeed.initialize.nano.step2">
<Trans i18nKey="onboarding.writeSeed.initialize.nano.step2">
{'Press the right button to display'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Word #2'}
@ -61,37 +61,37 @@ class WriteSeedNano extends PureComponent<Props, *> {
{
key: 'step3',
icon: <IconOptionRow>{'3.'}</IconOptionRow>,
desc: t('onboarding:writeSeed.initialize.nano.step3'),
desc: t('onboarding.writeSeed.initialize.nano.step3'),
},
]
const disclaimerNotes = [
{
key: 'note1',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note1'),
desc: t('onboarding.writeSeed.disclaimer.note1'),
},
{
key: 'note2',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note2'),
desc: t('onboarding.writeSeed.disclaimer.note2'),
},
{
key: 'note3',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note3'),
desc: t('onboarding.writeSeed.disclaimer.note3'),
},
{
key: 'note4',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note4'),
desc: t('onboarding.writeSeed.disclaimer.note4'),
},
]
return (
<Fragment>
<Box mb={3}>
<Title>{t('onboarding:writeSeed.initialize.title')}</Title>
<Description>{t('onboarding:writeSeed.initialize.desc')}</Description>
<Title>{t('onboarding.writeSeed.initialize.title')}</Title>
<Description>{t('onboarding.writeSeed.initialize.desc')}</Description>
</Box>
<Box align="center" mt={3}>
<Inner style={{ width: 700 }}>

26
src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js

@ -34,14 +34,14 @@ class WriteSeedRestore extends PureComponent<Props, *> {
{
key: 'step1',
icon: <IconOptionRow>{'1.'}</IconOptionRow>,
desc: t('onboarding:writeSeed.restore.nano.step1'),
desc: t('onboarding.writeSeed.restore.nano.step1'),
},
{
key: 'step2',
icon: <IconOptionRow>{'2.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:writeSeed.restore.nano.step2">
<Trans i18nKey="onboarding.writeSeed.restore.nano.step2">
{'Select the first letters of'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Word #1'}
@ -56,7 +56,7 @@ class WriteSeedRestore extends PureComponent<Props, *> {
icon: <IconOptionRow>{'3.'}</IconOptionRow>,
desc: (
<Box style={{ display: 'block' }}>
<Trans i18nKey="onboarding:writeSeed.restore.nano.step3">
<Trans i18nKey="onboarding.writeSeed.restore.nano.step3">
{'Select'}
<Text ff="Open Sans|SemiBold" color="dark">
{'Word #1'}
@ -69,54 +69,54 @@ class WriteSeedRestore extends PureComponent<Props, *> {
{
key: 'step4',
icon: <IconOptionRow>{'4.'}</IconOptionRow>,
desc: t('onboarding:writeSeed.restore.nano.step4'),
desc: t('onboarding.writeSeed.restore.nano.step4'),
},
]
const stepsBlue = [
{
key: 'step1',
icon: <IconOptionRow>{'1.'}</IconOptionRow>,
desc: t('onboarding:writeSeed.restore.blue.step1'),
desc: t('onboarding.writeSeed.restore.blue.step1'),
},
{
key: 'step2',
icon: <IconOptionRow>{'2.'}</IconOptionRow>,
desc: t('onboarding:writeSeed.restore.blue.step2'),
desc: t('onboarding.writeSeed.restore.blue.step2'),
},
{
key: 'step3',
icon: <IconOptionRow>{'3.'}</IconOptionRow>,
desc: t('onboarding:writeSeed.restore.blue.step3'),
desc: t('onboarding.writeSeed.restore.blue.step3'),
},
]
const disclaimerNotes = [
{
key: 'note1',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note1'),
desc: t('onboarding.writeSeed.disclaimer.note1'),
},
{
key: 'note2',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note2'),
desc: t('onboarding.writeSeed.disclaimer.note2'),
},
{
key: 'note3',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note3'),
desc: t('onboarding.writeSeed.disclaimer.note3'),
},
{
key: 'note4',
icon: <IconChevronRight size={12} style={{ color: colors.smoke }} />,
desc: t('onboarding:writeSeed.disclaimer.note4'),
desc: t('onboarding.writeSeed.disclaimer.note4'),
},
]
return (
<Fragment>
<Box mb={3}>
<Title>{t('onboarding:writeSeed.restore.title')}</Title>
<Description>{t('onboarding:writeSeed.restore.desc')}</Description>
<Title>{t('onboarding.writeSeed.restore.title')}</Title>
<Description>{t('onboarding.writeSeed.restore.desc')}</Description>
</Box>
<Box align="center">
<Inner style={{ width: 760 }}>

2
src/components/OpenUserDataDirectoryBtn.js

@ -21,7 +21,7 @@ class OpenUserDataDirectoryBtn extends Component<{
const { t } = this.props
return (
<Button primary small onClick={this.handleOpenUserDataDirectory}>
{t('app:settings.openUserDataDirectory.btn')}
{t('settings.openUserDataDirectory.btn')}
</Button>
)
}

2
src/components/OperationsList/AmountCell.js

@ -2,7 +2,7 @@
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import { getOperationAmountNumber } from '@ledgerhq/live-common/lib/helpers/operation'
import { getOperationAmountNumber } from '@ledgerhq/live-common/lib/operation'
import type { Currency, Unit, Operation } from '@ledgerhq/live-common/lib/types'
import Box from 'components/base/Box'
import CounterValue from 'components/CounterValue'

2
src/components/OperationsList/ConfirmationCheck.js

@ -59,7 +59,7 @@ class ConfirmationCheck extends PureComponent<{
renderTooltip = () => {
const { t, isConfirmed } = this.props
return t(isConfirmed ? 'app:operationDetails.confirmed' : 'app:operationDetails.notConfirmed')
return t(isConfirmed ? 'operationDetails.confirmed' : 'operationDetails.notConfirmed')
}
render() {

2
src/components/OperationsList/DateCell.js

@ -29,7 +29,7 @@ class DateCell extends PureComponent<Props> {
return (
<Cell>
<Box ff="Open Sans|SemiBold" fontSize={3} color="smoke">
{t(`app:operation.type.${operation.type}`)}
{t(`operation.type.${operation.type}`)}
</Box>
<OperationDate date={operation.date} />
</Cell>

6
src/components/OperationsList/index.js

@ -8,7 +8,7 @@ import { translate } from 'react-i18next'
import {
groupAccountOperationsByDay,
groupAccountsOperationsByDay,
} from '@ledgerhq/live-common/lib/helpers/account'
} from '@ledgerhq/live-common/lib/account'
import type { Operation, Account } from '@ledgerhq/live-common/lib/types'
@ -139,13 +139,13 @@ export class OperationsList extends PureComponent<Props, State> {
) : null}
{!groupedOperations.completed ? (
<ShowMore onClick={this.fetchMoreOperations}>
<span>{t('app:common.showMore')}</span>
<span>{t('common.showMore')}</span>
<IconAngleDown size={12} />
</ShowMore>
) : (
<Box p={6} align="center">
<Text ff="Open Sans" fontSize={3}>
{t('app:operationList.noMoreOperations')}
{t('operationList.noMoreOperations')}
</Text>
</Box>
)}

2
src/components/PillsDaysCount.js

@ -24,7 +24,7 @@ class PillsDaysCount extends PureComponent<Props> {
items={Object.keys(timeRangeDaysByKey).map((key: TimeRange) => ({
key,
value: timeRangeDaysByKey[key],
label: t(`app:time.${key}`),
label: t(`time.${key}`),
}))}
activeKey={selected}
onChange={onChange}

44
src/components/QRCodeExporter.js

@ -1,24 +1,32 @@
// @flow
import React, { PureComponent } from 'react'
import { Buffer } from 'buffer'
import { createSelector } from 'reselect'
import { connect } from 'react-redux'
import { accountsSelector } from 'reducers/accounts'
import { makeChunks } from '@ledgerhq/live-common/lib/bridgestream/exporter'
import { exportSettingsSelector } from 'reducers/settings'
import { encode } from '@ledgerhq/live-common/lib/cross'
import { dataToFrames } from 'qrloop/exporter'
import QRCode from './base/QRCode'
const mapStateToProps = createSelector(accountsSelector, accounts => ({
chunks: makeChunks({
accounts,
exporterName: 'desktop',
exporterVersion: __APP_VERSION__,
pad: true,
const mapStateToProps = createSelector(
accountsSelector,
exportSettingsSelector,
(accounts, settings) => ({
chunks: dataToFrames(
encode({
accounts,
settings,
exporterName: 'desktop',
exporterVersion: __APP_VERSION__,
}),
200,
4,
),
}),
}))
const LOW_FPS = 2
const HIGH_FPS = 8
)
class QRCodeExporter extends PureComponent<
{
@ -31,23 +39,21 @@ class QRCodeExporter extends PureComponent<
},
> {
static defaultProps = {
size: 440,
size: 460,
}
state = {
frame: 0,
fps: HIGH_FPS,
fps: 3,
}
componentDidMount() {
console.log(`BRIDGESTREAM_DATA=${btoa(JSON.stringify(this.props.chunks))}`) // eslint-disable-line
const BRIDGESTREAM_DATA = Buffer.from(JSON.stringify(this.props.chunks)).toString('base64')
console.log(`BRIDGESTREAM_DATA=${BRIDGESTREAM_DATA}`) // eslint-disable-line
const nextFrame = ({ frame, fps }, { chunks }) => {
const nextFrame = ({ frame }, { chunks }) => {
frame = (frame + 1) % chunks.length
return {
frame,
fps: frame === 0 ? (fps === LOW_FPS ? HIGH_FPS : LOW_FPS) : fps,
}
return { frame }
}
let lastT

2
src/components/RecipientAddress/index.js

@ -4,7 +4,7 @@ import type { BigNumber } from 'bignumber.js'
import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'
import noop from 'lodash/noop'
import { decodeURIScheme } from '@ledgerhq/live-common/lib/helpers/currencies'
import { decodeURIScheme } from '@ledgerhq/live-common/lib/currencies'
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import { radii } from 'styles/theme'

23
src/components/RenderError.js

@ -75,7 +75,7 @@ class RenderError extends PureComponent<
<img alt="" src={i('crash-screen.svg')} width={380} />
<Space of={40} />
<Box ff="Museo Sans|Regular" fontSize={7} color="dark">
{t('app:crash.oops')}
{t('crash.oops')}
</Box>
<Space of={15} />
<Box
@ -85,25 +85,20 @@ class RenderError extends PureComponent<
color="smoke"
fontSize={4}
>
{t('app:crash.uselessText')}
{t('crash.uselessText')}
</Box>
<Space of={30} />
<Box horizontal flow={2}>
<Button small primary onClick={this.handleRestart}>
{t('app:crash.restart')}
{t('crash.restart')}
</Button>
<ExportLogsBtn withoutAppData={withoutAppData} />
<ExternalLinkButton
small
primary
label={t('app:crash.support')}
url={urls.contactSupport}
/>
<ExternalLinkButton small primary label={t('crash.support')} url={urls.contactSupport} />
<Button small primary onClick={this.github}>
{t('app:crash.github')}
{t('crash.github')}
</Button>
<Button small danger onClick={this.handleOpenHardResetModal}>
{t('app:common.reset')}
{t('common.reset')}
</Button>
</Box>
<ConfirmModal
@ -114,9 +109,9 @@ class RenderError extends PureComponent<
onClose={this.handleCloseHardResetModal}
onReject={this.handleCloseHardResetModal}
onConfirm={this.handleHardReset}
confirmText={t('app:common.reset')}
title={t('app:settings.hardResetModal.title')}
desc={t('app:settings.hardResetModal.desc')}
confirmText={t('common.reset')}
title={t('settings.hardResetModal.title')}
desc={t('settings.hardResetModal.desc')}
renderIcon={this.hardResetIconRender}
/>
<Box my={6}>

2
src/components/RequestAmount/index.js

@ -180,7 +180,7 @@ export class RequestAmount extends PureComponent<Props> {
{withMax && (
<Box grow justify="flex-end">
<Button primary onClick={this.handleClickMax}>
{t('app:common.max')}
{t('common.max')}
</Button>
</Box>
)}

4
src/components/SelectAccount/index.js

@ -74,9 +74,9 @@ const RawSelectAccount = ({ accounts, onChange, value, t, ...props }: Props) =>
getOptionValue={getOptionValue}
renderValue={renderOption}
renderOption={renderOption}
placeholder={t('app:common.selectAccount')}
placeholder={t('common.selectAccount')}
noOptionsMessage={({ inputValue }) =>
t('app:common.selectAccountNoOption', { accountName: inputValue })
t('common.selectAccountNoOption', { accountName: inputValue })
}
onChange={onChange}
/>

5
src/components/SelectCurrency/index.js

@ -39,10 +39,9 @@ const SelectCurrency = ({ onChange, value, t, placeholder, currencies, ...props
renderOption={renderOption}
renderValue={renderOption}
options={options}
placeholder={placeholder || t('app:common.selectCurrency')}
data-e2e="test"
placeholder={placeholder || t('common.selectCurrency')}
noOptionsMessage={({ inputValue }: { inputValue: string }) =>
t('app:common.selectCurrencyNoOption', { currencyName: inputValue })
t('common.selectCurrencyNoOption', { currencyName: inputValue })
}
onChange={item => onChange(item ? item.currency : null)}
{...props}

6
src/components/SelectExchange.js

@ -127,11 +127,11 @@ class SelectExchange extends Component<
options={options}
onChange={onChange}
isLoading={isLoading}
placeholder={t('app:common.selectExchange')}
placeholder={t('common.selectExchange')}
noOptionsMessage={({ inputValue }) =>
inputValue
? t('app:common.selectExchangeNoOption', { exchangeName: inputValue })
: t('app:common.selectExchangeNoOptionAtAll')
? t('common.selectExchangeNoOption', { exchangeName: inputValue })
: t('common.selectExchangeNoOptionAtAll')
}
{...props}
/>

22
src/components/SettingsPage/CleanButton.js

@ -3,11 +3,13 @@
import React, { Fragment, PureComponent } from 'react'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import logger from 'logger'
import type { T } from 'types/common'
import { cleanAccountsCache } from 'actions/accounts'
import Button from 'components/base/Button'
import { ConfirmModal } from 'components/base/Modal'
import { softReset } from 'helpers/reset'
import ResetFallbackModal from './ResetFallbackModal'
const mapDispatchToProps = {
cleanAccountsCache,
@ -20,36 +22,40 @@ type Props = {
type State = {
opened: boolean,
fallbackOpened: boolean,
isLoading: boolean,
}
class CleanButton extends PureComponent<Props, State> {
state = {
opened: false,
fallbackOpened: false,
isLoading: false,
}
open = () => this.setState({ opened: true })
close = () => this.setState({ opened: false })
closeFallback = () => this.setState({ fallbackOpened: false })
action = async () => {
if (this.state.isLoading) return
try {
this.setState({ isLoading: true })
await softReset({ cleanAccountsCache: this.props.cleanAccountsCache })
} finally {
this.setState({ isLoading: false })
} catch (err) {
logger.error(err)
this.setState({ isLoading: false, fallbackOpened: true })
}
}
render() {
const { t } = this.props
const { opened, isLoading } = this.state
const { opened, isLoading, fallbackOpened } = this.state
return (
<Fragment>
<Button small primary onClick={this.open} event="ClearCacheIntent">
{t('app:settings.profile.softReset')}
{t('settings.profile.softReset')}
</Button>
<ConfirmModal
@ -59,10 +65,12 @@ class CleanButton extends PureComponent<Props, State> {
onReject={this.close}
onConfirm={this.action}
isLoading={isLoading}
title={t('app:settings.softResetModal.title')}
subTitle={t('app:common.areYouSure')}
desc={t('app:settings.softResetModal.desc')}
title={t('settings.softResetModal.title')}
subTitle={t('common.areYouSure')}
desc={t('settings.softResetModal.desc')}
/>
<ResetFallbackModal isOpened={fallbackOpened} onClose={this.closeFallback} />
</Fragment>
)
}

2
src/components/SettingsPage/CounterValueSelect.js

@ -3,7 +3,7 @@
import React, { Fragment, PureComponent } from 'react'
import { connect } from 'react-redux'
import { createStructuredSelector } from 'reselect'
import { listFiatCurrencies } from '@ledgerhq/live-common/lib/helpers/currencies'
import { listFiatCurrencies } from '@ledgerhq/live-common/lib/currencies'
import type { Currency } from '@ledgerhq/live-common/lib/types'
import { setCounterValue } from 'actions/settings'
import { counterValueCurrencySelector } from 'reducers/settings'

10
src/components/SettingsPage/DisablePasswordModal.js

@ -69,15 +69,15 @@ class DisablePasswordModal extends PureComponent<Props, State> {
<form onSubmit={this.disablePassword}>
<ModalBody onClose={onClose}>
<ModalTitle data-e2e="disablePassword_modalTitle">
{t('app:password.disablePassword.title')}
{t('password.disablePassword.title')}
</ModalTitle>
<ModalContent>
<Box ff="Open Sans" color="smoke" fontSize={4} textAlign="center" px={4}>
{t('app:password.disablePassword.desc')}
{t('password.disablePassword.desc')}
<Box px={7} mt={4} flow={3}>
<Box flow={1}>
<Label htmlFor="password">
{t('app:password.inputFields.currentPassword.label')}
{t('password.inputFields.currentPassword.label')}
</Label>
<InputPassword
autoFocus
@ -93,7 +93,7 @@ class DisablePasswordModal extends PureComponent<Props, State> {
</ModalContent>
<ModalFooter horizontal align="center" justify="flex-end" flow={2}>
<Button small type="button" onClick={onClose}>
{t('app:common.cancel')}
{t('common.cancel')}
</Button>
<Button
small
@ -101,7 +101,7 @@ class DisablePasswordModal extends PureComponent<Props, State> {
onClick={this.disablePassword}
disabled={!currentPassword && !incorrectPassword}
>
{t('app:common.save')}
{t('common.save')}
</Button>
</ModalFooter>
</ModalBody>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save