aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app')
-rw-r--r--ui/app/account-detail.js117
-rw-r--r--ui/app/accounts/import/index.js15
-rw-r--r--ui/app/accounts/import/json.js17
-rw-r--r--ui/app/accounts/import/private-key.js13
-rw-r--r--ui/app/accounts/import/seed.js6
-rw-r--r--ui/app/accounts/new-account/create-form.js13
-rw-r--r--ui/app/accounts/new-account/index.js9
-rw-r--r--ui/app/actions.js14
-rw-r--r--ui/app/add-token.js43
-rw-r--r--ui/app/app.js63
-rw-r--r--ui/app/components/account-dropdowns.js15
-rw-r--r--ui/app/components/account-export.js15
-rw-r--r--ui/app/components/account-menu/index.js17
-rw-r--r--ui/app/components/balance.js89
-rw-r--r--ui/app/components/binary-renderer.js46
-rw-r--r--ui/app/components/bn-as-decimal-input.js9
-rw-r--r--ui/app/components/buy-button-subview.js15
-rw-r--r--ui/app/components/coinbase-form.js5
-rw-r--r--ui/app/components/copyButton.js3
-rw-r--r--ui/app/components/copyable.js3
-rw-r--r--ui/app/components/currency-input.js22
-rw-r--r--ui/app/components/customize-gas-modal/index.js56
-rw-r--r--ui/app/components/dropdowns/account-options-dropdown.js29
-rw-r--r--ui/app/components/dropdowns/account-selection-dropdown.js29
-rw-r--r--ui/app/components/dropdowns/components/account-dropdowns.js22
-rw-r--r--ui/app/components/dropdowns/index.js6
-rw-r--r--ui/app/components/dropdowns/network-dropdown.js27
-rw-r--r--ui/app/components/dropdowns/token-menu-dropdown.js3
-rw-r--r--ui/app/components/ens-input.js5
-rw-r--r--ui/app/components/hex-as-decimal-input.js9
-rw-r--r--ui/app/components/input-number.js1
-rw-r--r--ui/app/components/mini-account-panel.js74
-rw-r--r--ui/app/components/modals/account-details-modal.js5
-rw-r--r--ui/app/components/modals/account-modal-container.js3
-rw-r--r--ui/app/components/modals/buy-options-modal.js15
-rw-r--r--ui/app/components/modals/deposit-ether-modal.js131
-rw-r--r--ui/app/components/modals/edit-account-name-modal.js7
-rw-r--r--ui/app/components/modals/export-private-key-modal.js16
-rw-r--r--ui/app/components/modals/hide-token-confirmation-modal.js13
-rw-r--r--ui/app/components/modals/modal.js21
-rw-r--r--ui/app/components/modals/new-account-modal.js17
-rw-r--r--ui/app/components/network.js25
-rw-r--r--ui/app/components/notice.js3
-rw-r--r--ui/app/components/pending-msg-details.js4
-rw-r--r--ui/app/components/pending-msg.js15
-rw-r--r--ui/app/components/pending-personal-msg-details.js60
-rw-r--r--ui/app/components/pending-tx/confirm-deploy-contract.js590
-rw-r--r--ui/app/components/pending-tx/confirm-send-ether.js409
-rw-r--r--ui/app/components/pending-tx/confirm-send-token.js244
-rw-r--r--ui/app/components/pending-typed-msg-details.js59
-rw-r--r--ui/app/components/pending-typed-msg.js46
-rw-r--r--ui/app/components/range-slider.js58
-rw-r--r--ui/app/components/send-token/index.js439
-rw-r--r--ui/app/components/send/currency-toggle.js44
-rw-r--r--ui/app/components/send/eth-fee-display.js37
-rw-r--r--ui/app/components/send/gas-fee-display-v2.js13
-rw-r--r--ui/app/components/send/gas-fee-display.js62
-rw-r--r--ui/app/components/send/gas-tooltip.js4
-rw-r--r--ui/app/components/send/send-v2-container.js1
-rw-r--r--ui/app/components/send/to-autocomplete.js4
-rw-r--r--ui/app/components/send/usd-fee-display.js35
-rw-r--r--ui/app/components/sender-to-recipient.js45
-rw-r--r--ui/app/components/shapeshift-form.js23
-rw-r--r--ui/app/components/shift-list-item.js15
-rw-r--r--ui/app/components/signature-request.js25
-rw-r--r--ui/app/components/template.js18
-rw-r--r--ui/app/components/token-list.js7
-rw-r--r--ui/app/components/transaction-list-item-icon.js68
-rw-r--r--ui/app/components/transaction-list-item.js238
-rw-r--r--ui/app/components/transaction-list.js87
-rw-r--r--ui/app/components/tx-list-item.js100
-rw-r--r--ui/app/components/tx-list.js20
-rw-r--r--ui/app/components/tx-view.js21
-rw-r--r--ui/app/components/typed-message-renderer.js42
-rw-r--r--ui/app/components/wallet-content-display.js56
-rw-r--r--ui/app/components/wallet-view.js9
-rw-r--r--ui/app/conf-tx.js18
-rw-r--r--ui/app/conversion-util.js13
-rw-r--r--ui/app/css/itcss/components/account-menu.scss3
-rw-r--r--ui/app/css/itcss/components/buttons.scss12
-rw-r--r--ui/app/css/itcss/components/confirm.scss48
-rw-r--r--ui/app/css/itcss/components/hero-balance.scss3
-rw-r--r--ui/app/css/itcss/components/index.scss4
-rw-r--r--ui/app/css/itcss/components/modal.scss58
-rw-r--r--ui/app/css/itcss/components/network.scss3
-rw-r--r--ui/app/css/itcss/components/new-account.scss3
-rw-r--r--ui/app/css/itcss/components/newui-sections.scss24
-rw-r--r--ui/app/css/itcss/components/send.scss27
-rw-r--r--ui/app/css/itcss/components/sender-to-recipient.scss58
-rw-r--r--ui/app/css/itcss/components/transaction-list.scss55
-rw-r--r--ui/app/css/itcss/components/welcome-screen.scss59
-rw-r--r--ui/app/css/itcss/generic/index.scss54
-rw-r--r--ui/app/css/itcss/generic/reset.scss4
-rw-r--r--ui/app/css/itcss/settings/variables.scss1
-rw-r--r--ui/app/first-time/init-menu.js19
-rw-r--r--ui/app/info.js154
-rw-r--r--ui/app/keychains/hd/recover-seed/confirmation.js7
-rw-r--r--ui/app/keychains/hd/restore-vault.js42
-rw-r--r--ui/app/main-container.js14
-rw-r--r--ui/app/reducers/metamask.js8
-rw-r--r--ui/app/selectors.js5
-rw-r--r--ui/app/send-v2.js39
-rw-r--r--ui/app/send.js547
-rw-r--r--ui/app/settings.js76
-rw-r--r--ui/app/template.js30
-rw-r--r--ui/app/token-tracker.js0
-rw-r--r--ui/app/unlock.js144
-rw-r--r--ui/app/welcome-screen.js56
108 files changed, 1919 insertions, 3633 deletions
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
deleted file mode 100644
index 0da435298..000000000
--- a/ui/app/account-detail.js
+++ /dev/null
@@ -1,117 +0,0 @@
-const inherits = require('util').inherits
-const extend = require('xtend')
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const connect = require('react-redux').connect
-const actions = require('./actions')
-const valuesFor = require('./util').valuesFor
-const TransactionList = require('./components/transaction-list')
-const ExportAccountView = require('./components/account-export')
-const TabBar = require('./components/tab-bar')
-const TokenList = require('./components/token-list')
-
-module.exports = connect(mapStateToProps)(AccountDetailScreen)
-
-function mapStateToProps (state) {
- return {
- metamask: state.metamask,
- identities: state.metamask.identities,
- accounts: state.metamask.accounts,
- address: state.metamask.selectedAddress,
- accountDetail: state.appState.accountDetail,
- network: state.metamask.network,
- unapprovedMsgs: valuesFor(state.metamask.unapprovedMsgs),
- shapeShiftTxList: state.metamask.shapeShiftTxList,
- transactions: state.metamask.selectedAddressTxList || [],
- conversionRate: state.metamask.conversionRate,
- currentCurrency: state.metamask.currentCurrency,
- currentAccountTab: state.metamask.currentAccountTab,
- tokens: state.metamask.tokens,
- computedBalances: state.metamask.computedBalances,
- }
-}
-
-inherits(AccountDetailScreen, Component)
-function AccountDetailScreen () {
- Component.call(this)
-}
-
-// Note: This component is no longer used. Leaving the file for reference:
-// - structuring routing for add token
-// - state required for TxList
-// Delete file when those features are complete
-AccountDetailScreen.prototype.render = function () {}
-
-AccountDetailScreen.prototype.subview = function () {
- var subview
- try {
- subview = this.props.accountDetail.subview
- } catch (e) {
- subview = null
- }
-
- switch (subview) {
- case 'transactions':
- return this.tabSections()
- case 'export':
- var state = extend({key: 'export'}, this.props)
- return h(ExportAccountView, state)
- default:
- return this.tabSections()
- }
-}
-
-AccountDetailScreen.prototype.tabSections = function () {
- const { currentAccountTab } = this.props
-
- return h('section.tabSection.full-flex-height.grow-tenx', [
-
- h(TabBar, {
- tabs: [
- { content: 'Sent', key: 'history' },
- { content: 'Tokens', key: 'tokens' },
- ],
- defaultTab: currentAccountTab || 'history',
- tabSelected: (key) => {
- this.props.dispatch(actions.setCurrentAccountTab(key))
- },
- }),
-
- this.tabSwitchView(),
- ])
-}
-
-AccountDetailScreen.prototype.tabSwitchView = function () {
- const props = this.props
- const { address, network } = props
- const { currentAccountTab, tokens } = this.props
-
- switch (currentAccountTab) {
- case 'tokens':
- return h(TokenList, {
- userAddress: address,
- network,
- tokens,
- addToken: () => this.props.dispatch(actions.showAddTokenPage()),
- })
- default:
- return this.transactionList()
- }
-}
-
-AccountDetailScreen.prototype.transactionList = function () {
- const {transactions, unapprovedMsgs, address,
- network, shapeShiftTxList, conversionRate } = this.props
-
- return h(TransactionList, {
- transactions: transactions.sort((a, b) => b.time - a.time),
- network,
- unapprovedMsgs,
- conversionRate,
- address,
- shapeShiftTxList,
- viewPendingTx: (txId) => {
- this.props.dispatch(actions.viewPendingTx(txId))
- },
- })
-}
diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js
index adb52db74..fc9031a65 100644
--- a/ui/app/accounts/import/index.js
+++ b/ui/app/accounts/import/index.js
@@ -2,6 +2,7 @@ const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
+const t = require('../../../i18n')
import Select from 'react-select'
// Subviews
@@ -9,8 +10,8 @@ const JsonImportView = require('./json.js')
const PrivateKeyImportView = require('./private-key.js')
const menuItems = [
- 'Private Key',
- 'JSON File',
+ t('privateKey'),
+ t('jsonFile'),
]
module.exports = connect(mapStateToProps)(AccountImportSubview)
@@ -36,7 +37,7 @@ AccountImportSubview.prototype.render = function () {
h('div.new-account-import-form', [
h('.new-account-import-disclaimer', [
- h('span', 'Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts '),
+ h('span', t('importAccountMsg')),
h('span', {
style: {
cursor: 'pointer',
@@ -47,12 +48,12 @@ AccountImportSubview.prototype.render = function () {
url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts',
})
},
- }, 'here'),
+ }, t('here')),
]),
h('div.new-account-import-form__select-section', [
- h('div.new-account-import-form__select-label', 'Select Type'),
+ h('div.new-account-import-form__select-label', t('selectType')),
h(Select, {
className: 'new-account-import-form__select',
@@ -85,9 +86,9 @@ AccountImportSubview.prototype.renderImportView = function () {
const current = type || menuItems[0]
switch (current) {
- case 'Private Key':
+ case t('privateKey'):
return h(PrivateKeyImportView)
- case 'JSON File':
+ case t('jsonFile'):
return h(JsonImportView)
default:
return h(JsonImportView)
diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js
index c13622166..fa25168f1 100644
--- a/ui/app/accounts/import/json.js
+++ b/ui/app/accounts/import/json.js
@@ -4,6 +4,7 @@ const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('../../actions')
const FileInput = require('react-simple-file-input').default
+const t = require('../../../i18n')
const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts'
@@ -23,11 +24,11 @@ class JsonImportSubview extends Component {
return (
h('div.new-account-import-form__json', [
- h('p', 'Used by a variety of different clients'),
+ h('p', t('usedByClients')),
h('a.warning', {
href: HELP_LINK,
target: '_blank',
- }, 'File import not working? Click here!'),
+ }, t('fileImportFail')),
h(FileInput, {
readAs: 'text',
@@ -42,7 +43,7 @@ class JsonImportSubview extends Component {
h('input.new-account-import-form__input-password', {
type: 'password',
- placeholder: 'Enter password',
+ placeholder: t('enterPassword'),
id: 'json-password-box',
onKeyPress: this.createKeyringOnEnter.bind(this),
}),
@@ -52,13 +53,13 @@ class JsonImportSubview extends Component {
h('button.new-account-create-form__button-cancel', {
onClick: () => this.props.goHome(),
}, [
- 'CANCEL',
+ t('cancel'),
]),
h('button.new-account-create-form__button-create', {
onClick: () => this.createNewKeychain(),
}, [
- 'IMPORT',
+ t('import'),
]),
]),
@@ -83,14 +84,14 @@ class JsonImportSubview extends Component {
const state = this.state
if (!state) {
- const message = 'You must select a valid file to import.'
+ const message = t('validFileImport')
return this.props.displayWarning(message)
}
const { fileContents } = state
if (!fileContents) {
- const message = 'You must select a file to import.'
+ const message = t('needImportFile')
return this.props.displayWarning(message)
}
@@ -98,7 +99,7 @@ class JsonImportSubview extends Component {
const password = passwordInput.value
if (!password) {
- const message = 'You must enter a password for the selected file.'
+ const message = t('needImportPassword')
return this.props.displayWarning(message)
}
diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js
index 12f3a6430..bc9e9384e 100644
--- a/ui/app/accounts/import/private-key.js
+++ b/ui/app/accounts/import/private-key.js
@@ -3,6 +3,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('../../actions')
+const t = require('../../../i18n')
module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView)
@@ -33,9 +34,9 @@ PrivateKeyImportView.prototype.render = function () {
return (
h('div.new-account-import-form__private-key', [
- h('div.new-account-import-form__private-key-password-container', [
+ h('span.new-account-create-form__instruction', t('pastePrivateKey')),
- h('span.new-account-import-form__instruction', 'Paste your private key string here:'),
+ h('div.new-account-import-form__private-key-password-container', [
h('input.new-account-import-form__input-password', {
type: 'password',
@@ -47,16 +48,16 @@ PrivateKeyImportView.prototype.render = function () {
h('div.new-account-import-form__buttons', {}, [
- h('button.new-account-create-form__button-cancel', {
+ h('button.new-account-create-form__button-cancel.allcaps', {
onClick: () => goHome(),
}, [
- 'CANCEL',
+ t('cancel'),
]),
- h('button.new-account-create-form__button-create', {
+ h('button.new-account-create-form__button-create.allcaps', {
onClick: () => this.createNewKeychain(),
}, [
- 'IMPORT',
+ t('import'),
]),
]),
diff --git a/ui/app/accounts/import/seed.js b/ui/app/accounts/import/seed.js
index b4a7c0afa..9ffc669a2 100644
--- a/ui/app/accounts/import/seed.js
+++ b/ui/app/accounts/import/seed.js
@@ -2,6 +2,7 @@ const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
+const t = require('../../../i18n')
module.exports = connect(mapStateToProps)(SeedImportSubview)
@@ -20,11 +21,10 @@ SeedImportSubview.prototype.render = function () {
style: {
},
}, [
- `Paste your seed phrase here!`,
+ t('pasteSeed'),
h('textarea'),
h('br'),
- h('button', 'Submit'),
+ h('button', t('submit')),
])
)
}
-
diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js
index a6b3bba4b..8ef842a2a 100644
--- a/ui/app/accounts/new-account/create-form.js
+++ b/ui/app/accounts/new-account/create-form.js
@@ -3,6 +3,7 @@ const PropTypes = require('prop-types')
const h = require('react-hyperscript')
const { connect } = require('react-redux')
const actions = require('../../actions')
+const t = require('../../../i18n')
class NewAccountCreateForm extends Component {
constructor (props) {
@@ -13,7 +14,7 @@ class NewAccountCreateForm extends Component {
this.state = {
newAccountName: '',
- defaultAccountName: `Account ${newAccountNumber}`,
+ defaultAccountName: t('newAccountNumberName', [newAccountNumber]),
}
}
@@ -24,7 +25,7 @@ class NewAccountCreateForm extends Component {
return h('div.new-account-create-form', [
h('div.new-account-create-form__input-label', {}, [
- 'Account Name',
+ t('accountName'),
]),
h('div.new-account-create-form__input-wrapper', {}, [
@@ -37,16 +38,16 @@ class NewAccountCreateForm extends Component {
h('div.new-account-create-form__buttons', {}, [
- h('button.new-account-create-form__button-cancel', {
+ h('button.new-account-create-form__button-cancel.allcaps', {
onClick: () => this.props.goHome(),
}, [
- 'CANCEL',
+ t('cancel'),
]),
- h('button.new-account-create-form__button-create', {
+ h('button.new-account-create-form__button-create.allcaps', {
onClick: () => this.props.createAccount(newAccountName || defaultAccountName),
}, [
- 'CREATE',
+ t('create'),
]),
]),
diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js
index acf0dc6e4..854568c77 100644
--- a/ui/app/accounts/new-account/index.js
+++ b/ui/app/accounts/new-account/index.js
@@ -3,6 +3,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../actions')
+const t = require('../../../i18n')
const { getCurrentViewContext } = require('../../selectors')
const classnames = require('classnames')
@@ -42,10 +43,10 @@ AccountDetailsModal.prototype.render = function () {
const { displayedForm, displayForm } = this.props
return h('div.new-account', {}, [
-
+
h('div.new-account__header', [
- h('div.new-account__title', 'New Account'),
+ h('div.new-account__title', t('newAccount')),
h('div.new-account__tabs', [
@@ -55,7 +56,7 @@ AccountDetailsModal.prototype.render = function () {
'new-account__tabs__unselected cursor-pointer': displayedForm !== 'CREATE',
}),
onClick: () => displayForm('CREATE'),
- }, 'Create'),
+ }, t('createDen')),
h('div.new-account__tabs__tab', {
className: classnames('new-account__tabs__tab', {
@@ -63,7 +64,7 @@ AccountDetailsModal.prototype.render = function () {
'new-account__tabs__unselected cursor-pointer': displayedForm !== 'IMPORT',
}),
onClick: () => displayForm('IMPORT'),
- }, 'Import'),
+ }, t('import')),
]),
diff --git a/ui/app/actions.js b/ui/app/actions.js
index b56265edc..bc7ee3d07 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -75,6 +75,8 @@ var actions = {
resetAccount,
showNewVaultSeed: showNewVaultSeed,
showInfoPage: showInfoPage,
+ CLOSE_WELCOME_SCREEN: 'CLOSE_WELCOME_SCREEN',
+ closeWelcomeScreen,
// seed recovery actions
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
revealSeedConfirmation: revealSeedConfirmation,
@@ -788,7 +790,7 @@ function updateTransaction (txData) {
function updateAndApproveTx (txData) {
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
return (dispatch) => {
- log.debug(`actions calling background.updateAndApproveTx`)
+ log.debug(`actions calling background.updateAndApproveTx.`)
background.updateAndApproveTransaction(txData, (err) => {
dispatch(actions.hideLoadingIndication())
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
@@ -947,6 +949,12 @@ function showNewVaultSeed (seed) {
}
}
+function closeWelcomeScreen () {
+ return {
+ type: actions.CLOSE_WELCOME_SCREEN,
+ }
+}
+
function backToUnlockView () {
return {
type: actions.BACK_TO_UNLOCK_VIEW,
@@ -1270,8 +1278,10 @@ function retryTransaction (txId) {
if (err) {
return dispatch(actions.displayWarning(err.message))
}
+ const { selectedAddressTxList } = newState
+ const { id: newTxId } = selectedAddressTxList[selectedAddressTxList.length - 1]
dispatch(actions.updateMetamaskState(newState))
- dispatch(actions.viewPendingTx(txId))
+ dispatch(actions.viewPendingTx(newTxId))
})
}
}
diff --git a/ui/app/add-token.js b/ui/app/add-token.js
index b8878b772..b3a5bdc20 100644
--- a/ui/app/add-token.js
+++ b/ui/app/add-token.js
@@ -26,6 +26,7 @@ const fuse = new Fuse(contractList, {
const actions = require('./actions')
const ethUtil = require('ethereumjs-util')
const { tokenInfoGetter } = require('./token-util')
+const t = require('../i18n')
const emptyAddr = '0x0000000000000000000000000000000000000000'
@@ -139,28 +140,28 @@ AddTokenScreen.prototype.validate = function () {
if (customAddress) {
const validAddress = ethUtil.isValidAddress(customAddress)
if (!validAddress) {
- errors.customAddress = 'Address is invalid. '
+ errors.customAddress = t('invalidAddress')
}
const validDecimals = customDecimals !== null && customDecimals >= 0 && customDecimals < 36
if (!validDecimals) {
- errors.customDecimals = 'Decimals must be at least 0, and not over 36.'
+ errors.customDecimals = t('decimalsMustZerotoTen')
}
const symbolLen = customSymbol.trim().length
const validSymbol = symbolLen > 0 && symbolLen < 10
if (!validSymbol) {
- errors.customSymbol = 'Symbol must be between 0 and 10 characters.'
+ errors.customSymbol = t('symbolBetweenZeroTen')
}
const ownAddress = identitiesList.includes(standardAddress)
if (ownAddress) {
- errors.customAddress = 'Personal address detected. Input the token contract address.'
+ errors.customAddress = t('personalAddressDetected')
}
const tokenAlreadyAdded = this.checkExistingAddresses(customAddress)
if (tokenAlreadyAdded) {
- errors.customAddress = 'Token has already been added.'
+ errors.customAddress = t('tokenAlreadyAdded')
}
} else if (
Object.entries(selectedTokens)
@@ -168,7 +169,7 @@ AddTokenScreen.prototype.validate = function () {
isEmpty && !isSelected
), true)
) {
- errors.tokenSelector = 'Must select at least 1 token.'
+ errors.tokenSelector = t('mustSelectOne')
}
return {
@@ -198,7 +199,7 @@ AddTokenScreen.prototype.renderCustomForm = function () {
'add-token__add-custom-field--error': errors.customAddress,
}),
}, [
- h('div.add-token__add-custom-label', 'Token Address'),
+ h('div.add-token__add-custom-label', t('tokenAddress')),
h('input.add-token__add-custom-input', {
type: 'text',
onChange: this.tokenAddressDidChange,
@@ -211,7 +212,7 @@ AddTokenScreen.prototype.renderCustomForm = function () {
'add-token__add-custom-field--error': errors.customSymbol,
}),
}, [
- h('div.add-token__add-custom-label', 'Token Symbol'),
+ h('div.add-token__add-custom-label', t('tokenSymbol')),
h('input.add-token__add-custom-input', {
type: 'text',
onChange: this.tokenSymbolDidChange,
@@ -225,7 +226,7 @@ AddTokenScreen.prototype.renderCustomForm = function () {
'add-token__add-custom-field--error': errors.customDecimals,
}),
}, [
- h('div.add-token__add-custom-label', 'Decimals of Precision'),
+ h('div.add-token__add-custom-label', t('decimal')),
h('input.add-token__add-custom-input', {
type: 'number',
onChange: this.tokenDecimalsDidChange,
@@ -299,11 +300,11 @@ AddTokenScreen.prototype.renderConfirmation = function () {
h('div.add-token', [
h('div.add-token__wrapper', [
h('div.add-token__title-container.add-token__confirmation-title', [
- h('div.add-token__title', 'Add Token'),
- h('div.add-token__description', 'Would you like to add these tokens?'),
+ h('div.add-token__title', t('addToken')),
+ h('div.add-token__description', t('likeToAddTokens')),
]),
h('div.add-token__content-container.add-token__confirmation-content', [
- h('div.add-token__description.add-token__confirmation-description', 'Your balances'),
+ h('div.add-token__description.add-token__confirmation-description', t('balances')),
h('div.add-token__confirmation-token-list',
Object.entries(tokens)
.map(([ address, token ]) => (
@@ -322,10 +323,10 @@ AddTokenScreen.prototype.renderConfirmation = function () {
h('div.add-token__buttons', [
h('button.btn-cancel.add-token__button', {
onClick: () => this.setState({ isShowingConfirmation: false }),
- }, 'Back'),
+ }, t('back')),
h('button.btn-clear.add-token__button', {
onClick: () => addTokens(tokens).then(goHome),
- }, 'Add Tokens'),
+ }, t('addTokens')),
]),
])
)
@@ -341,15 +342,15 @@ AddTokenScreen.prototype.render = function () {
h('div.add-token', [
h('div.add-token__wrapper', [
h('div.add-token__title-container', [
- h('div.add-token__title', 'Add Token'),
- h('div.add-token__description', 'Keep track of the tokens you’ve bought with your MetaMask account. If you bought tokens using a different account, those tokens will not appear here.'),
- h('div.add-token__description', 'Search for tokens or select from our list of popular tokens.'),
+ h('div.add-token__title', t('addToken')),
+ h('div.add-token__description', t('tokenWarning1')),
+ h('div.add-token__description', t('tokenSelection')),
]),
h('div.add-token__content-container', [
h('div.add-token__input-container', [
h('input.add-token__input', {
type: 'text',
- placeholder: 'Search',
+ placeholder: t('search'),
onChange: e => this.setState({ searchQuery: e.target.value }),
}),
h('div.add-token__search-input-error-message', errors.tokenSelector),
@@ -363,7 +364,7 @@ AddTokenScreen.prototype.render = function () {
h('div.add-token__add-custom', {
onClick: () => this.setState({ isCollapsed: !isCollapsed }),
}, [
- 'Add custom token',
+ t('addCustomToken'),
h(`i.fa.fa-angle-${isCollapsed ? 'down' : 'up'}`),
]),
this.renderCustomForm(),
@@ -372,10 +373,10 @@ AddTokenScreen.prototype.render = function () {
h('div.add-token__buttons', [
h('button.btn-cancel.add-token__button', {
onClick: goHome,
- }, 'Cancel'),
+ }, t('cancel')),
h('button.btn-clear.add-token__button', {
onClick: this.onNext,
- }, 'Next'),
+ }, t('next')),
]),
])
)
diff --git a/ui/app/app.js b/ui/app/app.js
index 4e6da24c3..6d9296131 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -4,6 +4,7 @@ const connect = require('react-redux').connect
const h = require('react-hyperscript')
const actions = require('./actions')
const classnames = require('classnames')
+const t = require('../i18n')
// mascara
const MascaraFirstTime = require('../../mascara/src/app/first-time').default
@@ -12,6 +13,8 @@ const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ethe
const OldUIInitializeMenuScreen = require('./first-time/init-menu')
const InitializeMenuScreen = MascaraFirstTime
const NewKeyChainScreen = require('./new-keychain')
+const WelcomeScreen = require('./welcome-screen').default
+
// accounts
const MainContainer = require('./main-container')
const SendTransactionScreen2 = require('./components/send/send-v2-container')
@@ -91,6 +94,7 @@ function mapStateToProps (state) {
betaUI: state.metamask.featureFlags.betaUI,
isRevealingSeedWords: state.metamask.isRevealingSeedWords,
Qr: state.appState.Qr,
+ welcomeScreenSeen: state.metamask.welcomeScreenSeen,
// state needed to get account dropdown temporarily rendering from app bar
identities,
@@ -128,7 +132,7 @@ App.prototype.render = function () {
} = props
const isLoadingNetwork = network === 'loading' && props.currentView.name !== 'config'
const loadMessage = loadingMessage || isLoadingNetwork ?
- `Connecting to ${this.getNetworkName()}` : null
+ this.getConnectingLabel() : null
log.debug('Main ui render function')
return (
@@ -244,6 +248,7 @@ App.prototype.renderAppBar = function () {
isInitialized,
betaUI,
isPopup,
+ welcomeScreenSeen,
} = this.props
if (window.METAMASK_UI_TYPE === 'notification') {
@@ -269,7 +274,7 @@ App.prototype.renderAppBar = function () {
style: {},
}, [
- h('.app-header.flex-row.flex-space-between', {
+ (isInitialized || welcomeScreenSeen || isPopup || !betaUI) && h('.app-header.flex-row.flex-space-between', {
className: classnames({
'app-header--initialized': !isOnboarding,
}),
@@ -289,12 +294,12 @@ App.prototype.renderAppBar = function () {
// metamask name
h('.flex-row', [
- h('h1', 'MetaMask'),
- h('div.beta-label', 'BETA'),
+ h('h1', t('appName')),
+ h('div.beta-label', t('beta')),
]),
]),
- h('div.header__right-actions', [
+ betaUI && isInitialized && h('div.header__right-actions', [
h('div.network-component-wrapper', {
style: {},
}, [
@@ -324,8 +329,14 @@ App.prototype.renderAppBar = function () {
]),
]),
- !isInitialized && !isPopup && betaUI && h('h2.alpha-warning',
- 'Please be aware that this version is still under development'),
+ !isInitialized && !isPopup && betaUI && h('.alpha-warning__container', {}, [
+ h('h2', {
+ className: classnames({
+ 'alpha-warning': welcomeScreenSeen,
+ 'alpha-warning-welcome-screen': !welcomeScreenSeen,
+ }),
+ }, 'Please be aware that this version is still under development'),
+ ]),
])
)
@@ -369,11 +380,18 @@ App.prototype.renderPrimary = function () {
isOnboarding,
betaUI,
isRevealingSeedWords,
+ welcomeScreenSeen,
Qr,
+ isInitialized,
+ isUnlocked,
} = props
const isMascaraOnboarding = isMascara && isOnboarding
const isBetaUIOnboarding = betaUI && isOnboarding && !props.isPopup && !isRevealingSeedWords
+ if (!welcomeScreenSeen && betaUI && !isInitialized && !isUnlocked) {
+ return h(WelcomeScreen)
+ }
+
if (isMascaraOnboarding || isBetaUIOnboarding) {
return h(MascaraFirstTime)
}
@@ -532,6 +550,27 @@ App.prototype.toggleMetamaskActive = function () {
}
}
+App.prototype.getConnectingLabel = function () {
+ const { provider } = this.props
+ const providerName = provider.type
+
+ let name
+
+ if (providerName === 'mainnet') {
+ name = t('connectingToMainnet')
+ } else if (providerName === 'ropsten') {
+ name = t('connectingToRopsten')
+ } else if (providerName === 'kovan') {
+ name = t('connectingToRopsten')
+ } else if (providerName === 'rinkeby') {
+ name = t('connectingToRinkeby')
+ } else {
+ name = t('connectingToUnknown')
+ }
+
+ return name
+}
+
App.prototype.getNetworkName = function () {
const { provider } = this.props
const providerName = provider.type
@@ -539,15 +578,15 @@ App.prototype.getNetworkName = function () {
let name
if (providerName === 'mainnet') {
- name = 'Main Ethereum Network'
+ name = t('mainnet')
} else if (providerName === 'ropsten') {
- name = 'Ropsten Test Network'
+ name = t('ropsten')
} else if (providerName === 'kovan') {
- name = 'Kovan Test Network'
+ name = t('kovan')
} else if (providerName === 'rinkeby') {
- name = 'Rinkeby Test Network'
+ name = t('rinkeby')
} else {
- name = 'Unknown Private Network'
+ name = t('unknownNetwork')
}
return name
diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js
index 1cd7a0847..1612d7b6a 100644
--- a/ui/app/components/account-dropdowns.js
+++ b/ui/app/components/account-dropdowns.js
@@ -9,6 +9,7 @@ const DropdownMenuItem = require('./dropdown').DropdownMenuItem
const Identicon = require('./identicon')
const ethUtil = require('ethereumjs-util')
const copyToClipboard = require('copy-to-clipboard')
+const t = require('../../i18n')
class AccountDropdowns extends Component {
constructor (props) {
@@ -79,7 +80,7 @@ class AccountDropdowns extends Component {
try { // Sometimes keyrings aren't loaded yet:
const type = keyring.type
const isLoose = type !== 'HD Key Tree'
- return isLoose ? h('.keyring-label', 'LOOSE') : null
+ return isLoose ? h('.keyring-label.allcaps', t('loose')) : null
} catch (e) { return }
}
@@ -129,7 +130,7 @@ class AccountDropdowns extends Component {
diameter: 32,
},
),
- h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, 'Create Account'),
+ h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, t('createAccount')),
],
),
h(
@@ -154,7 +155,7 @@ class AccountDropdowns extends Component {
fontSize: '24px',
marginBottom: '5px',
},
- }, 'Import Account'),
+ }, t('importAccount')),
]
),
]
@@ -192,7 +193,7 @@ class AccountDropdowns extends Component {
global.platform.openWindow({ url })
},
},
- 'View account on Etherscan',
+ t('etherscanView'),
),
h(
DropdownMenuItem,
@@ -204,7 +205,7 @@ class AccountDropdowns extends Component {
actions.showQrView(selected, identity ? identity.name : '')
},
},
- 'Show QR Code',
+ t('showQRCode'),
),
h(
DropdownMenuItem,
@@ -216,7 +217,7 @@ class AccountDropdowns extends Component {
copyToClipboard(checkSumAddress)
},
},
- 'Copy Address to clipboard',
+ t('copyAddress'),
),
h(
DropdownMenuItem,
@@ -226,7 +227,7 @@ class AccountDropdowns extends Component {
actions.requestAccountExport()
},
},
- 'Export Private Key',
+ t('exportPrivateKey'),
),
]
)
diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js
index 32b103c86..5637bc8d0 100644
--- a/ui/app/components/account-export.js
+++ b/ui/app/components/account-export.js
@@ -6,6 +6,7 @@ const copyToClipboard = require('copy-to-clipboard')
const actions = require('../actions')
const ethUtil = require('ethereumjs-util')
const connect = require('react-redux').connect
+const t = require('../../i18n')
module.exports = connect(mapStateToProps)(ExportAccountView)
@@ -35,7 +36,7 @@ ExportAccountView.prototype.render = function () {
if (notExporting) return h('div')
if (exportRequested) {
- const warning = `Export private keys at your own risk.`
+ const warning = t('exportPrivateKeyWarning')
return (
h('div', {
style: {
@@ -53,7 +54,7 @@ ExportAccountView.prototype.render = function () {
h('p.error', warning),
h('input#exportAccount.sizing-input', {
type: 'password',
- placeholder: 'confirm password',
+ placeholder: t('confirmPassword').toLowerCase(),
onKeyPress: this.onExportKeyPress.bind(this),
style: {
position: 'relative',
@@ -74,10 +75,10 @@ ExportAccountView.prototype.render = function () {
style: {
marginRight: '10px',
},
- }, 'Submit'),
+ }, t('submit')),
h('button', {
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)),
- }, 'Cancel'),
+ }, t('cancel')),
]),
(this.props.warning) && (
h('span.error', {
@@ -98,7 +99,7 @@ ExportAccountView.prototype.render = function () {
margin: '0 20px',
},
}, [
- h('label', 'Your private key (click to copy):'),
+ h('label', t('copyPrivateKey') + ':'),
h('p.error.cursor-pointer', {
style: {
textOverflow: 'ellipsis',
@@ -112,13 +113,13 @@ ExportAccountView.prototype.render = function () {
}, plainKey),
h('button', {
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)),
- }, 'Done'),
+ }, t('done')),
h('button', {
style: {
marginLeft: '10px',
},
onClick: () => exportAsFile(`MetaMask ${nickname} Private Key`, plainKey),
- }, 'Save as File'),
+ }, t('saveAsFile')),
])
}
}
diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js
index 1a0103d4f..e838e8916 100644
--- a/ui/app/components/account-menu/index.js
+++ b/ui/app/components/account-menu/index.js
@@ -6,6 +6,7 @@ const actions = require('../../actions')
const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu')
const Identicon = require('../identicon')
const { formatBalance } = require('../../util')
+const t = require('../../../i18n')
module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu)
@@ -70,10 +71,10 @@ AccountMenu.prototype.render = function () {
h(Item, {
className: 'account-menu__header',
}, [
- 'My Accounts',
+ t('myAccounts'),
h('button.account-menu__logout-button', {
onClick: lockMetamask,
- }, 'Log out'),
+ }, t('logout')),
]),
h(Divider),
h('div.account-menu__accounts', this.renderAccounts()),
@@ -81,23 +82,23 @@ AccountMenu.prototype.render = function () {
h(Item, {
onClick: () => showNewAccountPage('CREATE'),
icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }),
- text: 'Create Account',
+ text: t('createAccount'),
}),
h(Item, {
onClick: () => showNewAccountPage('IMPORT'),
icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }),
- text: 'Import Account',
+ text: t('importAccount'),
}),
h(Divider),
h(Item, {
onClick: showInfoPage,
- icon: h('img.account-menu__item-icon', { src: 'images/mm-info-icon.svg' }),
- text: 'Info & Help',
+ icon: h('img', { src: 'images/mm-info-icon.svg' }),
+ text: t('infoHelp'),
}),
h(Item, {
onClick: showConfigPage,
icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }),
- text: 'Settings',
+ text: t('settings'),
}),
])
}
@@ -155,6 +156,6 @@ AccountMenu.prototype.indicateIfLoose = function (keyring) {
try { // Sometimes keyrings aren't loaded yet:
const type = keyring.type
const isLoose = type !== 'HD Key Tree'
- return isLoose ? h('.keyring-label', 'IMPORTED') : null
+ return isLoose ? h('.keyring-label.allcaps', t('imported')) : null
} catch (e) { return }
}
diff --git a/ui/app/components/balance.js b/ui/app/components/balance.js
deleted file mode 100644
index 57ca84564..000000000
--- a/ui/app/components/balance.js
+++ /dev/null
@@ -1,89 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const formatBalance = require('../util').formatBalance
-const generateBalanceObject = require('../util').generateBalanceObject
-const Tooltip = require('./tooltip.js')
-const FiatValue = require('./fiat-value.js')
-
-module.exports = EthBalanceComponent
-
-inherits(EthBalanceComponent, Component)
-function EthBalanceComponent () {
- Component.call(this)
-}
-
-EthBalanceComponent.prototype.render = function () {
- var props = this.props
- let { value } = props
- var style = props.style
- var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
- value = value ? formatBalance(value, 6, needsParse) : '...'
- var width = props.width
-
- return (
-
- h('.ether-balance.ether-balance-amount', {
- style: style,
- }, [
- h('div', {
- style: {
- display: 'inline',
- width: width,
- },
- }, this.renderBalance(value)),
- ])
-
- )
-}
-EthBalanceComponent.prototype.renderBalance = function (value) {
- var props = this.props
- if (value === 'None') return value
- if (value === '...') return value
- var balanceObj = generateBalanceObject(value, props.shorten ? 1 : 3)
- var balance
- var splitBalance = value.split(' ')
- var ethNumber = splitBalance[0]
- var ethSuffix = splitBalance[1]
- const showFiat = 'showFiat' in props ? props.showFiat : true
-
- if (props.shorten) {
- balance = balanceObj.shortBalance
- } else {
- balance = balanceObj.balance
- }
-
- var label = balanceObj.label
-
- return (
- h(Tooltip, {
- position: 'bottom',
- title: `${ethNumber} ${ethSuffix}`,
- }, h('div.flex-column', [
- h('.flex-row', {
- style: {
- alignItems: 'flex-end',
- lineHeight: '13px',
- fontFamily: 'Montserrat Light',
- textRendering: 'geometricPrecision',
- },
- }, [
- h('div', {
- style: {
- width: '100%',
- textAlign: 'right',
- },
- }, this.props.incoming ? `+${balance}` : balance),
- h('div', {
- style: {
- color: ' #AEAEAE',
- fontSize: '12px',
- marginLeft: '5px',
- },
- }, label),
- ]),
-
- showFiat ? h(FiatValue, { value: props.value }) : null,
- ]))
- )
-}
diff --git a/ui/app/components/binary-renderer.js b/ui/app/components/binary-renderer.js
deleted file mode 100644
index 0b6a1f5c2..000000000
--- a/ui/app/components/binary-renderer.js
+++ /dev/null
@@ -1,46 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const ethUtil = require('ethereumjs-util')
-const extend = require('xtend')
-
-module.exports = BinaryRenderer
-
-inherits(BinaryRenderer, Component)
-function BinaryRenderer () {
- Component.call(this)
-}
-
-BinaryRenderer.prototype.render = function () {
- const props = this.props
- const { value, style } = props
- const text = this.hexToText(value)
-
- const defaultStyle = extend({
- width: '315px',
- maxHeight: '210px',
- resize: 'none',
- border: 'none',
- background: 'white',
- padding: '3px',
- }, style)
-
- return (
- h('textarea.font-small', {
- readOnly: true,
- style: defaultStyle,
- defaultValue: text,
- })
- )
-}
-
-BinaryRenderer.prototype.hexToText = function (hex) {
- try {
- const stripped = ethUtil.stripHexPrefix(hex)
- const buff = Buffer.from(stripped, 'hex')
- return buff.toString('utf8')
- } catch (e) {
- return hex
- }
-}
-
diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js
index 22e37602e..70701b039 100644
--- a/ui/app/components/bn-as-decimal-input.js
+++ b/ui/app/components/bn-as-decimal-input.js
@@ -4,6 +4,7 @@ const inherits = require('util').inherits
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
const extend = require('xtend')
+const t = require('../../i18n')
module.exports = BnAsDecimalInput
@@ -136,13 +137,13 @@ BnAsDecimalInput.prototype.constructWarning = function () {
let message = name ? name + ' ' : ''
if (min && max) {
- message += `must be greater than or equal to ${newMin} ${suffix} and less than or equal to ${newMax} ${suffix}.`
+ message += t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`])
} else if (min) {
- message += `must be greater than or equal to ${newMin} ${suffix}.`
+ message += t('greaterThanMin', [`${newMin} ${suffix}`])
} else if (max) {
- message += `must be less than or equal to ${newMax} ${suffix}.`
+ message += t('lessThanMax', [`${newMax} ${suffix}`])
} else {
- message += 'Invalid input.'
+ message += t('invalidInput')
}
return message
diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js
index d5958787b..1e277a94b 100644
--- a/ui/app/components/buy-button-subview.js
+++ b/ui/app/components/buy-button-subview.js
@@ -9,6 +9,7 @@ const Loading = require('./loading')
const AccountPanel = require('./account-panel')
const RadioList = require('./custom-radio-list')
const networkNames = require('../../../app/scripts/config.js').networkNames
+const t = require('../../i18n')
module.exports = connect(mapStateToProps)(BuyButtonSubview)
@@ -76,7 +77,7 @@ BuyButtonSubview.prototype.headerSubview = function () {
paddingTop: '4px',
paddingBottom: '4px',
},
- }, 'Deposit Eth'),
+ }, t('depositEth')),
]),
// loading indication
@@ -118,7 +119,7 @@ BuyButtonSubview.prototype.headerSubview = function () {
paddingTop: '4px',
paddingBottom: '4px',
},
- }, 'Select Service'),
+ }, t('selectService')),
]),
])
@@ -143,7 +144,7 @@ BuyButtonSubview.prototype.primarySubview = function () {
case '4':
case '42':
const networkName = networkNames[network]
- const label = `${networkName} Test Faucet`
+ const label = `${networkName} ${t('testFaucet')}`
return (
h('div.flex-column', {
style: {
@@ -164,14 +165,14 @@ BuyButtonSubview.prototype.primarySubview = function () {
style: {
marginTop: '15px',
},
- }, 'Borrow With Dharma (Beta)')
+ }, t('borrowDharma'))
) : null,
])
)
default:
return (
- h('h2.error', 'Unknown network ID')
+ h('h2.error', t('unknownNetworkId'))
)
}
@@ -203,8 +204,8 @@ BuyButtonSubview.prototype.mainnetSubview = function () {
'ShapeShift',
],
subtext: {
- 'Coinbase': 'Crypto/FIAT (USA only)',
- 'ShapeShift': 'Crypto',
+ 'Coinbase': `${t('crypto')}/${t('fiat')} (${t('usaOnly')})`,
+ 'ShapeShift': t('crypto'),
},
onClick: this.radioHandler.bind(this),
}),
diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js
index f70208625..e442b43d5 100644
--- a/ui/app/components/coinbase-form.js
+++ b/ui/app/components/coinbase-form.js
@@ -3,6 +3,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../actions')
+const t = require('../../i18n')
module.exports = connect(mapStateToProps)(CoinbaseForm)
@@ -37,11 +38,11 @@ CoinbaseForm.prototype.render = function () {
}, [
h('button.btn-green', {
onClick: this.toCoinbase.bind(this),
- }, 'Continue to Coinbase'),
+ }, t('continueToCoinbase')),
h('button.btn-red', {
onClick: () => props.dispatch(actions.goHome()),
- }, 'Cancel'),
+ }, t('cancel')),
]),
])
}
diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js
index a25d0719c..355f78d45 100644
--- a/ui/app/components/copyButton.js
+++ b/ui/app/components/copyButton.js
@@ -2,6 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const copyToClipboard = require('copy-to-clipboard')
+const t = require('../../i18n')
const Tooltip = require('./tooltip')
@@ -22,7 +23,7 @@ CopyButton.prototype.render = function () {
const value = props.value
const copied = state.copied
- const message = copied ? 'Copied' : props.title || ' Copy '
+ const message = copied ? t('copiedButton') : props.title || t('copyButton')
return h('.copy-button', {
style: {
diff --git a/ui/app/components/copyable.js b/ui/app/components/copyable.js
index a4f6f4bc6..fca7d3863 100644
--- a/ui/app/components/copyable.js
+++ b/ui/app/components/copyable.js
@@ -4,6 +4,7 @@ const inherits = require('util').inherits
const Tooltip = require('./tooltip')
const copyToClipboard = require('copy-to-clipboard')
+const t = require('../../i18n')
module.exports = Copyable
@@ -22,7 +23,7 @@ Copyable.prototype.render = function () {
const { copied } = state
return h(Tooltip, {
- title: copied ? 'Copied!' : 'Copy',
+ title: copied ? t('copiedExclamation') : t('copy'),
position: 'bottom',
}, h('span', {
style: {
diff --git a/ui/app/components/currency-input.js b/ui/app/components/currency-input.js
index 6f7862e51..ece3eb43d 100644
--- a/ui/app/components/currency-input.js
+++ b/ui/app/components/currency-input.js
@@ -8,8 +8,12 @@ inherits(CurrencyInput, Component)
function CurrencyInput (props) {
Component.call(this)
+ const sanitizedValue = sanitizeValue(props.value)
+
this.state = {
- value: sanitizeValue(props.value),
+ value: sanitizedValue,
+ emptyState: false,
+ focused: false,
}
}
@@ -58,9 +62,11 @@ CurrencyInput.prototype.handleChange = function (newValue) {
if (value === '0' && newValue[newValueLastIndex] === '0') {
parsedValue = parsedValue.slice(0, newValueLastIndex)
}
-
const sanitizedValue = sanitizeValue(parsedValue)
- this.setState({ value: sanitizedValue })
+ this.setState({
+ value: sanitizedValue,
+ emptyState: newValue === '' && sanitizedValue === '0',
+ })
onInputChange(sanitizedValue)
}
@@ -85,18 +91,22 @@ CurrencyInput.prototype.render = function () {
placeholder,
readOnly,
inputRef,
+ type,
} = this.props
+ const { emptyState, focused } = this.state
const inputSizeMultiplier = readOnly ? 1 : 1.2
const valueToRender = this.getValueToRender()
-
return h('input', {
className,
- value: valueToRender,
- placeholder,
+ type,
+ value: emptyState ? '' : valueToRender,
+ placeholder: focused ? '' : placeholder,
size: valueToRender.length * inputSizeMultiplier,
readOnly,
+ onFocus: () => this.setState({ focused: true, emptyState: valueToRender === '0' }),
+ onBlur: () => this.setState({ focused: false, emptyState: false }),
onChange: e => this.handleChange(e.target.value),
ref: inputRef,
})
diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js
index 826d2cd4b..d8384c19d 100644
--- a/ui/app/components/customize-gas-modal/index.js
+++ b/ui/app/components/customize-gas-modal/index.js
@@ -3,6 +3,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../actions')
+const t = require('../../../i18n')
const GasModalCard = require('./gas-modal-card')
const ethUtil = require('ethereumjs-util')
@@ -21,12 +22,14 @@ const {
conversionUtil,
multiplyCurrencies,
conversionGreaterThan,
+ conversionMax,
subtractCurrencies,
} = require('../../conversion-util')
const {
getGasPrice,
getGasLimit,
+ getForceGasMin,
conversionRateSelector,
getSendAmount,
getSelectedToken,
@@ -44,6 +47,7 @@ function mapStateToProps (state) {
return {
gasPrice: getGasPrice(state),
gasLimit: getGasLimit(state),
+ forceGasMin: getForceGasMin(state),
conversionRate,
amount: getSendAmount(state),
maxModeOn: getSendMaxModeState(state),
@@ -114,9 +118,9 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) {
updateSendAmount(maxAmount)
}
- updateGasPrice(gasPrice)
- updateGasLimit(gasLimit)
- updateGasTotal(gasTotal)
+ updateGasPrice(ethUtil.addHexPrefix(gasPrice))
+ updateGasLimit(ethUtil.addHexPrefix(gasLimit))
+ updateGasTotal(ethUtil.addHexPrefix(gasTotal))
hideModal()
}
@@ -146,7 +150,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) {
})
if (!balanceIsSufficient) {
- error = 'Insufficient balance for current gas total'
+ error = t('balanceIsInsufficientGas')
}
const gasLimitTooLow = gasLimit && conversionGreaterThan(
@@ -162,7 +166,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) {
)
if (gasLimitTooLow) {
- error = 'Gas limit must be at least 21000'
+ error = t('gasLimitTooLow')
}
this.setState({ error })
@@ -217,7 +221,7 @@ CustomizeGasModal.prototype.convertAndSetGasPrice = function (newGasPrice) {
}
CustomizeGasModal.prototype.render = function () {
- const { hideModal } = this.props
+ const { hideModal, forceGasMin } = this.props
const { gasPrice, gasLimit, gasTotal, error, priceSigZeros, priceSigDec } = this.state
let convertedGasPrice = conversionUtil(gasPrice, {
@@ -229,6 +233,22 @@ CustomizeGasModal.prototype.render = function () {
convertedGasPrice += convertedGasPrice.match(/[.]/) ? priceSigZeros : `${priceSigDec}${priceSigZeros}`
+ let newGasPrice = gasPrice
+ if (forceGasMin) {
+ const convertedMinPrice = conversionUtil(forceGasMin, {
+ fromNumericBase: 'hex',
+ toNumericBase: 'dec',
+ })
+ convertedGasPrice = conversionMax(
+ { value: convertedMinPrice, fromNumericBase: 'dec' },
+ { value: convertedGasPrice, fromNumericBase: 'dec' }
+ )
+ newGasPrice = conversionMax(
+ { value: gasPrice, fromNumericBase: 'hex' },
+ { value: forceGasMin, fromNumericBase: 'hex' }
+ )
+ }
+
const convertedGasLimit = conversionUtil(gasLimit, {
fromNumericBase: 'hex',
toNumericBase: 'dec',
@@ -239,7 +259,7 @@ CustomizeGasModal.prototype.render = function () {
}, [
h('div.send-v2__customize-gas__header', {}, [
- h('div.send-v2__customize-gas__title', 'Customize Gas'),
+ h('div.send-v2__customize-gas__title', t('customGas')),
h('div.send-v2__customize-gas__close', {
onClick: hideModal,
@@ -251,12 +271,12 @@ CustomizeGasModal.prototype.render = function () {
h(GasModalCard, {
value: convertedGasPrice,
- min: MIN_GAS_PRICE_GWEI,
+ min: forceGasMin || MIN_GAS_PRICE_GWEI,
// max: 1000,
step: multiplyCurrencies(MIN_GAS_PRICE_GWEI, 10),
onChange: value => this.convertAndSetGasPrice(value),
- title: 'Gas Price (GWEI)',
- copy: 'We calculate the suggested gas prices based on network success rates.',
+ title: t('gasPrice'),
+ copy: t('gasPriceCalculation'),
}),
h(GasModalCard, {
@@ -265,8 +285,8 @@ CustomizeGasModal.prototype.render = function () {
// max: 100000,
step: 1,
onChange: value => this.convertAndSetGasLimit(value),
- title: 'Gas Limit',
- copy: 'We calculate the suggested gas limit based on network success rates.',
+ title: t('gasLimit'),
+ copy: t('gasLimitCalculation'),
}),
]),
@@ -279,16 +299,16 @@ CustomizeGasModal.prototype.render = function () {
h('div.send-v2__customize-gas__revert', {
onClick: () => this.revert(),
- }, ['Revert']),
+ }, [t('revert')]),
h('div.send-v2__customize-gas__buttons', [
- h('div.send-v2__customize-gas__cancel', {
+ h('div.send-v2__customize-gas__cancel.allcaps', {
onClick: this.props.hideModal,
- }, ['CANCEL']),
+ }, [t('cancel')]),
- h(`div.send-v2__customize-gas__save${error ? '__error' : ''}`, {
- onClick: () => !error && this.save(gasPrice, gasLimit, gasTotal),
- }, ['SAVE']),
+ h(`div.send-v2__customize-gas__save${error ? '__error' : ''}.allcaps`, {
+ onClick: () => !error && this.save(newGasPrice, gasLimit, gasTotal),
+ }, [t('save')]),
]),
]),
diff --git a/ui/app/components/dropdowns/account-options-dropdown.js b/ui/app/components/dropdowns/account-options-dropdown.js
deleted file mode 100644
index f74c0a2d4..000000000
--- a/ui/app/components/dropdowns/account-options-dropdown.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const AccountDropdowns = require('./components/account-dropdowns')
-
-inherits(AccountOptionsDropdown, Component)
-function AccountOptionsDropdown () {
- Component.call(this)
-}
-
-module.exports = AccountOptionsDropdown
-
-// TODO: specify default props and proptypes
-// TODO: hook up to state, connect to redux to clean up API
-// TODO: selectedAddress is not defined... should we use selected?
-AccountOptionsDropdown.prototype.render = function () {
- const { selected, network, identities, style, dropdownWrapperStyle, menuItemStyles } = this.props
-
- return h(AccountDropdowns, {
- enableAccountOptions: true,
- enableAccountsSelector: false,
- selected,
- network,
- identities,
- style: style || {},
- dropdownWrapperStyle: dropdownWrapperStyle || {},
- menuItemStyles: menuItemStyles || {},
- }, [])
-}
diff --git a/ui/app/components/dropdowns/account-selection-dropdown.js b/ui/app/components/dropdowns/account-selection-dropdown.js
deleted file mode 100644
index 2f6452b15..000000000
--- a/ui/app/components/dropdowns/account-selection-dropdown.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const AccountDropdowns = require('./components/account-dropdowns')
-
-inherits(AccountSelectionDropdown, Component)
-function AccountSelectionDropdown () {
- Component.call(this)
-}
-
-module.exports = AccountSelectionDropdown
-
-// TODO: specify default props and proptypes
-// TODO: hook up to state, connect to redux to clean up API
-// TODO: selectedAddress is not defined... should we use selected?
-AccountSelectionDropdown.prototype.render = function () {
- const { selected, network, identities, style, dropdownWrapperStyle, menuItemStyles } = this.props
-
- return h(AccountDropdowns, {
- enableAccountOptions: false,
- enableAccountsSelector: true,
- selected,
- network,
- identities,
- style: style || {},
- dropdownWrapperStyle: dropdownWrapperStyle || {},
- menuItemStyles: menuItemStyles || {},
- }, [])
-}
diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js
index 40918cc53..e5359c1d6 100644
--- a/ui/app/components/dropdowns/components/account-dropdowns.js
+++ b/ui/app/components/dropdowns/components/account-dropdowns.js
@@ -10,6 +10,7 @@ const Identicon = require('../../identicon')
const ethUtil = require('ethereumjs-util')
const copyToClipboard = require('copy-to-clipboard')
const { formatBalance } = require('../../../util')
+const t = require('../../../../i18n')
class AccountDropdowns extends Component {
constructor (props) {
@@ -121,7 +122,7 @@ class AccountDropdowns extends Component {
flex: '3 3 auto',
},
}, [
- h('span.account-dropdown-edit-button', {
+ h('span.account-dropdown-edit-button.allcaps', {
style: {
fontSize: '16px',
},
@@ -129,7 +130,7 @@ class AccountDropdowns extends Component {
actions.showEditAccountModal(identity)
},
}, [
- 'Edit',
+ t('edit'),
]),
]),
@@ -143,7 +144,7 @@ class AccountDropdowns extends Component {
try { // Sometimes keyrings aren't loaded yet:
const type = keyring.type
const isLoose = type !== 'HD Key Tree'
- return isLoose ? h('.keyring-label', 'IMPORTED') : null
+ return isLoose ? h('.keyring-label.allcaps', t('loose')) : null
} catch (e) { return }
}
@@ -201,7 +202,7 @@ class AccountDropdowns extends Component {
fontSize: '16px',
lineHeight: '23px',
},
- }, 'Create Account'),
+ }, t('createAccount')),
],
),
h(
@@ -235,7 +236,7 @@ class AccountDropdowns extends Component {
fontSize: '16px',
lineHeight: '23px',
},
- }, 'Import Account'),
+ }, t('importAccount')),
]
),
]
@@ -286,7 +287,7 @@ class AccountDropdowns extends Component {
menuItemStyles,
),
},
- 'Account Details',
+ t('accountDetails'),
),
h(
DropdownMenuItem,
@@ -302,7 +303,7 @@ class AccountDropdowns extends Component {
menuItemStyles,
),
},
- 'View account on Etherscan',
+ t('etherscanView'),
),
h(
DropdownMenuItem,
@@ -318,7 +319,7 @@ class AccountDropdowns extends Component {
menuItemStyles,
),
},
- 'Copy Address to clipboard',
+ t('copyAddress'),
),
h(
DropdownMenuItem,
@@ -330,7 +331,7 @@ class AccountDropdowns extends Component {
menuItemStyles,
),
},
- 'Export Private Key',
+ t('exportPrivateKey'),
),
h(
DropdownMenuItem,
@@ -345,7 +346,7 @@ class AccountDropdowns extends Component {
menuItemStyles,
),
},
- 'Add Token',
+ t('addToken'),
),
]
@@ -463,4 +464,3 @@ function mapStateToProps (state) {
}
module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDropdowns)
-
diff --git a/ui/app/components/dropdowns/index.js b/ui/app/components/dropdowns/index.js
index fa66f5000..605507058 100644
--- a/ui/app/components/dropdowns/index.js
+++ b/ui/app/components/dropdowns/index.js
@@ -1,17 +1,11 @@
// Reusable Dropdown Components
// TODO: Refactor into separate components
const Dropdown = require('./components/dropdown').Dropdown
-const AccountDropdowns = require('./components/account-dropdowns')
// App-Specific Instances
-const AccountSelectionDropdown = require('./account-selection-dropdown')
-const AccountOptionsDropdown = require('./account-options-dropdown')
const NetworkDropdown = require('./network-dropdown').default
module.exports = {
- AccountSelectionDropdown,
- AccountOptionsDropdown,
NetworkDropdown,
Dropdown,
- AccountDropdowns,
}
diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js
index ff10c0758..5afe730c1 100644
--- a/ui/app/components/dropdowns/network-dropdown.js
+++ b/ui/app/components/dropdowns/network-dropdown.js
@@ -6,6 +6,7 @@ const actions = require('../../actions')
const Dropdown = require('./components/dropdown').Dropdown
const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem
const NetworkDropdownIcon = require('./components/network-dropdown-icon')
+const t = require('../../../i18n')
const R = require('ramda')
// classes from nodes of the toggle element.
@@ -93,13 +94,13 @@ NetworkDropdown.prototype.render = function () {
}, [
h('div.network-dropdown-header', {}, [
- h('div.network-dropdown-title', {}, 'Networks'),
+ h('div.network-dropdown-title', {}, t('networks')),
h('div.network-dropdown-divider'),
h('div.network-dropdown-content',
{},
- 'The default network for Ether transactions is Main Net.'
+ t('defaultNetwork')
),
]),
@@ -121,7 +122,7 @@ NetworkDropdown.prototype.render = function () {
style: {
color: providerType === 'mainnet' ? '#ffffff' : '#9b9b9b',
},
- }, 'Main Ethereum Network'),
+ }, t('mainnet')),
]
),
@@ -143,7 +144,7 @@ NetworkDropdown.prototype.render = function () {
style: {
color: providerType === 'ropsten' ? '#ffffff' : '#9b9b9b',
},
- }, 'Ropsten Test Network'),
+ }, t('ropsten')),
]
),
@@ -165,7 +166,7 @@ NetworkDropdown.prototype.render = function () {
style: {
color: providerType === 'kovan' ? '#ffffff' : '#9b9b9b',
},
- }, 'Kovan Test Network'),
+ }, t('kovan')),
]
),
@@ -187,7 +188,7 @@ NetworkDropdown.prototype.render = function () {
style: {
color: providerType === 'rinkeby' ? '#ffffff' : '#9b9b9b',
},
- }, 'Rinkeby Test Network'),
+ }, t('rinkeby')),
]
),
@@ -209,7 +210,7 @@ NetworkDropdown.prototype.render = function () {
style: {
color: activeNetwork === 'http://localhost:8545' ? '#ffffff' : '#9b9b9b',
},
- }, 'Localhost 8545'),
+ }, t('localhost')),
]
),
@@ -233,7 +234,7 @@ NetworkDropdown.prototype.render = function () {
style: {
color: activeNetwork === 'custom' ? '#ffffff' : '#9b9b9b',
},
- }, 'Custom RPC'),
+ }, t('customRPC')),
]
),
@@ -248,15 +249,15 @@ NetworkDropdown.prototype.getNetworkName = function () {
let name
if (providerName === 'mainnet') {
- name = 'Main Ethereum Network'
+ name = t('mainnet')
} else if (providerName === 'ropsten') {
- name = 'Ropsten Test Network'
+ name = t('ropsten')
} else if (providerName === 'kovan') {
- name = 'Kovan Test Network'
+ name = t('kovan')
} else if (providerName === 'rinkeby') {
- name = 'Rinkeby Test Network'
+ name = t('rinkeby')
} else {
- name = 'Unknown Private Network'
+ name = t('unknownNetwork')
}
return name
diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js
index dc7a985e3..a4f93b505 100644
--- a/ui/app/components/dropdowns/token-menu-dropdown.js
+++ b/ui/app/components/dropdowns/token-menu-dropdown.js
@@ -3,6 +3,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../actions')
+const t = require('../../../i18n')
module.exports = connect(null, mapDispatchToProps)(TokenMenuDropdown)
@@ -43,7 +44,7 @@ TokenMenuDropdown.prototype.render = function () {
showHideTokenConfirmationModal(this.props.token)
this.props.onClose()
},
- }, 'Hide Token'),
+ }, t('hideToken')),
]),
]),
diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js
index 6553053f7..add67ea35 100644
--- a/ui/app/components/ens-input.js
+++ b/ui/app/components/ens-input.js
@@ -8,6 +8,7 @@ const ENS = require('ethjs-ens')
const networkMap = require('ethjs-ens/lib/network-map.json')
const ensRE = /.+\..+$/
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
+const t = require('../../i18n')
module.exports = EnsInput
@@ -89,13 +90,13 @@ EnsInput.prototype.lookupEnsName = function () {
log.info(`ENS attempting to resolve name: ${recipient}`)
this.ens.lookup(recipient.trim())
.then((address) => {
- if (address === ZERO_ADDRESS) throw new Error('No address has been set for this name.')
+ if (address === ZERO_ADDRESS) throw new Error(t('noAddressForName'))
if (address !== ensResolution) {
this.setState({
loadingEns: false,
ensResolution: address,
nickname: recipient.trim(),
- hoverText: address + '\nClick to Copy',
+ hoverText: address + '\n' + t('clickCopy'),
ensFailure: false,
})
}
diff --git a/ui/app/components/hex-as-decimal-input.js b/ui/app/components/hex-as-decimal-input.js
index 4a71e9585..a43d44f89 100644
--- a/ui/app/components/hex-as-decimal-input.js
+++ b/ui/app/components/hex-as-decimal-input.js
@@ -4,6 +4,7 @@ const inherits = require('util').inherits
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
const extend = require('xtend')
+const t = require('../../i18n')
module.exports = HexAsDecimalInput
@@ -126,13 +127,13 @@ HexAsDecimalInput.prototype.constructWarning = function () {
let message = name ? name + ' ' : ''
if (min && max) {
- message += `must be greater than or equal to ${min} and less than or equal to ${max}.`
+ message += t('betweenMinAndMax', [min, max])
} else if (min) {
- message += `must be greater than or equal to ${min}.`
+ message += t('greaterThanMin', [min])
} else if (max) {
- message += `must be less than or equal to ${max}.`
+ message += t('lessThanMax', [max])
} else {
- message += 'Invalid input.'
+ message += t('invalidInput')
}
return message
diff --git a/ui/app/components/input-number.js b/ui/app/components/input-number.js
index fd8c5c309..5600e35ee 100644
--- a/ui/app/components/input-number.js
+++ b/ui/app/components/input-number.js
@@ -55,6 +55,7 @@ InputNumber.prototype.render = function () {
className: 'customize-gas-input',
value,
placeholder,
+ type: 'number',
onInputChange: newValue => {
this.setValue(newValue)
},
diff --git a/ui/app/components/mini-account-panel.js b/ui/app/components/mini-account-panel.js
deleted file mode 100644
index c09cf5b7a..000000000
--- a/ui/app/components/mini-account-panel.js
+++ /dev/null
@@ -1,74 +0,0 @@
-const inherits = require('util').inherits
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const Identicon = require('./identicon')
-
-module.exports = AccountPanel
-
-
-inherits(AccountPanel, Component)
-function AccountPanel () {
- Component.call(this)
-}
-
-AccountPanel.prototype.render = function () {
- var props = this.props
- var picOrder = props.picOrder || 'left'
- const { imageSeed } = props
-
- return (
-
- h('.identity-panel.flex-row.flex-left', {
- style: {
- cursor: props.onClick ? 'pointer' : undefined,
- },
- onClick: props.onClick,
- }, [
-
- this.genIcon(imageSeed, picOrder),
-
- h('div.flex-column.flex-justify-center', {
- style: {
- lineHeight: '15px',
- order: 2,
- display: 'flex',
- alignItems: picOrder === 'left' ? 'flex-begin' : 'flex-end',
- },
- }, this.props.children),
- ])
- )
-}
-
-AccountPanel.prototype.genIcon = function (seed, picOrder) {
- const props = this.props
-
- // When there is no seed value, this is a contract creation.
- // We then show the contract icon.
- if (!seed) {
- return h('.identicon-wrapper.flex-column.select-none', {
- style: {
- order: picOrder === 'left' ? 1 : 3,
- },
- }, [
- h('i.fa.fa-file-text-o.fa-lg', {
- style: {
- fontSize: '42px',
- transform: 'translate(0px, -16px)',
- },
- }),
- ])
- }
-
- // If there was a seed, we return an identicon for that address.
- return h('.identicon-wrapper.flex-column.select-none', {
- style: {
- order: picOrder === 'left' ? 1 : 3,
- },
- }, [
- h(Identicon, {
- address: seed,
- imageify: props.imageifyIdenticons,
- }),
- ])
-}
-
diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js
index c1f7a3236..75f989e86 100644
--- a/ui/app/components/modals/account-details-modal.js
+++ b/ui/app/components/modals/account-details-modal.js
@@ -8,6 +8,7 @@ const { getSelectedIdentity } = require('../../selectors')
const genAccountLink = require('../../../lib/account-link.js')
const QrView = require('../qr-code')
const EditableLabel = require('../editable-label')
+const t = require('../../../i18n')
function mapStateToProps (state) {
return {
@@ -64,12 +65,12 @@ AccountDetailsModal.prototype.render = function () {
h('button.btn-clear.account-modal__button', {
onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }),
- }, 'View account on Etherscan'),
+ }, t('etherscanView')),
// Holding on redesign for Export Private Key functionality
h('button.btn-clear.account-modal__button', {
onClick: () => showExportPrivateKeyModal(),
- }, 'Export private key'),
+ }, t('exportPrivateKey')),
])
}
diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js
index c548fb7b3..08540aa76 100644
--- a/ui/app/components/modals/account-modal-container.js
+++ b/ui/app/components/modals/account-modal-container.js
@@ -5,6 +5,7 @@ const connect = require('react-redux').connect
const actions = require('../../actions')
const { getSelectedIdentity } = require('../../selectors')
const Identicon = require('../identicon')
+const t = require('../../../i18n')
function mapStateToProps (state) {
return {
@@ -59,7 +60,7 @@ AccountModalContainer.prototype.render = function () {
h('i.fa.fa-angle-left.fa-lg'),
- h('span.account-modal-back__text', ' Back'),
+ h('span.account-modal-back__text', ' ' + t('back')),
]),
diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js
index 74a7a847e..7eb73c3a6 100644
--- a/ui/app/components/modals/buy-options-modal.js
+++ b/ui/app/components/modals/buy-options-modal.js
@@ -4,6 +4,7 @@ const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../actions')
const networkNames = require('../../../../app/scripts/config.js').networkNames
+const t = require('../../../i18n')
function mapStateToProps (state) {
return {
@@ -56,15 +57,15 @@ BuyOptions.prototype.render = function () {
}, [
h('div.buy-modal-content-title', {
style: {},
- }, 'Transfers'),
- h('div', {}, 'How would you like to deposit Ether?'),
+ }, t('transfers')),
+ h('div', {}, t('howToDeposit')),
]),
h('div.buy-modal-content-options.flex-column.flex-center', {}, [
isTestNetwork
- ? this.renderModalContentOption(networkName, 'Test Faucet', () => toFaucet(network))
- : this.renderModalContentOption('Coinbase', 'Deposit with Fiat', () => toCoinbase(address)),
+ ? this.renderModalContentOption(networkName, t('testFaucet'), () => toFaucet(network))
+ : this.renderModalContentOption('Coinbase', t('depositFiat'), () => toCoinbase(address)),
// h('div.buy-modal-content-option', {}, [
// h('div.buy-modal-content-option-title', {}, 'Shapeshift'),
@@ -72,8 +73,8 @@ BuyOptions.prototype.render = function () {
// ]),,
this.renderModalContentOption(
- 'Direct Deposit',
- 'Deposit from another account',
+ t('directDeposit'),
+ t('depositFromAccount'),
() => this.goToAccountDetailsModal()
),
@@ -84,7 +85,7 @@ BuyOptions.prototype.render = function () {
background: 'white',
},
onClick: () => { this.props.hideModal() },
- }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, 'Cancel')),
+ }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, t('cancel'))),
]),
])
}
diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js
index 7547dbcf5..b642513d7 100644
--- a/ui/app/components/modals/deposit-ether-modal.js
+++ b/ui/app/components/modals/deposit-ether-modal.js
@@ -5,18 +5,18 @@ const connect = require('react-redux').connect
const actions = require('../../actions')
const networkNames = require('../../../../app/scripts/config.js').networkNames
const ShapeshiftForm = require('../shapeshift-form')
-
-const DIRECT_DEPOSIT_ROW_TITLE = 'Directly Deposit Ether'
-const DIRECT_DEPOSIT_ROW_TEXT = `If you already have some Ether, the quickest way to get Ether in
-your new wallet by direct deposit.`
-const COINBASE_ROW_TITLE = 'Buy on Coinbase'
-const COINBASE_ROW_TEXT = `Coinbase is the world’s most popular way to buy and sell bitcoin,
-ethereum, and litecoin.`
-const SHAPESHIFT_ROW_TITLE = 'Deposit with ShapeShift'
-const SHAPESHIFT_ROW_TEXT = `If you own other cryptocurrencies, you can trade and deposit Ether
-directly into your MetaMask wallet. No Account Needed.`
-const FAUCET_ROW_TITLE = 'Test Faucet'
-const facuetRowText = networkName => `Get Ether from a faucet for the ${networkName}`
+const t = require('../../../i18n')
+
+const DIRECT_DEPOSIT_ROW_TITLE = t('directDepositEther')
+const DIRECT_DEPOSIT_ROW_TEXT = t('directDepositEtherExplainer')
+const COINBASE_ROW_TITLE = t('buyCoinbase')
+const COINBASE_ROW_TEXT = t('buyCoinbaseExplainer')
+const SHAPESHIFT_ROW_TITLE = t('depositShapeShift')
+const SHAPESHIFT_ROW_TEXT = t('depositShapeShiftExplainer')
+const FAUCET_ROW_TITLE = t('testFaucet')
+const facuetRowText = (networkName) => {
+ return t('getEtherFromFaucet', [networkName])
+}
function mapStateToProps (state) {
return {
@@ -83,7 +83,7 @@ DepositEtherModal.prototype.renderRow = function ({
]),
- h('div.deposit-ether-modal__buy-row__logo', [logo]),
+ h('div.deposit-ether-modal__buy-row__logo-container', [logo]),
h('div.deposit-ether-modal__buy-row__description', [
@@ -109,17 +109,17 @@ DepositEtherModal.prototype.render = function () {
const isTestNetwork = ['3', '4', '42'].find(n => n === network)
const networkName = networkNames[network]
- return h('div.deposit-ether-modal', {}, [
+ return h('div.page-container.page-container--full-width.page-container--full-height', {}, [
- h('div.deposit-ether-modal__header', [
+ h('div.page-container__header', [
- h('div.deposit-ether-modal__header__title', ['Deposit Ether']),
+ h('div.page-container__title', [t('depositEther')]),
- h('div.deposit-ether-modal__header__description', [
- 'To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet.',
+ h('div.page-container__subtitle', [
+ t('needEtherInWallet'),
]),
- h('div.deposit-ether-modal__header__close', {
+ h('div.page-container__header-close', {
onClick: () => {
this.setState({ buyingWithShapeshift: false })
this.props.hideWarning()
@@ -129,54 +129,65 @@ DepositEtherModal.prototype.render = function () {
]),
- h('div.deposit-ether-modal__buy-rows', [
+ h('.page-container__content', {}, [
- this.renderRow({
- logo: h('img.deposit-ether-modal__buy-row__eth-logo', { src: '../../../images/eth_logo.svg' }),
- title: DIRECT_DEPOSIT_ROW_TITLE,
- text: DIRECT_DEPOSIT_ROW_TEXT,
- buttonLabel: 'View Account',
- onButtonClick: () => this.goToAccountDetailsModal(),
- hide: buyingWithShapeshift,
- }),
+ h('div.deposit-ether-modal__buy-rows', [
- this.renderRow({
- logo: h('i.fa.fa-tint.fa-2x'),
- title: FAUCET_ROW_TITLE,
- text: facuetRowText(networkName),
- buttonLabel: 'Get Ether',
- onButtonClick: () => toFaucet(network),
- hide: !isTestNetwork || buyingWithShapeshift,
- }),
+ this.renderRow({
+ logo: h('img.deposit-ether-modal__logo', {
+ src: '../../../images/deposit-eth.svg',
+ }),
+ title: DIRECT_DEPOSIT_ROW_TITLE,
+ text: DIRECT_DEPOSIT_ROW_TEXT,
+ buttonLabel: t('viewAccount'),
+ onButtonClick: () => this.goToAccountDetailsModal(),
+ hide: buyingWithShapeshift,
+ }),
- this.renderRow({
- logo: h('img.deposit-ether-modal__buy-row__coinbase-logo', {
- src: '../../../images/coinbase logo.png',
+ this.renderRow({
+ logo: h('i.fa.fa-tint.fa-2x'),
+ title: FAUCET_ROW_TITLE,
+ text: facuetRowText(networkName),
+ buttonLabel: t('getEther'),
+ onButtonClick: () => toFaucet(network),
+ hide: !isTestNetwork || buyingWithShapeshift,
}),
- title: COINBASE_ROW_TITLE,
- text: COINBASE_ROW_TEXT,
- buttonLabel: 'Continue to Coinbase',
- onButtonClick: () => toCoinbase(address),
- hide: isTestNetwork || buyingWithShapeshift,
- }),
- this.renderRow({
- logo: h('img.deposit-ether-modal__buy-row__shapeshift-logo', {
- src: '../../../images/shapeshift logo.png',
+ this.renderRow({
+ logo: h('div.deposit-ether-modal__logo', {
+ style: {
+ backgroundImage: 'url(\'../../../images/coinbase logo.png\')',
+ height: '40px',
+ },
+ }),
+ title: COINBASE_ROW_TITLE,
+ text: COINBASE_ROW_TEXT,
+ buttonLabel: t('continueToCoinbase'),
+ onButtonClick: () => toCoinbase(address),
+ hide: isTestNetwork || buyingWithShapeshift,
+ }),
+
+ this.renderRow({
+ logo: h('div.deposit-ether-modal__logo', {
+ style: {
+ backgroundImage: 'url(\'../../../images/shapeshift logo.png\')',
+ },
+ }),
+ title: SHAPESHIFT_ROW_TITLE,
+ text: SHAPESHIFT_ROW_TEXT,
+ buttonLabel: t('shapeshiftBuy'),
+ onButtonClick: () => this.setState({ buyingWithShapeshift: true }),
+ hide: isTestNetwork,
+ hideButton: buyingWithShapeshift,
+ hideTitle: buyingWithShapeshift,
+ onBackClick: () => this.setState({ buyingWithShapeshift: false }),
+ showBackButton: this.state.buyingWithShapeshift,
+ className: buyingWithShapeshift && 'deposit-ether-modal__buy-row__shapeshift-buy',
}),
- title: SHAPESHIFT_ROW_TITLE,
- text: SHAPESHIFT_ROW_TEXT,
- buttonLabel: 'Buy with Shapeshift',
- onButtonClick: () => this.setState({ buyingWithShapeshift: true }),
- hide: isTestNetwork,
- hideButton: buyingWithShapeshift,
- hideTitle: buyingWithShapeshift,
- onBackClick: () => this.setState({ buyingWithShapeshift: false }),
- showBackButton: this.state.buyingWithShapeshift,
- className: buyingWithShapeshift && 'deposit-ether-modal__buy-row__shapeshift-buy',
- }),
- buyingWithShapeshift && h(ShapeshiftForm),
+ buyingWithShapeshift && h(ShapeshiftForm),
+
+ ]),
]),
])
diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js
index e2361140d..6efa8d476 100644
--- a/ui/app/components/modals/edit-account-name-modal.js
+++ b/ui/app/components/modals/edit-account-name-modal.js
@@ -4,6 +4,7 @@ const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../actions')
const { getSelectedAccount } = require('../../selectors')
+const t = require('../../../i18n')
function mapStateToProps (state) {
return {
@@ -50,7 +51,7 @@ EditAccountNameModal.prototype.render = function () {
]),
h('div.edit-account-name-modal-title', {
- }, ['Edit Account Name']),
+ }, [t('editAccountName')]),
h('input.edit-account-name-modal-input', {
placeholder: identity.name,
@@ -60,7 +61,7 @@ EditAccountNameModal.prototype.render = function () {
value: this.state.inputText,
}, []),
- h('button.btn-clear.edit-account-name-modal-save-button', {
+ h('button.btn-clear.edit-account-name-modal-save-button.allcaps', {
onClick: () => {
if (this.state.inputText.length !== 0) {
saveAccountLabel(identity.address, this.state.inputText)
@@ -69,7 +70,7 @@ EditAccountNameModal.prototype.render = function () {
},
disabled: this.state.inputText.length === 0,
}, [
- 'SAVE',
+ t('save'),
]),
]),
diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js
index 422f23f44..017177cfd 100644
--- a/ui/app/components/modals/export-private-key-modal.js
+++ b/ui/app/components/modals/export-private-key-modal.js
@@ -7,6 +7,7 @@ const actions = require('../../actions')
const AccountModalContainer = require('./account-modal-container')
const { getSelectedIdentity } = require('../../selectors')
const ReadOnlyInput = require('../readonly-input')
+const t = require('../../../i18n')
const copyToClipboard = require('copy-to-clipboard')
function mapStateToProps (state) {
@@ -48,8 +49,8 @@ ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (passwo
ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) {
return h('span.private-key-password-label', privateKey
- ? 'This is your private key (click to copy)'
- : 'Type Your Password'
+ ? t('copyPrivateKey')
+ : t('typePassword')
)
}
@@ -86,8 +87,8 @@ ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password,
),
(privateKey
- ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), 'Done')
- : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), 'Confirm')
+ ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), t('done'))
+ : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), t('confirm'))
),
])
@@ -120,7 +121,7 @@ ExportPrivateKeyModal.prototype.render = function () {
h('div.account-modal-divider'),
- h('span.modal-body-title', 'Show Private Keys'),
+ h('span.modal-body-title', t('showPrivateKeys')),
h('div.private-key-password', {}, [
this.renderPasswordLabel(privateKey),
@@ -130,10 +131,7 @@ ExportPrivateKeyModal.prototype.render = function () {
!warning ? null : h('span.private-key-password-error', warning),
]),
- h('div.private-key-password-warning', `Warning: Never disclose this key.
- Anyone with your private keys can take steal any assets held in your
- account.`
- ),
+ h('div.private-key-password-warning', t('privateKeyWarning')),
this.renderButtons(privateKey, this.state.password, address, hideModal),
diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js
index 56c7ba299..33d8062c6 100644
--- a/ui/app/components/modals/hide-token-confirmation-modal.js
+++ b/ui/app/components/modals/hide-token-confirmation-modal.js
@@ -4,6 +4,7 @@ const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../actions')
const Identicon = require('../identicon')
+const t = require('../../../i18n')
function mapStateToProps (state) {
return {
@@ -41,7 +42,7 @@ HideTokenConfirmationModal.prototype.render = function () {
h('div.hide-token-confirmation__container', {
}, [
h('div.hide-token-confirmation__title', {}, [
- 'Hide Token?',
+ t('hideTokenPrompt'),
]),
h(Identicon, {
@@ -54,19 +55,19 @@ HideTokenConfirmationModal.prototype.render = function () {
h('div.hide-token-confirmation__symbol', {}, symbol),
h('div.hide-token-confirmation__copy', {}, [
- 'You can add this token back in the future by going go to “Add token” in your accounts options menu.',
+ t('readdToken'),
]),
h('div.hide-token-confirmation__buttons', {}, [
- h('button.btn-cancel.hide-token-confirmation__button', {
+ h('button.btn-cancel.hide-token-confirmation__button.allcaps', {
onClick: () => hideModal(),
}, [
- 'CANCEL',
+ t('cancel'),
]),
- h('button.btn-clear.hide-token-confirmation__button', {
+ h('button.btn-clear.hide-token-confirmation__button.allcaps', {
onClick: () => hideToken(address),
}, [
- 'HIDE',
+ t('hide'),
]),
]),
]),
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index 8e9e58985..501b83430 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -6,6 +6,7 @@ const FadeModal = require('boron').FadeModal
const actions = require('../../actions')
const isMobileView = require('../../../lib/is-mobile-view')
const isPopupOrNotification = require('../../../../app/scripts/lib/is-popup-or-notification')
+const t = require('../../../i18n')
// Modal Components
const BuyOptions = require('./buy-options-modal')
@@ -92,18 +93,20 @@ const MODALS = {
display: 'flex',
},
laptopModalStyle: {
- width: '900px',
- maxWidth: '900px',
+ width: '850px',
top: 'calc(10% + 10px)',
left: '0',
right: '0',
margin: '0 auto',
boxShadow: '0 0 6px 0 rgba(0,0,0,0.3)',
- borderRadius: '8px',
+ borderRadius: '7px',
transform: 'none',
+ height: 'calc(80% - 20px)',
+ overflowY: 'hidden',
},
contentStyle: {
- borderRadius: '8px',
+ borderRadius: '7px',
+ height: '100%',
},
},
@@ -171,9 +174,8 @@ const MODALS = {
BETA_UI_NOTIFICATION_MODAL: {
contents: [
h(NotifcationModal, {
- header: 'Welcome to the New UI (Beta)',
- message: `You are now using the new Metamask UI. Take a look around, try out new features like sending tokens,
- and let us know if you have any issues.`,
+ header: t('uiWelcome'),
+ message: t('uiWelcomeMessage'),
}),
],
mobileModalStyle: {
@@ -189,9 +191,8 @@ const MODALS = {
OLD_UI_NOTIFICATION_MODAL: {
contents: [
h(NotifcationModal, {
- header: 'Old UI',
- message: `You have returned to the old UI. You can switch back to the New UI through the option in the top
- right dropdown menu.`,
+ header: t('oldUI'),
+ message: t('oldUIMessage'),
}),
],
mobileModalStyle: {
diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js
index fc1fd413d..298b76af4 100644
--- a/ui/app/components/modals/new-account-modal.js
+++ b/ui/app/components/modals/new-account-modal.js
@@ -3,6 +3,7 @@ const PropTypes = require('prop-types')
const h = require('react-hyperscript')
const { connect } = require('react-redux')
const actions = require('../../actions')
+const t = require('../../../i18n')
class NewAccountModal extends Component {
constructor (props) {
@@ -11,7 +12,7 @@ class NewAccountModal extends Component {
const newAccountNumber = numberOfExistingAccounts + 1
this.state = {
- newAccountName: `Account ${newAccountNumber}`,
+ newAccountName: `${t('account')} ${newAccountNumber}`,
}
}
@@ -22,7 +23,7 @@ class NewAccountModal extends Component {
h('div.new-account-modal-wrapper', {
}, [
h('div.new-account-modal-header', {}, [
- 'New Account',
+ t('newAccount'),
]),
h('div.modal-close-x', {
@@ -30,19 +31,19 @@ class NewAccountModal extends Component {
}),
h('div.new-account-modal-content', {}, [
- 'Account Name',
+ t('accountName'),
]),
h('div.new-account-input-wrapper', {}, [
h('input.new-account-input', {
value: this.state.newAccountName,
- placeholder: 'E.g. My new account',
+ placeholder: t('sampleAccountName'),
onChange: event => this.setState({ newAccountName: event.target.value }),
}, []),
]),
h('div.new-account-modal-content.after-input', {}, [
- 'or',
+ t('or'),
]),
h('div.new-account-modal-content.after-input.pointer', {
@@ -50,13 +51,13 @@ class NewAccountModal extends Component {
this.props.hideModal()
this.props.showImportPage()
},
- }, 'Import an account'),
+ }, t('importAnAccount')),
- h('div.new-account-modal-content.button', {}, [
+ h('div.new-account-modal-content.button.allcaps', {}, [
h('button.btn-clear', {
onClick: () => this.props.createAccount(newAccountName),
}, [
- 'SAVE',
+ t('save'),
]),
]),
]),
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index 3e91fa807..f3df2242a 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -3,6 +3,7 @@ const h = require('react-hyperscript')
const classnames = require('classnames')
const inherits = require('util').inherits
const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon')
+const t = require('../../i18n')
module.exports = Network
@@ -33,7 +34,7 @@ Network.prototype.render = function () {
onClick: (event) => this.props.onClick(event),
}, [
h('img', {
- title: 'Attempting to connect to blockchain.',
+ title: t('attemptingConnect'),
style: {
width: '27px',
},
@@ -41,22 +42,22 @@ Network.prototype.render = function () {
}),
])
} else if (providerName === 'mainnet') {
- hoverText = 'Main Ethereum Network'
+ hoverText = t('mainnet')
iconName = 'ethereum-network'
} else if (providerName === 'ropsten') {
- hoverText = 'Ropsten Test Network'
+ hoverText = t('ropsten')
iconName = 'ropsten-test-network'
} else if (parseInt(networkNumber) === 3) {
- hoverText = 'Ropsten Test Network'
+ hoverText = t('ropsten')
iconName = 'ropsten-test-network'
} else if (providerName === 'kovan') {
- hoverText = 'Kovan Test Network'
+ hoverText = t('kovan')
iconName = 'kovan-test-network'
} else if (providerName === 'rinkeby') {
- hoverText = 'Rinkeby Test Network'
+ hoverText = t('rinkeby')
iconName = 'rinkeby-test-network'
} else {
- hoverText = 'Unknown Private Network'
+ hoverText = t('unknownNetwork')
iconName = 'unknown-private-network'
}
@@ -84,7 +85,7 @@ Network.prototype.render = function () {
backgroundColor: '#038789', // $blue-lagoon
nonSelectBackgroundColor: '#15afb2',
}),
- h('.network-name', 'Main Network'),
+ h('.network-name', t('mainnet')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
case 'ropsten-test-network':
@@ -93,7 +94,7 @@ Network.prototype.render = function () {
backgroundColor: '#e91550', // $crimson
nonSelectBackgroundColor: '#ec2c50',
}),
- h('.network-name', 'Ropsten Test Net'),
+ h('.network-name', t('ropsten')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
case 'kovan-test-network':
@@ -102,7 +103,7 @@ Network.prototype.render = function () {
backgroundColor: '#690496', // $purple
nonSelectBackgroundColor: '#b039f3',
}),
- h('.network-name', 'Kovan Test Net'),
+ h('.network-name', t('kovan')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
case 'rinkeby-test-network':
@@ -111,7 +112,7 @@ Network.prototype.render = function () {
backgroundColor: '#ebb33f', // $tulip-tree
nonSelectBackgroundColor: '#ecb23e',
}),
- h('.network-name', 'Rinkeby Test Net'),
+ h('.network-name', t('rinkeby')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
default:
@@ -123,7 +124,7 @@ Network.prototype.render = function () {
},
}),
- h('.network-name', 'Private Network'),
+ h('.network-name', t('privateNetwork')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
}
diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js
index 9d2e89cb0..8b0ce1e8b 100644
--- a/ui/app/components/notice.js
+++ b/ui/app/components/notice.js
@@ -4,6 +4,7 @@ const h = require('react-hyperscript')
const ReactMarkdown = require('react-markdown')
const linker = require('extension-link-enabler')
const findDOMNode = require('react-dom').findDOMNode
+const t = require('../../i18n')
module.exports = Notice
@@ -110,7 +111,7 @@ Notice.prototype.render = function () {
style: {
marginTop: '18px',
},
- }, 'Accept'),
+ }, t('accept')),
])
)
}
diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js
index 718a22de0..87e66855d 100644
--- a/ui/app/components/pending-msg-details.js
+++ b/ui/app/components/pending-msg-details.js
@@ -1,6 +1,7 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
+const t = require('../../i18n')
const AccountPanel = require('./account-panel')
@@ -39,7 +40,7 @@ PendingMsgDetails.prototype.render = function () {
// message data
h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [
h('.flex-column.flex-space-between', [
- h('label.font-small', 'MESSAGE'),
+ h('label.font-small.allcaps', t('message')),
h('span.font-small', msgParams.data),
]),
]),
@@ -47,4 +48,3 @@ PendingMsgDetails.prototype.render = function () {
])
)
}
-
diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js
index 834719c53..dc406b955 100644
--- a/ui/app/components/pending-msg.js
+++ b/ui/app/components/pending-msg.js
@@ -2,6 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const PendingTxDetails = require('./pending-msg-details')
+const t = require('../../i18n')
module.exports = PendingMsg
@@ -29,17 +30,14 @@ PendingMsg.prototype.render = function () {
fontWeight: 'bold',
textAlign: 'center',
},
- }, 'Sign Message'),
+ }, t('signMessage')),
h('.error', {
style: {
margin: '10px',
},
}, [
- `Signing this message can have
- dangerous side effects. Only sign messages from
- sites you fully trust with your entire account.
- This dangerous method will be removed in a future version. `,
+ t('signNotice'),
h('a', {
href: 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527',
style: { color: 'rgb(247, 134, 28)' },
@@ -48,7 +46,7 @@ PendingMsg.prototype.render = function () {
const url = 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527'
global.platform.openWindow({ url })
},
- }, 'Read more here.'),
+ }, t('readMore')),
]),
// message details
@@ -58,13 +56,12 @@ PendingMsg.prototype.render = function () {
h('.flex-row.flex-space-around', [
h('button', {
onClick: state.cancelMessage,
- }, 'Cancel'),
+ }, t('cancel')),
h('button', {
onClick: state.signMessage,
- }, 'Sign'),
+ }, t('sign')),
]),
])
)
}
-
diff --git a/ui/app/components/pending-personal-msg-details.js b/ui/app/components/pending-personal-msg-details.js
deleted file mode 100644
index 1050513f2..000000000
--- a/ui/app/components/pending-personal-msg-details.js
+++ /dev/null
@@ -1,60 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-
-const AccountPanel = require('./account-panel')
-const BinaryRenderer = require('./binary-renderer')
-
-module.exports = PendingMsgDetails
-
-inherits(PendingMsgDetails, Component)
-function PendingMsgDetails () {
- Component.call(this)
-}
-
-PendingMsgDetails.prototype.render = function () {
- var state = this.props
- var msgData = state.txData
-
- var msgParams = msgData.msgParams || {}
- var address = msgParams.from || state.selectedAddress
- var identity = state.identities[address] || { address: address }
- var account = state.accounts[address] || { address: address }
-
- var { data } = msgParams
-
- return (
- h('div', {
- key: msgData.id,
- style: {
- margin: '10px 20px',
- },
- }, [
-
- // account that will sign
- h(AccountPanel, {
- showFullAddress: true,
- identity: identity,
- account: account,
- imageifyIdenticons: state.imageifyIdenticons,
- }),
-
- // message data
- h('div', {
- style: {
- height: '260px',
- },
- }, [
- h('label.font-small', { style: { display: 'block' } }, 'MESSAGE'),
- h(BinaryRenderer, {
- value: data,
- style: {
- height: '215px',
- },
- }),
- ]),
-
- ])
- )
-}
-
diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js
index ae6c6ef7b..4810bb515 100644
--- a/ui/app/components/pending-tx/confirm-deploy-contract.js
+++ b/ui/app/components/pending-tx/confirm-deploy-contract.js
@@ -1,348 +1,350 @@
-const Component = require('react').Component
+const { Component } = require('react')
const { connect } = require('react-redux')
const h = require('react-hyperscript')
-const inherits = require('util').inherits
+const PropTypes = require('prop-types')
const actions = require('../../actions')
const clone = require('clone')
-const Identicon = require('../identicon')
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
const { conversionUtil } = require('../../conversion-util')
+const t = require('../../../i18n')
+const SenderToRecipient = require('../sender-to-recipient')
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
+class ConfirmDeployContract extends Component {
+ constructor (props) {
+ super(props)
-module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract)
-
-function mapStateToProps (state) {
- const {
- conversionRate,
- identities,
- currentCurrency,
- } = state.metamask
- const accounts = state.metamask.accounts
- const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
- return {
- currentCurrency,
- conversionRate,
- identities,
- selectedAddress,
+ this.state = {
+ valid: false,
+ submitting: false,
+ }
}
-}
-function mapDispatchToProps (dispatch) {
- return {
- backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
- cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
+ onSubmit (event) {
+ event.preventDefault()
+ const txMeta = this.gatherTxMeta()
+ const valid = this.checkValidity()
+ this.setState({ valid, submitting: true })
+
+ if (valid && this.verifyGasParams()) {
+ this.props.sendTransaction(txMeta, event)
+ } else {
+ this.props.displayWarning('invalidGasParams')
+ this.setState({ submitting: false })
+ }
}
-}
-
-inherits(ConfirmDeployContract, Component)
-function ConfirmDeployContract () {
- Component.call(this)
- this.state = {}
- this.onSubmit = this.onSubmit.bind(this)
-}
+ cancel (event, txMeta) {
+ event.preventDefault()
+ this.props.cancelTransaction(txMeta)
+ }
-ConfirmDeployContract.prototype.onSubmit = function (event) {
- event.preventDefault()
- const txMeta = this.gatherTxMeta()
- const valid = this.checkValidity()
- this.setState({ valid, submitting: true })
-
- if (valid && this.verifyGasParams()) {
- this.props.sendTransaction(txMeta, event)
- } else {
- this.props.dispatch(actions.displayWarning('Invalid Gas Parameters'))
- this.setState({ submitting: false })
+ checkValidity () {
+ const form = this.getFormEl()
+ const valid = form.checkValidity()
+ return valid
}
-}
-ConfirmDeployContract.prototype.cancel = function (event, txMeta) {
- event.preventDefault()
- this.props.cancelTransaction(txMeta)
-}
+ getFormEl () {
+ const form = document.querySelector('form#pending-tx-form')
+ // Stub out form for unit tests:
+ if (!form) {
+ return { checkValidity () { return true } }
+ }
+ return form
+ }
-ConfirmDeployContract.prototype.checkValidity = function () {
- const form = this.getFormEl()
- const valid = form.checkValidity()
- return valid
-}
+ // After a customizable state value has been updated,
+ gatherTxMeta () {
+ const props = this.props
+ const state = this.state
+ const txData = clone(state.txData) || clone(props.txData)
-ConfirmDeployContract.prototype.getFormEl = function () {
- const form = document.querySelector('form#pending-tx-form')
- // Stub out form for unit tests:
- if (!form) {
- return { checkValidity () { return true } }
+ // log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
+ return txData
}
- return form
-}
-
-// After a customizable state value has been updated,
-ConfirmDeployContract.prototype.gatherTxMeta = function () {
- const props = this.props
- const state = this.state
- const txData = clone(state.txData) || clone(props.txData)
- // log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
- return txData
-}
+ verifyGasParams () {
+ // We call this in case the gas has not been modified at all
+ if (!this.state) { return true }
+ return (
+ this._notZeroOrEmptyString(this.state.gas) &&
+ this._notZeroOrEmptyString(this.state.gasPrice)
+ )
+ }
-ConfirmDeployContract.prototype.verifyGasParams = function () {
- // We call this in case the gas has not been modified at all
- if (!this.state) { return true }
- return (
- this._notZeroOrEmptyString(this.state.gas) &&
- this._notZeroOrEmptyString(this.state.gasPrice)
- )
-}
+ _notZeroOrEmptyString (obj) {
+ return obj !== '' && obj !== '0x0'
+ }
-ConfirmDeployContract.prototype._notZeroOrEmptyString = function (obj) {
- return obj !== '' && obj !== '0x0'
-}
+ bnMultiplyByFraction (targetBN, numerator, denominator) {
+ const numBN = new BN(numerator)
+ const denomBN = new BN(denominator)
+ return targetBN.mul(numBN).div(denomBN)
+ }
-ConfirmDeployContract.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) {
- const numBN = new BN(numerator)
- const denomBN = new BN(denominator)
- return targetBN.mul(numBN).div(denomBN)
-}
+ getData () {
+ const { identities } = this.props
+ const txMeta = this.gatherTxMeta()
+ const txParams = txMeta.txParams || {}
+
+ return {
+ from: {
+ address: txParams.from,
+ name: identities[txParams.from].name,
+ },
+ memo: txParams.memo || '',
+ }
+ }
-ConfirmDeployContract.prototype.getData = function () {
- const { identities } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
+ getAmount () {
+ const { conversionRate, currentCurrency } = this.props
+ const txMeta = this.gatherTxMeta()
+ const txParams = txMeta.txParams || {}
+
+ const FIAT = conversionUtil(txParams.value, {
+ fromNumericBase: 'hex',
+ toNumericBase: 'dec',
+ fromCurrency: 'ETH',
+ toCurrency: currentCurrency,
+ numberOfDecimals: 2,
+ fromDenomination: 'WEI',
+ conversionRate,
+ })
+ const ETH = conversionUtil(txParams.value, {
+ fromNumericBase: 'hex',
+ toNumericBase: 'dec',
+ fromCurrency: 'ETH',
+ toCurrency: 'ETH',
+ fromDenomination: 'WEI',
+ conversionRate,
+ numberOfDecimals: 6,
+ })
+
+ return {
+ fiat: Number(FIAT),
+ token: Number(ETH),
+ }
- return {
- from: {
- address: txParams.from,
- name: identities[txParams.from].name,
- },
- memo: txParams.memo || '',
}
-}
-
-ConfirmDeployContract.prototype.getAmount = function () {
- const { conversionRate, currentCurrency } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
-
- const FIAT = conversionUtil(txParams.value, {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- fromCurrency: 'ETH',
- toCurrency: currentCurrency,
- numberOfDecimals: 2,
- fromDenomination: 'WEI',
- conversionRate,
- })
- const ETH = conversionUtil(txParams.value, {
- fromNumericBase: 'hex',
- toNumericBase: 'dec',
- fromCurrency: 'ETH',
- toCurrency: 'ETH',
- fromDenomination: 'WEI',
- conversionRate,
- numberOfDecimals: 6,
- })
- return {
- fiat: Number(FIAT),
- token: Number(ETH),
+ getGasFee () {
+ const { conversionRate, currentCurrency } = this.props
+ const txMeta = this.gatherTxMeta()
+ const txParams = txMeta.txParams || {}
+
+ // Gas
+ const gas = txParams.gas
+ const gasBn = hexToBn(gas)
+
+ // Gas Price
+ const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_HEX
+ const gasPriceBn = hexToBn(gasPrice)
+
+ const txFeeBn = gasBn.mul(gasPriceBn)
+
+ const FIAT = conversionUtil(txFeeBn, {
+ fromNumericBase: 'BN',
+ toNumericBase: 'dec',
+ fromDenomination: 'WEI',
+ fromCurrency: 'ETH',
+ toCurrency: currentCurrency,
+ numberOfDecimals: 2,
+ conversionRate,
+ })
+ const ETH = conversionUtil(txFeeBn, {
+ fromNumericBase: 'BN',
+ toNumericBase: 'dec',
+ fromDenomination: 'WEI',
+ fromCurrency: 'ETH',
+ toCurrency: 'ETH',
+ numberOfDecimals: 6,
+ conversionRate,
+ })
+
+ return {
+ fiat: Number(FIAT),
+ eth: Number(ETH),
+ }
}
-}
+ renderGasFee () {
+ const { currentCurrency } = this.props
+ const { fiat: fiatGas, eth: ethGas } = this.getGasFee()
-ConfirmDeployContract.prototype.getGasFee = function () {
- const { conversionRate, currentCurrency } = this.props
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
+ return (
+ h('section.flex-row.flex-center.confirm-screen-row', [
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`),
- // Gas
- const gas = txParams.gas
- const gasBn = hexToBn(gas)
+ h(
+ 'div.confirm-screen-row-detail',
+ `${ethGas} ETH`
+ ),
+ ]),
+ ])
+ )
+ }
- // Gas Price
- const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_HEX
- const gasPriceBn = hexToBn(gasPrice)
+ renderHeroAmount () {
+ const { currentCurrency } = this.props
+ const { fiat: fiatAmount } = this.getAmount()
+ const txMeta = this.gatherTxMeta()
+ const txParams = txMeta.txParams || {}
+ const { memo = '' } = txParams
+
+ return (
+ h('div.confirm-send-token__hero-amount-wrapper', [
+ h('h3.flex-center.confirm-screen-send-amount', `${fiatAmount}`),
+ h('h3.flex-center.confirm-screen-send-amount-currency', currentCurrency.toUpperCase()),
+ h('div.flex-center.confirm-memo-wrapper', [
+ h('h3.confirm-screen-send-memo', memo),
+ ]),
+ ])
+ )
+ }
- const txFeeBn = gasBn.mul(gasPriceBn)
+ renderTotalPlusGas () {
+ const { currentCurrency } = this.props
+ const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
+ const { fiat: fiatGas, eth: ethGas } = this.getGasFee()
- const FIAT = conversionUtil(txFeeBn, {
- fromNumericBase: 'BN',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- fromCurrency: 'ETH',
- toCurrency: currentCurrency,
- numberOfDecimals: 2,
- conversionRate,
- })
- const ETH = conversionUtil(txFeeBn, {
- fromNumericBase: 'BN',
- toNumericBase: 'dec',
- fromDenomination: 'WEI',
- fromCurrency: 'ETH',
- toCurrency: 'ETH',
- numberOfDecimals: 6,
- conversionRate,
- })
+ return (
+ h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
+ h('div.confirm-screen-section-column', [
+ h('span.confirm-screen-label', [ t('total') + ' ' ]),
+ h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]),
+ ]),
- return {
- fiat: Number(FIAT),
- eth: Number(ETH),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', `${fiatAmount + fiatGas} ${currentCurrency.toUpperCase()}`),
+ h('div.confirm-screen-row-detail', `${tokenAmount + ethGas} ETH`),
+ ]),
+ ])
+ )
}
-}
-
-ConfirmDeployContract.prototype.renderGasFee = function () {
- const { currentCurrency } = this.props
- const { fiat: fiatGas, eth: ethGas } = this.getGasFee()
-
- return (
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'Gas Fee' ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`),
-
- h(
- 'div.confirm-screen-row-detail',
- `${ethGas} ETH`
- ),
- ]),
- ])
- )
-}
-ConfirmDeployContract.prototype.renderHeroAmount = function () {
- const { currentCurrency } = this.props
- const { fiat: fiatAmount } = this.getAmount()
- const txMeta = this.gatherTxMeta()
- const txParams = txMeta.txParams || {}
- const { memo = '' } = txParams
-
- return (
- h('div.confirm-send-token__hero-amount-wrapper', [
- h('h3.flex-center.confirm-screen-send-amount', `${fiatAmount}`),
- h('h3.flex-center.confirm-screen-send-amount-currency', currentCurrency.toUpperCase()),
- h('div.flex-center.confirm-memo-wrapper', [
- h('h3.confirm-screen-send-memo', memo),
- ]),
- ])
- )
-}
+ render () {
+ const { backToAccountDetail, selectedAddress } = this.props
+ const txMeta = this.gatherTxMeta()
-ConfirmDeployContract.prototype.renderTotalPlusGas = function () {
- const { currentCurrency } = this.props
- const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
- const { fiat: fiatGas, eth: ethGas } = this.getGasFee()
-
- return (
- h('section.flex-row.flex-center.confirm-screen-total-box ', [
- h('div.confirm-screen-section-column', [
- h('span.confirm-screen-label', [ 'Total ' ]),
- h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]),
- ]),
-
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${fiatAmount + fiatGas} ${currentCurrency.toUpperCase()}`),
- h('div.confirm-screen-row-detail', `${tokenAmount + ethGas} ETH`),
- ]),
- ])
- )
-}
+ const {
+ from: {
+ address: fromAddress,
+ name: fromName,
+ },
+ } = this.getData()
-ConfirmDeployContract.prototype.render = function () {
- const { backToAccountDetail, selectedAddress } = this.props
- const txMeta = this.gatherTxMeta()
+ this.inputs = []
- const {
- from: {
- address: fromAddress,
- name: fromName,
- },
- } = this.getData()
-
- this.inputs = []
-
- return (
- h('div.flex-column.flex-grow.confirm-screen-container', {
- style: { minWidth: '355px' },
- }, [
- // Main Send token Card
- h('div.confirm-screen-wrapper.flex-column.flex-grow', [
- h('h3.flex-center.confirm-screen-header', [
- h('button.confirm-screen-back-button', {
+ return (
+ h('.page-container', [
+ h('.page-container__header', [
+ h('.page-container__back-button', {
onClick: () => backToAccountDetail(selectedAddress),
- }, 'BACK'),
- h('div.confirm-screen-title', 'Confirm Contract'),
- h('div.confirm-screen-header-tip'),
- ]),
- h('div.flex-row.flex-center.confirm-screen-identicons', [
- h('div.confirm-screen-account-wrapper', [
- h(
- Identicon,
- {
- address: fromAddress,
- diameter: 60,
- },
- ),
- h('span.confirm-screen-account-name', fromName),
- // h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
- ]),
- h('i.fa.fa-arrow-right.fa-lg'),
- h('div.confirm-screen-account-wrapper', [
- h('i.fa.fa-file-text-o'),
- h('span.confirm-screen-account-name', 'New Contract'),
- h('span.confirm-screen-account-number', ' '),
- ]),
+ }, t('back')),
+ h('.page-container__title', t('confirmContract')),
+ h('.page-container__subtitle', t('pleaseReviewTransaction')),
]),
+ // Main Send token Card
+ h('.page-container__content', [
+
+ h(SenderToRecipient, {
+ senderName: fromName,
+ senderAddress: fromAddress,
+ }),
+
+ // h('h3.flex-center.confirm-screen-sending-to-message', {
+ // style: {
+ // textAlign: 'center',
+ // fontSize: '16px',
+ // },
+ // }, [
+ // `You're deploying a new contract.`,
+ // ]),
+
+ this.renderHeroAmount(),
+
+ h('div.confirm-screen-rows', [
+ h('section.flex-row.flex-center.confirm-screen-row', [
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', fromName),
+ h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
+ ]),
+ ]),
- // h('h3.flex-center.confirm-screen-sending-to-message', {
- // style: {
- // textAlign: 'center',
- // fontSize: '16px',
- // },
- // }, [
- // `You're deploying a new contract.`,
- // ]),
-
- this.renderHeroAmount(),
-
- h('div.confirm-screen-rows', [
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'From' ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', fromName),
- h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
+ h('section.flex-row.flex-center.confirm-screen-row', [
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', t('newContract')),
+ ]),
]),
+
+ this.renderGasFee(),
+
+ this.renderTotalPlusGas(),
+
]),
+ ]),
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'To' ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', 'New Contract'),
- ]),
+ h('form#pending-tx-form', {
+ onSubmit: event => this.onSubmit(event),
+ }, [
+ h('.page-container__footer', [
+ // Cancel Button
+ h('button.btn-cancel.page-container__footer-button.allcaps', {
+ onClick: event => this.cancel(event, txMeta),
+ }, t('cancel')),
+
+ // Accept Button
+ h('button.btn-confirm.page-container__footer-button.allcaps', {
+ onClick: event => this.onSubmit(event),
+ }, t('confirm')),
]),
+ ]),
+ ])
+ )
+ }
+}
- this.renderGasFee(),
+ConfirmDeployContract.propTypes = {
+ sendTransaction: PropTypes.func,
+ cancelTransaction: PropTypes.func,
+ backToAccountDetail: PropTypes.func,
+ displayWarning: PropTypes.func,
+ identities: PropTypes.object,
+ conversionRate: PropTypes.number,
+ currentCurrency: PropTypes.string,
+ selectedAddress: PropTypes.string,
+}
- this.renderTotalPlusGas(),
+const mapStateToProps = state => {
+ const {
+ conversionRate,
+ identities,
+ currentCurrency,
+ } = state.metamask
+ const accounts = state.metamask.accounts
+ const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
+ return {
+ currentCurrency,
+ conversionRate,
+ identities,
+ selectedAddress,
+ }
+}
- ]),
- ]),
-
- h('form#pending-tx-form', {
- onSubmit: this.onSubmit,
- }, [
- // Cancel Button
- h('div.cancel.btn-light.confirm-screen-cancel-button', {
- onClick: (event) => this.cancel(event, txMeta),
- }, 'CANCEL'),
-
- // Accept Button
- h('button.confirm-screen-confirm-button', ['CONFIRM']),
-
- ]),
- ])
- )
+const mapDispatchToProps = dispatch => {
+ return {
+ backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
+ cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
+ displayWarning: warning => actions.displayWarning(t(warning)),
+ }
}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract)
diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js
index 3f8d9c28f..f36def9d5 100644
--- a/ui/app/components/pending-tx/confirm-send-ether.js
+++ b/ui/app/components/pending-tx/confirm-send-ether.js
@@ -8,7 +8,13 @@ const Identicon = require('../identicon')
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
-const { conversionUtil, addCurrencies } = require('../../conversion-util')
+const {
+ conversionUtil,
+ addCurrencies,
+ multiplyCurrencies,
+} = require('../../conversion-util')
+const GasFeeDisplay = require('../send/gas-fee-display-v2')
+const t = require('../../../i18n')
const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')
@@ -43,6 +49,7 @@ function mapDispatchToProps (dispatch) {
to,
value: amount,
} = txParams
+
dispatch(actions.updateSend({
gasLimit,
gasPrice,
@@ -55,6 +62,29 @@ function mapDispatchToProps (dispatch) {
dispatch(actions.showSendPage())
},
cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
+ showCustomizeGasModal: (txMeta, sendGasLimit, sendGasPrice, sendGasTotal) => {
+ const { id, txParams, lastGasPrice } = txMeta
+ const { gas: txGasLimit, gasPrice: txGasPrice } = txParams
+
+ let forceGasMin
+ if (lastGasPrice) {
+ forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, {
+ multiplicandBase: 16,
+ multiplierBase: 10,
+ toNumericBase: 'hex',
+ fromDenomination: 'WEI',
+ }))
+ }
+
+ dispatch(actions.updateSend({
+ gasLimit: sendGasLimit || txGasLimit,
+ gasPrice: sendGasPrice || txGasPrice,
+ editingTransactionId: id,
+ gasTotal: sendGasTotal,
+ forceGasMin,
+ }))
+ dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' }))
+ },
}
}
@@ -139,6 +169,7 @@ ConfirmSendEther.prototype.getGasFee = function () {
return {
FIAT,
ETH,
+ gasFeeInHex: txFeeBn.toString(16),
}
}
@@ -146,7 +177,7 @@ ConfirmSendEther.prototype.getData = function () {
const { identities } = this.props
const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {}
- const { FIAT: gasFeeInFIAT, ETH: gasFeeInETH } = this.getGasFee()
+ const { FIAT: gasFeeInFIAT, ETH: gasFeeInETH, gasFeeInHex } = this.getGasFee()
const { FIAT: amountInFIAT, ETH: amountInETH } = this.getAmount()
const totalInFIAT = addCurrencies(gasFeeInFIAT, amountInFIAT, {
@@ -165,7 +196,7 @@ ConfirmSendEther.prototype.getData = function () {
},
to: {
address: txParams.to,
- name: identities[txParams.to] ? identities[txParams.to].name : 'New Recipient',
+ name: identities[txParams.to] ? identities[txParams.to].name : t('newRecipient'),
},
memo: txParams.memo || '',
gasFeeInFIAT,
@@ -174,11 +205,20 @@ ConfirmSendEther.prototype.getData = function () {
amountInETH,
totalInFIAT,
totalInETH,
+ gasFeeInHex,
}
}
ConfirmSendEther.prototype.render = function () {
- const { editTransaction, currentCurrency, clearSend } = this.props
+ const {
+ editTransaction,
+ currentCurrency,
+ clearSend,
+ conversionRate,
+ currentCurrency: convertedCurrency,
+ showCustomizeGasModal,
+ send: { gasTotal, gasLimit: sendGasLimit, gasPrice: sendGasPrice },
+ } = this.props
const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {}
@@ -192,13 +232,17 @@ ConfirmSendEther.prototype.render = function () {
name: toName,
},
memo,
- gasFeeInFIAT,
- gasFeeInETH,
+ gasFeeInHex,
amountInFIAT,
totalInFIAT,
totalInETH,
} = this.getData()
+ const title = txMeta.lastGasPrice ? 'Reprice Transaction' : 'Confirm'
+ const subtitle = txMeta.lastGasPrice
+ ? 'Increase your gas fee to attempt to overwrite and speed up your transaction'
+ : 'Please review your transaction.'
+
// This is from the latest master
// It handles some of the errors that we are not currently handling
// Leaving as comments fo reference
@@ -217,187 +261,193 @@ ConfirmSendEther.prototype.render = function () {
// Main Send token Card
h('div.page-container', [
h('div.page-container__header', [
- h('button.confirm-screen-back-button', {
+ !txMeta.lastGasPrice && h('button.confirm-screen-back-button', {
onClick: () => editTransaction(txMeta),
}, 'Edit'),
- h('div.page-container__title', 'Confirm'),
- h('div.page-container__subtitle', `Please review your transaction.`),
+ h('div.page-container__title', title),
+ h('div.page-container__subtitle', subtitle),
]),
- h('div.flex-row.flex-center.confirm-screen-identicons', [
- h('div.confirm-screen-account-wrapper', [
- h(
- Identicon,
- {
- address: fromAddress,
- diameter: 60,
- },
- ),
- h('span.confirm-screen-account-name', fromName),
- // h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
+ h('.page-container__content', [
+ h('div.flex-row.flex-center.confirm-screen-identicons', [
+ h('div.confirm-screen-account-wrapper', [
+ h(
+ Identicon,
+ {
+ address: fromAddress,
+ diameter: 60,
+ },
+ ),
+ h('span.confirm-screen-account-name', fromName),
+ // h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
+ ]),
+ h('i.fa.fa-arrow-right.fa-lg'),
+ h('div.confirm-screen-account-wrapper', [
+ h(
+ Identicon,
+ {
+ address: txParams.to,
+ diameter: 60,
+ },
+ ),
+ h('span.confirm-screen-account-name', toName),
+ // h('span.confirm-screen-account-number', toAddress.slice(toAddress.length - 4)),
+ ]),
]),
- h('i.fa.fa-arrow-right.fa-lg'),
- h('div.confirm-screen-account-wrapper', [
- h(
- Identicon,
- {
- address: txParams.to,
- diameter: 60,
- },
- ),
- h('span.confirm-screen-account-name', toName),
- // h('span.confirm-screen-account-number', toAddress.slice(toAddress.length - 4)),
+
+ // h('h3.flex-center.confirm-screen-sending-to-message', {
+ // style: {
+ // textAlign: 'center',
+ // fontSize: '16px',
+ // },
+ // }, [
+ // `You're sending to Recipient ...${toAddress.slice(toAddress.length - 4)}`,
+ // ]),
+
+ h('h3.flex-center.confirm-screen-send-amount', [`${amountInFIAT}`]),
+ h('h3.flex-center.confirm-screen-send-amount-currency', [ currentCurrency.toUpperCase() ]),
+ h('div.flex-center.confirm-memo-wrapper', [
+ h('h3.confirm-screen-send-memo', [ memo ? `"${memo}"` : '' ]),
]),
- ]),
- // h('h3.flex-center.confirm-screen-sending-to-message', {
- // style: {
- // textAlign: 'center',
- // fontSize: '16px',
- // },
- // }, [
- // `You're sending to Recipient ...${toAddress.slice(toAddress.length - 4)}`,
- // ]),
-
- h('h3.flex-center.confirm-screen-send-amount', [`${amountInFIAT}`]),
- h('h3.flex-center.confirm-screen-send-amount-currency', [ currentCurrency.toUpperCase() ]),
- h('div.flex-center.confirm-memo-wrapper', [
- h('h3.confirm-screen-send-memo', [ memo ? `"${memo}"` : '' ]),
- ]),
+ h('div.confirm-screen-rows', [
+ h('section.flex-row.flex-center.confirm-screen-row', [
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', fromName),
+ h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
+ ]),
+ ]),
- h('div.confirm-screen-rows', [
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'From' ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', fromName),
- h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
+ h('section.flex-row.flex-center.confirm-screen-row', [
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', toName),
+ h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`),
+ ]),
]),
- ]),
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'To' ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', toName),
- h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`),
+ h('section.flex-row.flex-center.confirm-screen-row', [
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]),
+ h('div.confirm-screen-section-column', [
+ h(GasFeeDisplay, {
+ gasTotal: gasTotal || gasFeeInHex,
+ conversionRate,
+ convertedCurrency,
+ onClick: () => showCustomizeGasModal(txMeta, sendGasLimit, sendGasPrice, gasTotal),
+ }),
+ ]),
]),
- ]),
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'Gas Fee' ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${gasFeeInFIAT} ${currentCurrency.toUpperCase()}`),
+ h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
+ h('div.confirm-screen-section-column', [
+ h('span.confirm-screen-label', [ t('total') + ' ' ]),
+ h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]),
+ ]),
- h('div.confirm-screen-row-detail', `${gasFeeInETH} ETH`),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', `${totalInFIAT} ${currentCurrency.toUpperCase()}`),
+ h('div.confirm-screen-row-detail', `${totalInETH} ETH`),
+ ]),
]),
]),
+ // These are latest errors handling from master
+ // Leaving as comments as reference when we start implementing error handling
+ // h('style', `
+ // .conf-buttons button {
+ // margin-left: 10px;
+ // text-transform: uppercase;
+ // }
+ // `),
+
+ // txMeta.simulationFails ?
+ // h('.error', {
+ // style: {
+ // marginLeft: 50,
+ // fontSize: '0.9em',
+ // },
+ // }, 'Transaction Error. Exception thrown in contract code.')
+ // : null,
+
+ // !isValidAddress ?
+ // h('.error', {
+ // style: {
+ // marginLeft: 50,
+ // fontSize: '0.9em',
+ // },
+ // }, 'Recipient address is invalid. Sending this transaction will result in a loss of ETH.')
+ // : null,
+
+ // insufficientBalance ?
+ // h('span.error', {
+ // style: {
+ // marginLeft: 50,
+ // fontSize: '0.9em',
+ // },
+ // }, 'Insufficient balance for transaction')
+ // : null,
+
+ // // send + cancel
+ // h('.flex-row.flex-space-around.conf-buttons', {
+ // style: {
+ // display: 'flex',
+ // justifyContent: 'flex-end',
+ // margin: '14px 25px',
+ // },
+ // }, [
+ // h('button', {
+ // onClick: (event) => {
+ // this.resetGasFields()
+ // event.preventDefault()
+ // },
+ // }, 'Reset'),
+
+ // // Accept Button or Buy Button
+ // insufficientBalance ? h('button.btn-green', { onClick: props.buyEth }, 'Buy Ether') :
+ // h('input.confirm.btn-green', {
+ // type: 'submit',
+ // value: 'SUBMIT',
+ // style: { marginLeft: '10px' },
+ // disabled: buyDisabled,
+ // }),
+
+ // h('button.cancel.btn-red', {
+ // onClick: props.cancelTransaction,
+ // }, 'Reject'),
+ // ]),
+ // showRejectAll ? h('.flex-row.flex-space-around.conf-buttons', {
+ // style: {
+ // display: 'flex',
+ // justifyContent: 'flex-end',
+ // margin: '14px 25px',
+ // },
+ // }, [
+ // h('button.cancel.btn-red', {
+ // onClick: props.cancelAllTransactions,
+ // }, 'Reject All'),
+ // ]) : null,
+ // ]),
+ // ])
+ // )
+ // }
+ ]),
- h('section.flex-row.flex-center.confirm-screen-total-box ', [
- h('div.confirm-screen-section-column', [
- h('span.confirm-screen-label', [ 'Total ' ]),
- h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]),
- ]),
+ h('form#pending-tx-form', {
+ onSubmit: this.onSubmit,
+ }, [
+ h('.page-container__footer', [
+ // Cancel Button
+ h('button.btn-cancel.page-container__footer-button.allcaps', {
+ onClick: (event) => {
+ clearSend()
+ this.cancel(event, txMeta)
+ },
+ }, t('cancel')),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${totalInFIAT} ${currentCurrency.toUpperCase()}`),
- h('div.confirm-screen-row-detail', `${totalInETH} ETH`),
- ]),
+ // Accept Button
+ h('button.btn-confirm.page-container__footer-button.allcaps', [t('confirm')]),
]),
]),
-
-// These are latest errors handling from master
-// Leaving as comments as reference when we start implementing error handling
-// h('style', `
-// .conf-buttons button {
-// margin-left: 10px;
-// text-transform: uppercase;
-// }
-// `),
-
-// txMeta.simulationFails ?
-// h('.error', {
-// style: {
-// marginLeft: 50,
-// fontSize: '0.9em',
-// },
-// }, 'Transaction Error. Exception thrown in contract code.')
-// : null,
-
-// !isValidAddress ?
-// h('.error', {
-// style: {
-// marginLeft: 50,
-// fontSize: '0.9em',
-// },
-// }, 'Recipient address is invalid. Sending this transaction will result in a loss of ETH.')
-// : null,
-
-// insufficientBalance ?
-// h('span.error', {
-// style: {
-// marginLeft: 50,
-// fontSize: '0.9em',
-// },
-// }, 'Insufficient balance for transaction')
-// : null,
-
-// // send + cancel
-// h('.flex-row.flex-space-around.conf-buttons', {
-// style: {
-// display: 'flex',
-// justifyContent: 'flex-end',
-// margin: '14px 25px',
-// },
-// }, [
-// h('button', {
-// onClick: (event) => {
-// this.resetGasFields()
-// event.preventDefault()
-// },
-// }, 'Reset'),
-
-// // Accept Button or Buy Button
-// insufficientBalance ? h('button.btn-green', { onClick: props.buyEth }, 'Buy Ether') :
-// h('input.confirm.btn-green', {
-// type: 'submit',
-// value: 'SUBMIT',
-// style: { marginLeft: '10px' },
-// disabled: buyDisabled,
-// }),
-
-// h('button.cancel.btn-red', {
-// onClick: props.cancelTransaction,
-// }, 'Reject'),
-// ]),
-// showRejectAll ? h('.flex-row.flex-space-around.conf-buttons', {
-// style: {
-// display: 'flex',
-// justifyContent: 'flex-end',
-// margin: '14px 25px',
-// },
-// }, [
-// h('button.cancel.btn-red', {
-// onClick: props.cancelAllTransactions,
-// }, 'Reject All'),
-// ]) : null,
-// ]),
-// ])
-// )
-// }
- ]),
-
- h('form#pending-tx-form', {
- onSubmit: this.onSubmit,
- }, [
- // Cancel Button
- h('div.cancel.btn-light.confirm-screen-cancel-button', {
- onClick: (event) => {
- clearSend()
- this.cancel(event, txMeta)
- },
- }, 'CANCEL'),
-
- // Accept Button
- h('button.confirm-screen-confirm-button', ['CONFIRM']),
]),
])
)
@@ -412,7 +462,7 @@ ConfirmSendEther.prototype.onSubmit = function (event) {
if (valid && this.verifyGasParams()) {
this.props.sendTransaction(txMeta, event)
} else {
- this.props.dispatch(actions.displayWarning('Invalid Gas Parameters'))
+ this.props.dispatch(actions.displayWarning(t('invalidGasParams')))
this.setState({ submitting: false })
}
}
@@ -445,6 +495,27 @@ ConfirmSendEther.prototype.gatherTxMeta = function () {
const state = this.state
const txData = clone(state.txData) || clone(props.txData)
+ const { gasPrice: sendGasPrice, gas: sendGasLimit } = props.send
+ const {
+ lastGasPrice,
+ txParams: {
+ gasPrice: txGasPrice,
+ gas: txGasLimit,
+ },
+ } = txData
+
+ let forceGasMin
+ if (lastGasPrice) {
+ forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, {
+ multiplicandBase: 16,
+ multiplierBase: 10,
+ toNumericBase: 'hex',
+ }))
+ }
+
+ txData.txParams.gasPrice = sendGasPrice || forceGasMin || txGasPrice
+ txData.txParams.gas = sendGasLimit || txGasLimit
+
// log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
return txData
}
diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js
index dd2bef3da..ccd87c0a4 100644
--- a/ui/app/components/pending-tx/confirm-send-token.js
+++ b/ui/app/components/pending-tx/confirm-send-token.js
@@ -6,8 +6,10 @@ const tokenAbi = require('human-standard-token-abi')
const abiDecoder = require('abi-decoder')
abiDecoder.addABI(tokenAbi)
const actions = require('../../actions')
+const t = require('../../../i18n')
const clone = require('clone')
const Identicon = require('../identicon')
+const GasFeeDisplay = require('../send/gas-fee-display-v2.js')
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
const {
@@ -88,6 +90,39 @@ function mapDispatchToProps (dispatch, ownProps) {
}))
dispatch(actions.showSendTokenPage())
},
+ showCustomizeGasModal: (txMeta, sendGasLimit, sendGasPrice, sendGasTotal) => {
+ const { id, txParams, lastGasPrice } = txMeta
+ const { gas: txGasLimit, gasPrice: txGasPrice } = txParams
+ const tokenData = txParams.data && abiDecoder.decodeMethod(txParams.data)
+ const { params = [] } = tokenData
+ const { value: to } = params[0] || {}
+ const { value: tokenAmountInDec } = params[1] || {}
+ const tokenAmountInHex = conversionUtil(tokenAmountInDec, {
+ fromNumericBase: 'dec',
+ toNumericBase: 'hex',
+ })
+
+ let forceGasMin
+ if (lastGasPrice) {
+ forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, {
+ multiplicandBase: 16,
+ multiplierBase: 10,
+ toNumericBase: 'hex',
+ fromDenomination: 'WEI',
+ }))
+ }
+
+ dispatch(actions.updateSend({
+ gasLimit: sendGasLimit || txGasLimit,
+ gasPrice: sendGasPrice || txGasPrice,
+ editingTransactionId: id,
+ gasTotal: sendGasTotal,
+ to,
+ amount: tokenAmountInHex,
+ forceGasMin,
+ }))
+ dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' }))
+ },
}
}
@@ -133,7 +168,7 @@ ConfirmSendToken.prototype.getAmount = function () {
? +(sendTokenAmount * tokenExchangeRate * conversionRate).toFixed(2)
: null,
token: typeof value === 'undefined'
- ? 'Unknown'
+ ? t('unknown')
: +sendTokenAmount.toFixed(decimals),
}
@@ -187,6 +222,7 @@ ConfirmSendToken.prototype.getGasFee = function () {
token: tokenExchangeRate
? tokenGas
: null,
+ gasFeeInHex: gasTotal.toString(16),
}
}
@@ -204,7 +240,7 @@ ConfirmSendToken.prototype.getData = function () {
},
to: {
address: value,
- name: identities[value] ? identities[value].name : 'New Recipient',
+ name: identities[value] ? identities[value].name : t('newRecipient'),
},
memo: txParams.memo || '',
}
@@ -239,19 +275,25 @@ ConfirmSendToken.prototype.renderHeroAmount = function () {
}
ConfirmSendToken.prototype.renderGasFee = function () {
- const { token: { symbol }, currentCurrency } = this.props
- const { fiat: fiatGas, token: tokenGas, eth: ethGas } = this.getGasFee()
+ const {
+ currentCurrency: convertedCurrency,
+ conversionRate,
+ send: { gasTotal, gasLimit: sendGasLimit, gasPrice: sendGasPrice },
+ showCustomizeGasModal,
+ } = this.props
+ const txMeta = this.gatherTxMeta()
+ const { gasFeeInHex } = this.getGasFee()
return (
h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'Gas Fee' ]),
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]),
h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency}`),
-
- h(
- 'div.confirm-screen-row-detail',
- tokenGas ? `${tokenGas} ${symbol}` : `${ethGas} ETH`
- ),
+ h(GasFeeDisplay, {
+ gasTotal: gasTotal || gasFeeInHex,
+ conversionRate,
+ convertedCurrency,
+ onClick: () => showCustomizeGasModal(txMeta, sendGasLimit, sendGasPrice, gasTotal),
+ }),
]),
])
)
@@ -264,10 +306,10 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () {
return fiatAmount && fiatGas
? (
- h('section.flex-row.flex-center.confirm-screen-total-box ', [
+ h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
h('div.confirm-screen-section-column', [
- h('span.confirm-screen-label', [ 'Total ' ]),
- h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]),
+ h('span.confirm-screen-label', [ t('total') + ' ' ]),
+ h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]),
]),
h('div.confirm-screen-section-column', [
@@ -277,15 +319,15 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () {
])
)
: (
- h('section.flex-row.flex-center.confirm-screen-total-box ', [
+ h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [
h('div.confirm-screen-section-column', [
- h('span.confirm-screen-label', [ 'Total ' ]),
- h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]),
+ h('span.confirm-screen-label', [ t('total') + ' ' ]),
+ h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]),
]),
h('div.confirm-screen-section-column', [
h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`),
- h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} Gas`),
+ h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${t('gas')}`),
]),
])
)
@@ -307,91 +349,98 @@ ConfirmSendToken.prototype.render = function () {
this.inputs = []
+ const title = txMeta.lastGasPrice ? 'Reprice Transaction' : t('confirm')
+ const subtitle = txMeta.lastGasPrice
+ ? 'Increase your gas fee to attempt to overwrite and speed up your transaction'
+ : t('pleaseReviewTransaction')
+
return (
h('div.confirm-screen-container.confirm-send-token', [
// Main Send token Card
h('div.page-container', [
h('div.page-container__header', [
- h('button.confirm-screen-back-button', {
+ !txMeta.lastGasPrice && h('button.confirm-screen-back-button', {
onClick: () => editTransaction(txMeta),
- }, 'Edit'),
- h('div.page-container__title', 'Confirm'),
- h('div.page-container__subtitle', `Please review your transaction.`),
+ }, t('edit')),
+ h('div.page-container__title', title),
+ h('div.page-container__subtitle', subtitle),
]),
- h('div.flex-row.flex-center.confirm-screen-identicons', [
- h('div.confirm-screen-account-wrapper', [
- h(
- Identicon,
- {
- address: fromAddress,
- diameter: 60,
- },
- ),
- h('span.confirm-screen-account-name', fromName),
- // h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
- ]),
- h('i.fa.fa-arrow-right.fa-lg'),
- h('div.confirm-screen-account-wrapper', [
- h(
- Identicon,
- {
- address: toAddress,
- diameter: 60,
- },
- ),
- h('span.confirm-screen-account-name', toName),
- // h('span.confirm-screen-account-number', toAddress.slice(toAddress.length - 4)),
- ]),
- ]),
-
- // h('h3.flex-center.confirm-screen-sending-to-message', {
- // style: {
- // textAlign: 'center',
- // fontSize: '16px',
- // },
- // }, [
- // `You're sending to Recipient ...${toAddress.slice(toAddress.length - 4)}`,
- // ]),
-
- this.renderHeroAmount(),
-
- h('div.confirm-screen-rows', [
- h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'From' ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', fromName),
- h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
+ h('.page-container__content', [
+ h('div.flex-row.flex-center.confirm-screen-identicons', [
+ h('div.confirm-screen-account-wrapper', [
+ h(
+ Identicon,
+ {
+ address: fromAddress,
+ diameter: 60,
+ },
+ ),
+ h('span.confirm-screen-account-name', fromName),
+ // h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
+ ]),
+ h('i.fa.fa-arrow-right.fa-lg'),
+ h('div.confirm-screen-account-wrapper', [
+ h(
+ Identicon,
+ {
+ address: toAddress,
+ diameter: 60,
+ },
+ ),
+ h('span.confirm-screen-account-name', toName),
+ // h('span.confirm-screen-account-number', toAddress.slice(toAddress.length - 4)),
]),
]),
- toAddress && h('section.flex-row.flex-center.confirm-screen-row', [
- h('span.confirm-screen-label.confirm-screen-section-column', [ 'To' ]),
- h('div.confirm-screen-section-column', [
- h('div.confirm-screen-row-info', toName),
- h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`),
+ // h('h3.flex-center.confirm-screen-sending-to-message', {
+ // style: {
+ // textAlign: 'center',
+ // fontSize: '16px',
+ // },
+ // }, [
+ // `You're sending to Recipient ...${toAddress.slice(toAddress.length - 4)}`,
+ // ]),
+
+ this.renderHeroAmount(),
+
+ h('div.confirm-screen-rows', [
+ h('section.flex-row.flex-center.confirm-screen-row', [
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', fromName),
+ h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
+ ]),
]),
- ]),
- this.renderGasFee(),
+ toAddress && h('section.flex-row.flex-center.confirm-screen-row', [
+ h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]),
+ h('div.confirm-screen-section-column', [
+ h('div.confirm-screen-row-info', toName),
+ h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`),
+ ]),
+ ]),
- this.renderTotalPlusGas(),
+ this.renderGasFee(),
- ]),
- ]),
+ this.renderTotalPlusGas(),
- h('form#pending-tx-form', {
- onSubmit: this.onSubmit,
- }, [
- // Cancel Button
- h('div.cancel.btn-light.confirm-screen-cancel-button', {
- onClick: (event) => this.cancel(event, txMeta),
- }, 'CANCEL'),
+ ]),
- // Accept Button
- h('button.confirm-screen-confirm-button', ['CONFIRM']),
+ ]),
+ h('form#pending-tx-form', {
+ onSubmit: this.onSubmit,
+ }, [
+ h('.page-container__footer', [
+ // Cancel Button
+ h('button.btn-cancel.page-container__footer-button.allcaps', {
+ onClick: (event) => this.cancel(event, txMeta),
+ }, t('cancel')),
+
+ // Accept Button
+ h('button.btn-confirm.page-container__footer-button.allcaps', [t('confirm')]),
+ ]),
+ ]),
]),
-
-
])
)
}
@@ -405,7 +454,7 @@ ConfirmSendToken.prototype.onSubmit = function (event) {
if (valid && this.verifyGasParams()) {
this.props.sendTransaction(txMeta, event)
} else {
- this.props.dispatch(actions.displayWarning('Invalid Gas Parameters'))
+ this.props.dispatch(actions.displayWarning(t('invalidGasParams')))
this.setState({ submitting: false })
}
}
@@ -438,6 +487,27 @@ ConfirmSendToken.prototype.gatherTxMeta = function () {
const state = this.state
const txData = clone(state.txData) || clone(props.txData)
+ const { gasPrice: sendGasPrice, gas: sendGasLimit } = props.send
+ const {
+ lastGasPrice,
+ txParams: {
+ gasPrice: txGasPrice,
+ gas: txGasLimit,
+ },
+ } = txData
+
+ let forceGasMin
+ if (lastGasPrice) {
+ forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, {
+ multiplicandBase: 16,
+ multiplierBase: 10,
+ toNumericBase: 'hex',
+ }))
+ }
+
+ txData.txParams.gasPrice = sendGasPrice || forceGasMin || txGasPrice
+ txData.txParams.gas = sendGasLimit || txGasLimit
+
// log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
return txData
}
diff --git a/ui/app/components/pending-typed-msg-details.js b/ui/app/components/pending-typed-msg-details.js
deleted file mode 100644
index b5fd29f71..000000000
--- a/ui/app/components/pending-typed-msg-details.js
+++ /dev/null
@@ -1,59 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-
-const AccountPanel = require('./account-panel')
-const TypedMessageRenderer = require('./typed-message-renderer')
-
-module.exports = PendingMsgDetails
-
-inherits(PendingMsgDetails, Component)
-function PendingMsgDetails () {
- Component.call(this)
-}
-
-PendingMsgDetails.prototype.render = function () {
- var state = this.props
- var msgData = state.txData
-
- var msgParams = msgData.msgParams || {}
- var address = msgParams.from || state.selectedAddress
- var identity = state.identities[address] || { address: address }
- var account = state.accounts[address] || { address: address }
-
- var { data } = msgParams
-
- return (
- h('div', {
- key: msgData.id,
- style: {
- margin: '10px 20px',
- },
- }, [
-
- // account that will sign
- h(AccountPanel, {
- showFullAddress: true,
- identity: identity,
- account: account,
- imageifyIdenticons: state.imageifyIdenticons,
- }),
-
- // message data
- h('div', {
- style: {
- height: '260px',
- },
- }, [
- h('label.font-small', { style: { display: 'block' } }, 'YOU ARE SIGNING'),
- h(TypedMessageRenderer, {
- value: data,
- style: {
- height: '215px',
- },
- }),
- ]),
-
- ])
- )
-}
diff --git a/ui/app/components/pending-typed-msg.js b/ui/app/components/pending-typed-msg.js
deleted file mode 100644
index f8926d0a3..000000000
--- a/ui/app/components/pending-typed-msg.js
+++ /dev/null
@@ -1,46 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const PendingTxDetails = require('./pending-typed-msg-details')
-
-module.exports = PendingMsg
-
-inherits(PendingMsg, Component)
-function PendingMsg () {
- Component.call(this)
-}
-
-PendingMsg.prototype.render = function () {
- var state = this.props
- var msgData = state.txData
-
- return (
-
- h('div', {
- key: msgData.id,
- }, [
-
- // header
- h('h3', {
- style: {
- fontWeight: 'bold',
- textAlign: 'center',
- },
- }, 'Sign Message'),
-
- // message details
- h(PendingTxDetails, state),
-
- // sign + cancel
- h('.flex-row.flex-space-around', [
- h('button', {
- onClick: state.cancelTypedMessage,
- }, 'Cancel'),
- h('button', {
- onClick: state.signTypedMessage,
- }, 'Sign'),
- ]),
- ])
-
- )
-}
diff --git a/ui/app/components/range-slider.js b/ui/app/components/range-slider.js
deleted file mode 100644
index 823f5eb01..000000000
--- a/ui/app/components/range-slider.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-
-module.exports = RangeSlider
-
-inherits(RangeSlider, Component)
-function RangeSlider () {
- Component.call(this)
-}
-
-RangeSlider.prototype.render = function () {
- const state = this.state || {}
- const props = this.props
- const onInput = props.onInput || function () {}
- const name = props.name
- const {
- min = 0,
- max = 100,
- increment = 1,
- defaultValue = 50,
- mirrorInput = false,
- } = this.props.options
- const {container, input, range} = props.style
-
- return (
- h('.flex-row', {
- style: container,
- }, [
- h('input', {
- type: 'range',
- name: name,
- min: min,
- max: max,
- step: increment,
- style: range,
- value: state.value || defaultValue,
- onChange: mirrorInput ? this.mirrorInputs.bind(this, event) : onInput,
- }),
-
- // Mirrored input for range
- mirrorInput ? h('input.large-input', {
- type: 'number',
- name: `${name}Mirror`,
- min: min,
- max: max,
- value: state.value || defaultValue,
- step: increment,
- style: input,
- onChange: this.mirrorInputs.bind(this, event),
- }) : null,
- ])
- )
-}
-
-RangeSlider.prototype.mirrorInputs = function (event) {
- this.setState({value: event.target.value})
-}
diff --git a/ui/app/components/send-token/index.js b/ui/app/components/send-token/index.js
deleted file mode 100644
index 99d078251..000000000
--- a/ui/app/components/send-token/index.js
+++ /dev/null
@@ -1,439 +0,0 @@
-const Component = require('react').Component
-const connect = require('react-redux').connect
-const h = require('react-hyperscript')
-const classnames = require('classnames')
-const abi = require('ethereumjs-abi')
-const inherits = require('util').inherits
-const actions = require('../../actions')
-const selectors = require('../../selectors')
-const { isValidAddress, allNull } = require('../../util')
-
-// const BalanceComponent = require('./balance-component')
-const Identicon = require('../identicon')
-const TokenBalance = require('../token-balance')
-const CurrencyToggle = require('../send/currency-toggle')
-const GasTooltip = require('../send/gas-tooltip')
-const GasFeeDisplay = require('../send/gas-fee-display')
-
-module.exports = connect(mapStateToProps, mapDispatchToProps)(SendTokenScreen)
-
-function mapStateToProps (state) {
- // const sidebarOpen = state.appState.sidebarOpen
-
- const { warning } = state.appState
- const identities = state.metamask.identities
- const addressBook = state.metamask.addressBook
- const conversionRate = state.metamask.conversionRate
- const currentBlockGasLimit = state.metamask.currentBlockGasLimit
- const accounts = state.metamask.accounts
- const selectedTokenAddress = state.metamask.selectedTokenAddress
- const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
- const selectedToken = selectors.getSelectedToken(state)
- const tokenExchangeRates = state.metamask.tokenExchangeRates
- const pair = `${selectedToken.symbol.toLowerCase()}_eth`
- const { rate: tokenExchangeRate = 0 } = tokenExchangeRates[pair] || {}
-
- return {
- selectedAddress,
- selectedTokenAddress,
- identities,
- addressBook,
- conversionRate,
- tokenExchangeRate,
- currentBlockGasLimit,
- selectedToken,
- warning,
- }
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
- hideWarning: () => dispatch(actions.hideWarning()),
- addToAddressBook: (recipient, nickname) => dispatch(
- actions.addToAddressBook(recipient, nickname)
- ),
- signTx: txParams => dispatch(actions.signTx(txParams)),
- signTokenTx: (tokenAddress, toAddress, amount, txData) => (
- dispatch(actions.signTokenTx(tokenAddress, toAddress, amount, txData))
- ),
- updateTokenExchangeRate: token => dispatch(actions.updateTokenExchangeRate(token)),
- estimateGas: params => dispatch(actions.estimateGas(params)),
- getGasPrice: () => dispatch(actions.getGasPrice()),
- }
-}
-
-inherits(SendTokenScreen, Component)
-function SendTokenScreen () {
- Component.call(this)
- this.state = {
- to: '',
- amount: '0x0',
- amountToSend: '0x0',
- selectedCurrency: 'USD',
- isGasTooltipOpen: false,
- gasPrice: null,
- gasLimit: null,
- errors: {},
- }
-}
-
-SendTokenScreen.prototype.componentWillMount = function () {
- const {
- updateTokenExchangeRate,
- selectedToken: { symbol },
- getGasPrice,
- estimateGas,
- selectedAddress,
- } = this.props
-
- updateTokenExchangeRate(symbol)
-
- const data = Array.prototype.map.call(
- abi.rawEncode(['address', 'uint256'], [selectedAddress, '0x0']),
- x => ('00' + x.toString(16)).slice(-2)
- ).join('')
-
- console.log(data)
- Promise.all([
- getGasPrice(),
- estimateGas({
- from: selectedAddress,
- value: '0x0',
- gas: '746a528800',
- data,
- }),
- ])
- .then(([blockGasPrice, estimatedGas]) => {
- console.log({ blockGasPrice, estimatedGas})
- this.setState({
- gasPrice: blockGasPrice,
- gasLimit: estimatedGas,
- })
- })
-}
-
-SendTokenScreen.prototype.validate = function () {
- const {
- to,
- amount: stringAmount,
- gasPrice: hexGasPrice,
- gasLimit: hexGasLimit,
- } = this.state
-
- const gasPrice = parseInt(hexGasPrice, 16)
- const gasLimit = parseInt(hexGasLimit, 16) / 1000000000
- const amount = Number(stringAmount)
-
- const errors = {
- to: !to ? 'Required' : null,
- amount: !amount ? 'Required' : null,
- gasPrice: !gasPrice ? 'Gas Price Required' : null,
- gasLimit: !gasLimit ? 'Gas Limit Required' : null,
- }
-
- if (to && !isValidAddress(to)) {
- errors.to = 'Invalid address'
- }
-
- const isValid = Object.entries(errors).every(([key, value]) => value === null)
- return {
- isValid,
- errors: isValid ? {} : errors,
- }
-}
-
-SendTokenScreen.prototype.setErrorsFor = function (field) {
- const { errors: previousErrors } = this.state
-
- const {
- isValid,
- errors: newErrors,
- } = this.validate()
-
- const nextErrors = Object.assign({}, previousErrors, {
- [field]: newErrors[field] || null,
- })
-
- if (!isValid) {
- this.setState({
- errors: nextErrors,
- isValid,
- })
- }
-}
-
-SendTokenScreen.prototype.clearErrorsFor = function (field) {
- const { errors: previousErrors } = this.state
- const nextErrors = Object.assign({}, previousErrors, {
- [field]: null,
- })
-
- this.setState({
- errors: nextErrors,
- isValid: allNull(nextErrors),
- })
-}
-
-SendTokenScreen.prototype.getAmountToSend = function (amount, selectedToken) {
- const { decimals } = selectedToken || {}
- const multiplier = Math.pow(10, Number(decimals || 0))
- const sendAmount = '0x' + Number(amount * multiplier).toString(16)
- return sendAmount
-}
-
-SendTokenScreen.prototype.submit = function () {
- const {
- to,
- amount,
- gasPrice,
- gasLimit,
- } = this.state
-
- const {
- identities,
- selectedAddress,
- selectedTokenAddress,
- hideWarning,
- addToAddressBook,
- signTokenTx,
- selectedToken,
- } = this.props
-
- const { nickname = ' ' } = identities[to] || {}
-
- hideWarning()
- addToAddressBook(to, nickname)
-
- const txParams = {
- from: selectedAddress,
- value: '0',
- gas: gasLimit,
- gasPrice: gasPrice,
- }
-
- const sendAmount = this.getAmountToSend(amount, selectedToken)
-
- signTokenTx(selectedTokenAddress, to, sendAmount, txParams)
-}
-
-SendTokenScreen.prototype.renderToAddressInput = function () {
- const {
- identities,
- addressBook,
- } = this.props
-
- const {
- to,
- errors: { to: errorMessage },
- } = this.state
-
- return h('div', {
- className: classnames('send-screen-input-wrapper', {
- 'send-screen-input-wrapper--error': errorMessage,
- }),
- }, [
- h('div', ['To:']),
- h('input.large-input.send-screen-input', {
- name: 'address',
- list: 'addresses',
- placeholder: 'Address',
- value: to,
- onChange: e => this.setState({
- to: e.target.value,
- errors: {},
- }),
- onBlur: () => {
- this.setErrorsFor('to')
- },
- onFocus: event => {
- if (to) event.target.select()
- this.clearErrorsFor('to')
- },
- }),
- h('datalist#addresses', [
- // Corresponds to the addresses owned.
- Object.entries(identities).map(([key, { address, name }]) => {
- return h('option', {
- value: address,
- label: name,
- key: address,
- })
- }),
- addressBook.map(({ address, name }) => {
- return h('option', {
- value: address,
- label: name,
- key: address,
- })
- }),
- ]),
- h('div.send-screen-input-wrapper__error-message', [ errorMessage ]),
- ])
-}
-
-SendTokenScreen.prototype.renderAmountInput = function () {
- const {
- selectedCurrency,
- amount,
- errors: { amount: errorMessage },
- } = this.state
-
- const {
- tokenExchangeRate,
- selectedToken: {symbol},
- } = this.props
-
- return h('div.send-screen-input-wrapper', {
- className: classnames('send-screen-input-wrapper', {
- 'send-screen-input-wrapper--error': errorMessage,
- }),
- }, [
- h('div.send-screen-amount-labels', [
- h('span', ['Amount']),
- h(CurrencyToggle, {
- currentCurrency: tokenExchangeRate ? selectedCurrency : 'USD',
- currencies: tokenExchangeRate ? [ symbol, 'USD' ] : [],
- onClick: currency => this.setState({ selectedCurrency: currency }),
- }),
- ]),
- h('input.large-input.send-screen-input', {
- placeholder: `0 ${symbol}`,
- type: 'number',
- value: amount,
- onChange: e => this.setState({
- amount: e.target.value,
- }),
- onBlur: () => {
- this.setErrorsFor('amount')
- },
- onFocus: () => this.clearErrorsFor('amount'),
- }),
- h('div.send-screen-input-wrapper__error-message', [ errorMessage ]),
- ])
-}
-
-SendTokenScreen.prototype.renderGasInput = function () {
- const {
- isGasTooltipOpen,
- gasPrice,
- gasLimit,
- selectedCurrency,
- errors: {
- gasPrice: gasPriceErrorMessage,
- gasLimit: gasLimitErrorMessage,
- },
- } = this.state
-
- const {
- conversionRate,
- tokenExchangeRate,
- currentBlockGasLimit,
- } = this.props
-
- return h('div.send-screen-input-wrapper', {
- className: classnames('send-screen-input-wrapper', {
- 'send-screen-input-wrapper--error': gasPriceErrorMessage || gasLimitErrorMessage,
- }),
- }, [
- isGasTooltipOpen && h(GasTooltip, {
- className: 'send-tooltip',
- gasPrice: gasPrice || '0x0',
- gasLimit: gasLimit || '0x0',
- onClose: () => this.setState({ isGasTooltipOpen: false }),
- onFeeChange: ({ gasLimit, gasPrice }) => {
- this.setState({ gasLimit, gasPrice, errors: {} })
- },
- onBlur: () => {
- this.setErrorsFor('gasLimit')
- this.setErrorsFor('gasPrice')
- },
- onFocus: () => {
- this.clearErrorsFor('gasLimit')
- this.clearErrorsFor('gasPrice')
- },
- }),
-
- h('div.send-screen-gas-labels', {}, [
- h('span', [ h('i.fa.fa-bolt'), 'Gas fee:']),
- h('span', ['What\'s this?']),
- ]),
- h('div.large-input.send-screen-gas-input', [
- h(GasFeeDisplay, {
- conversionRate,
- tokenExchangeRate,
- gasPrice: gasPrice || '0x0',
- activeCurrency: selectedCurrency,
- gas: gasLimit || '0x0',
- blockGasLimit: currentBlockGasLimit,
- }),
- h(
- 'div.send-screen-gas-input-customize',
- { onClick: () => this.setState({ isGasTooltipOpen: !isGasTooltipOpen }) },
- ['Customize']
- ),
- ]),
- h('div.send-screen-input-wrapper__error-message', [
- gasPriceErrorMessage || gasLimitErrorMessage,
- ]),
- ])
-}
-
-SendTokenScreen.prototype.renderMemoInput = function () {
- return h('div.send-screen-input-wrapper', [
- h('div', {}, ['Transaction memo (optional)']),
- h(
- 'input.large-input.send-screen-input',
- { onChange: e => this.setState({ memo: e.target.value }) }
- ),
- ])
-}
-
-SendTokenScreen.prototype.renderButtons = function () {
- const { selectedAddress, backToAccountDetail } = this.props
- const { isValid } = this.validate()
-
- return h('div.send-token__button-group', [
- h('button.send-token__button-next.btn-secondary', {
- className: !isValid && 'send-screen__send-button__disabled',
- onClick: () => isValid && this.submit(),
- }, ['Next']),
- h('button.send-token__button-cancel.btn-tertiary', {
- onClick: () => backToAccountDetail(selectedAddress),
- }, ['Cancel']),
- ])
-}
-
-SendTokenScreen.prototype.render = function () {
- const {
- selectedTokenAddress,
- selectedToken,
- warning,
- } = this.props
-
- return h('div.send-token', [
- h('div.send-token__content', [
- h(Identicon, {
- diameter: 75,
- address: selectedTokenAddress,
- }),
- h('div.send-token__title', ['Send Tokens']),
- h('div.send-token__description', ['Send Tokens to anyone with an Ethereum account']),
- h('div.send-token__balance-text', ['Your Token Balance is:']),
- h('div.send-token__token-balance', [
- h(TokenBalance, { token: selectedToken, balanceOnly: true }),
- ]),
- h('div.send-token__token-symbol', [selectedToken.symbol]),
- this.renderToAddressInput(),
- this.renderAmountInput(),
- this.renderGasInput(),
- this.renderMemoInput(),
- warning && h('div.send-screen-input-wrapper--error', {},
- h('div.send-screen-input-wrapper__error-message', [
- warning,
- ])
- ),
- ]),
- this.renderButtons(),
- ])
-}
diff --git a/ui/app/components/send/currency-toggle.js b/ui/app/components/send/currency-toggle.js
deleted file mode 100644
index 7aaccd490..000000000
--- a/ui/app/components/send/currency-toggle.js
+++ /dev/null
@@ -1,44 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const classnames = require('classnames')
-
-module.exports = CurrencyToggle
-
-inherits(CurrencyToggle, Component)
-function CurrencyToggle () {
- Component.call(this)
-}
-
-const defaultCurrencies = [ 'ETH', 'USD' ]
-
-CurrencyToggle.prototype.renderToggles = function () {
- const { onClick, activeCurrency } = this.props
- const [currencyA, currencyB] = this.props.currencies || defaultCurrencies
-
- return [
- h('span', {
- className: classnames('currency-toggle__item', {
- 'currency-toggle__item--selected': currencyA === activeCurrency,
- }),
- onClick: () => onClick(currencyA),
- }, [ currencyA ]),
- '<>',
- h('span', {
- className: classnames('currency-toggle__item', {
- 'currency-toggle__item--selected': currencyB === activeCurrency,
- }),
- onClick: () => onClick(currencyB),
- }, [ currencyB ]),
- ]
-}
-
-CurrencyToggle.prototype.render = function () {
- const currencies = this.props.currencies || defaultCurrencies
-
- return h('span.currency-toggle', currencies.length
- ? this.renderToggles()
- : []
- )
-}
-
diff --git a/ui/app/components/send/eth-fee-display.js b/ui/app/components/send/eth-fee-display.js
deleted file mode 100644
index 9eda5ec62..000000000
--- a/ui/app/components/send/eth-fee-display.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const EthBalance = require('../eth-balance')
-const { getTxFeeBn } = require('../../util')
-
-module.exports = EthFeeDisplay
-
-inherits(EthFeeDisplay, Component)
-function EthFeeDisplay () {
- Component.call(this)
-}
-
-EthFeeDisplay.prototype.render = function () {
- const {
- activeCurrency,
- conversionRate,
- gas,
- gasPrice,
- blockGasLimit,
- } = this.props
-
- return h(EthBalance, {
- value: getTxFeeBn(gas, gasPrice, blockGasLimit),
- currentCurrency: activeCurrency,
- conversionRate,
- showFiat: false,
- hideTooltip: true,
- styleOveride: {
- color: '#5d5d5d',
- fontSize: '16px',
- fontFamily: 'DIN OT',
- lineHeight: '22.4px',
- },
- })
-}
-
diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js
index 0c4c3f7a9..f6af13454 100644
--- a/ui/app/components/send/gas-fee-display-v2.js
+++ b/ui/app/components/send/gas-fee-display-v2.js
@@ -2,6 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const CurrencyDisplay = require('./currency-display')
+const t = require('../../../i18n')
module.exports = GasFeeDisplay
@@ -17,6 +18,7 @@ GasFeeDisplay.prototype.render = function () {
onClick,
primaryCurrency = 'ETH',
convertedCurrency,
+ gasLoadingError,
} = this.props
return h('div.send-v2__gas-fee-display', [
@@ -30,15 +32,16 @@ GasFeeDisplay.prototype.render = function () {
convertedPrefix: '$',
readOnly: true,
})
- : h('div.currency-display', 'Loading...'),
+ : gasLoadingError
+ ? h('div..currency-display.currency-display--message', 'Set with the gas price customizer.')
+ : h('div.currency-display', t('loading')),
- h('button.send-v2__sliders-icon-container', {
+ h('button.sliders-icon-container', {
onClick,
- disabled: !gasTotal,
+ disabled: !gasTotal && !gasLoadingError,
}, [
- h('i.fa.fa-sliders.send-v2__sliders-icon'),
+ h('i.fa.fa-sliders.sliders-icon'),
]),
])
}
-
diff --git a/ui/app/components/send/gas-fee-display.js b/ui/app/components/send/gas-fee-display.js
deleted file mode 100644
index a9a3f3f49..000000000
--- a/ui/app/components/send/gas-fee-display.js
+++ /dev/null
@@ -1,62 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const USDFeeDisplay = require('./usd-fee-display')
-const EthFeeDisplay = require('./eth-fee-display')
-const { getTxFeeBn, formatBalance, shortenBalance } = require('../../util')
-
-module.exports = GasFeeDisplay
-
-inherits(GasFeeDisplay, Component)
-function GasFeeDisplay () {
- Component.call(this)
-}
-
-GasFeeDisplay.prototype.getTokenValue = function () {
- const {
- tokenExchangeRate,
- gas,
- gasPrice,
- blockGasLimit,
- } = this.props
-
- const value = formatBalance(getTxFeeBn(gas, gasPrice, blockGasLimit), 6, true)
- const [ethNumber] = value.split(' ')
-
- return shortenBalance(Number(ethNumber) / tokenExchangeRate, 6)
-}
-
-GasFeeDisplay.prototype.render = function () {
- const {
- activeCurrency,
- conversionRate,
- gas,
- gasPrice,
- blockGasLimit,
- } = this.props
-
- switch (activeCurrency) {
- case 'USD':
- return h(USDFeeDisplay, {
- activeCurrency,
- conversionRate,
- gas,
- gasPrice,
- blockGasLimit,
- })
- case 'ETH':
- return h(EthFeeDisplay, {
- activeCurrency,
- conversionRate,
- gas,
- gasPrice,
- blockGasLimit,
- })
- default:
- return h('div.token-gas', [
- h('div.token-gas__amount', this.getTokenValue()),
- h('div.token-gas__symbol', activeCurrency),
- ])
- }
-}
-
diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js
index 46aff3499..d925d3ed8 100644
--- a/ui/app/components/send/gas-tooltip.js
+++ b/ui/app/components/send/gas-tooltip.js
@@ -2,6 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const InputNumber = require('../input-number.js')
+const t = require('../../../i18n')
module.exports = GasTooltip
@@ -81,7 +82,7 @@ GasTooltip.prototype.render = function () {
'marginTop': '81px',
},
}, [
- h('span.gas-tooltip-label', {}, ['Gas Limit']),
+ h('span.gas-tooltip-label', {}, [t('gasLimit')]),
h('i.fa.fa-info-circle'),
]),
h(InputNumber, {
@@ -97,4 +98,3 @@ GasTooltip.prototype.render = function () {
]),
])
}
-
diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js
index 1106902b7..d1319b6dc 100644
--- a/ui/app/components/send/send-v2-container.js
+++ b/ui/app/components/send/send-v2-container.js
@@ -48,6 +48,7 @@ function mapStateToProps (state) {
primaryCurrency,
convertedCurrency: getCurrentCurrency(state),
data,
+ selectedAddress,
amountConversionRate: selectedToken ? tokenToFiatRate : conversionRate,
tokenContract: getSelectedTokenContract(state),
unapprovedTxs: state.metamask.unapprovedTxs,
diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js
index e0cdd0a58..72074229e 100644
--- a/ui/app/components/send/to-autocomplete.js
+++ b/ui/app/components/send/to-autocomplete.js
@@ -2,6 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const AccountListItem = require('./account-list-item')
+const t = require('../../../i18n')
module.exports = ToAutoComplete
@@ -92,7 +93,7 @@ ToAutoComplete.prototype.render = function () {
return h('div.send-v2__to-autocomplete', {}, [
h('input.send-v2__to-autocomplete__input', {
- placeholder: 'Recipient Address',
+ placeholder: t('recipientAddress'),
className: inError ? `send-v2__error-border` : '',
value: to,
onChange: event => onChange(event.target.value),
@@ -111,4 +112,3 @@ ToAutoComplete.prototype.render = function () {
])
}
-
diff --git a/ui/app/components/send/usd-fee-display.js b/ui/app/components/send/usd-fee-display.js
deleted file mode 100644
index 4cf31a493..000000000
--- a/ui/app/components/send/usd-fee-display.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const FiatValue = require('../fiat-value')
-const { getTxFeeBn } = require('../../util')
-
-module.exports = USDFeeDisplay
-
-inherits(USDFeeDisplay, Component)
-function USDFeeDisplay () {
- Component.call(this)
-}
-
-USDFeeDisplay.prototype.render = function () {
- const {
- activeCurrency,
- conversionRate,
- gas,
- gasPrice,
- blockGasLimit,
- } = this.props
-
- return h(FiatValue, {
- value: getTxFeeBn(gas, gasPrice, blockGasLimit),
- conversionRate,
- currentCurrency: activeCurrency,
- style: {
- color: '#5d5d5d',
- fontSize: '16px',
- fontFamily: 'DIN OT',
- lineHeight: '22.4px',
- },
- })
-}
-
diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js
new file mode 100644
index 000000000..25b9c7d6b
--- /dev/null
+++ b/ui/app/components/sender-to-recipient.js
@@ -0,0 +1,45 @@
+const { Component } = require('react')
+const h = require('react-hyperscript')
+const PropTypes = require('prop-types')
+const t = require('../../i18n')
+const Identicon = require('./identicon')
+
+class SenderToRecipient extends Component {
+ render () {
+ const { senderName, senderAddress } = this.props
+
+ return (
+ h('.sender-to-recipient__container', [
+ h('.sender-to-recipient__sender', [
+ h('.sender-to-recipient__sender-icon', [
+ h(Identicon, {
+ address: senderAddress,
+ diameter: 20,
+ }),
+ ]),
+ h('.sender-to-recipient__name.sender-to-recipient__sender-name', senderName),
+ ]),
+ h('.sender-to-recipient__arrow-container', [
+ h('.sender-to-recipient__arrow-circle', [
+ h('img', {
+ height: 15,
+ width: 15,
+ src: '/images/arrow-right.svg',
+ }),
+ ]),
+ ]),
+ h('.sender-to-recipient__recipient', [
+ h('i.fa.fa-file-text-o'),
+ h('.sender-to-recipient__name.sender-to-recipient__recipient-name', t('newContract')),
+ ]),
+ ])
+ )
+ }
+}
+
+SenderToRecipient.propTypes = {
+ senderName: PropTypes.string,
+ senderAddress: PropTypes.string,
+}
+
+module.exports = SenderToRecipient
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
index 87eb1588a..3f8c17932 100644
--- a/ui/app/components/shapeshift-form.js
+++ b/ui/app/components/shapeshift-form.js
@@ -7,6 +7,7 @@ const { qrcode } = require('qrcode-npm')
const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../actions')
const { isValidAddress } = require('../util')
const SimpleDropdown = require('./dropdowns/simple-dropdown')
+const t = require('../../i18n')
function mapStateToProps (state) {
const {
@@ -15,7 +16,7 @@ function mapStateToProps (state) {
selectedAddress,
} = state.metamask
const { warning } = state.appState
-
+
return {
coinOptions,
tokenExchangeRates,
@@ -93,7 +94,7 @@ ShapeshiftForm.prototype.onBuyWithShapeShift = function () {
}))
.catch(() => this.setState({
showQrCode: false,
- errorMessage: 'Invalid Request',
+ errorMessage: t('invalidRequest'),
isLoading: false,
}))
}
@@ -125,10 +126,10 @@ ShapeshiftForm.prototype.renderMarketInfo = function () {
return h('div.shapeshift-form__metadata', {}, [
- this.renderMetadata('Status', limit ? 'Available' : 'Unavailable'),
- this.renderMetadata('Limit', limit),
- this.renderMetadata('Exchange Rate', rate),
- this.renderMetadata('Minimum', minimum),
+ this.renderMetadata(t('status'), limit ? t('available') : t('unavailable')),
+ this.renderMetadata(t('limit'), limit),
+ this.renderMetadata(t('exchangeRate'), rate),
+ this.renderMetadata(t('min'), minimum),
])
}
@@ -142,7 +143,7 @@ ShapeshiftForm.prototype.renderQrCode = function () {
return h('div.shapeshift-form', {}, [
h('div.shapeshift-form__deposit-instruction', [
- `Deposit your ${depositCoin.toUpperCase()} to the address below:`,
+ t('depositCoin', [depositCoin.toUpperCase()]),
]),
h('div', depositAddress),
@@ -179,7 +180,7 @@ ShapeshiftForm.prototype.render = function () {
h('div.shapeshift-form__selector', [
- h('div.shapeshift-form__selector-label', 'Deposit'),
+ h('div.shapeshift-form__selector-label', t('deposit')),
h(SimpleDropdown, {
selectedOption: this.state.depositCoin,
@@ -199,7 +200,7 @@ ShapeshiftForm.prototype.render = function () {
h('div.shapeshift-form__selector', [
h('div.shapeshift-form__selector-label', [
- 'Receive',
+ t('receive'),
]),
h('div.shapeshift-form__selector-input', ['ETH']),
@@ -217,7 +218,7 @@ ShapeshiftForm.prototype.render = function () {
}, [
h('div.shapeshift-form__address-input-label', [
- 'Your Refund Address',
+ t('refundAddress'),
]),
h('input.shapeshift-form__address-input', {
@@ -239,7 +240,7 @@ ShapeshiftForm.prototype.render = function () {
className: btnClass,
disabled: !token,
onClick: () => this.onBuyWithShapeShift(),
- }, ['Buy']),
+ }, [t('buy')]),
])
}
diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js
index 017bf9f0c..fddbc6821 100644
--- a/ui/app/components/shift-list-item.js
+++ b/ui/app/components/shift-list-item.js
@@ -6,6 +6,7 @@ const vreme = new (require('vreme'))()
const explorerLink = require('etherscan-link').createExplorerLink
const actions = require('../actions')
const addressSummary = require('../util').addressSummary
+const t = require('../../i18n')
const CopyButton = require('./copyButton')
const EthBalance = require('./eth-balance')
@@ -75,7 +76,7 @@ ShiftListItem.prototype.renderUtilComponents = function () {
value: this.props.depositAddress,
}),
h(Tooltip, {
- title: 'QR Code',
+ title: t('qrCode'),
}, [
h('i.fa.fa-qrcode.pointer.pop-hover', {
onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)),
@@ -135,8 +136,8 @@ ShiftListItem.prototype.renderInfo = function () {
color: '#ABA9AA',
width: '100%',
},
- }, `${props.depositType} to ETH via ShapeShift`),
- h('div', 'No deposits received'),
+ }, t('toETHviaShapeShift', [props.depositType])),
+ h('div', t('noDeposits')),
h('div', {
style: {
fontSize: 'x-small',
@@ -158,8 +159,8 @@ ShiftListItem.prototype.renderInfo = function () {
color: '#ABA9AA',
width: '100%',
},
- }, `${props.depositType} to ETH via ShapeShift`),
- h('div', 'Conversion in progress'),
+ }, t('toETHviaShapeShift', [props.depositType])),
+ h('div', t('conversionProgress')),
h('div', {
style: {
fontSize: 'x-small',
@@ -184,7 +185,7 @@ ShiftListItem.prototype.renderInfo = function () {
color: '#ABA9AA',
width: '100%',
},
- }, 'From ShapeShift'),
+ }, t('fromShapeShift')),
h('div', formatDate(props.time)),
h('div', {
style: {
@@ -196,7 +197,7 @@ ShiftListItem.prototype.renderInfo = function () {
])
case 'failed':
- return h('span.error', '(Failed)')
+ return h('span.error', '(' + t('failed') + ')')
default:
return ''
}
diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js
index c5cc23aa8..7bf34e7b6 100644
--- a/ui/app/components/signature-request.js
+++ b/ui/app/components/signature-request.js
@@ -9,6 +9,7 @@ const classnames = require('classnames')
const AccountDropdownMini = require('./dropdowns/account-dropdown-mini')
const actions = require('../actions')
+const t = require('../../i18n')
const { conversionUtil } = require('../conversion-util')
const {
@@ -54,7 +55,7 @@ SignatureRequest.prototype.renderHeader = function () {
h('div.request-signature__header-background'),
- h('div.request-signature__header__text', 'Signature Request'),
+ h('div.request-signature__header__text', t('sigRequest')),
h('div.request-signature__header__tip-container', [
h('div.request-signature__header__tip'),
@@ -75,7 +76,7 @@ SignatureRequest.prototype.renderAccountDropdown = function () {
return h('div.request-signature__account', [
- h('div.request-signature__account-text', ['Account:']),
+ h('div.request-signature__account-text', [t('account') + ':']),
h(AccountDropdownMini, {
selectedAccount,
@@ -102,7 +103,7 @@ SignatureRequest.prototype.renderBalance = function () {
return h('div.request-signature__balance', [
- h('div.request-signature__balance-text', ['Balance:']),
+ h('div.request-signature__balance-text', [t('balance')]),
h('div.request-signature__balance-value', `${balanceInEther} ETH`),
@@ -136,7 +137,7 @@ SignatureRequest.prototype.renderRequestInfo = function () {
return h('div.request-signature__request-info', [
h('div.request-signature__headline', [
- `Your signature is being requested`,
+ t('yourSigRequested'),
]),
])
@@ -154,21 +155,18 @@ SignatureRequest.prototype.msgHexToText = function (hex) {
SignatureRequest.prototype.renderBody = function () {
let rows
- let notice = 'You are signing:'
+ let notice = t('youSign') + ':'
const { txData } = this.props
const { type, msgParams: { data } } = txData
if (type === 'personal_sign') {
- rows = [{ name: 'Message', value: this.msgHexToText(data) }]
+ rows = [{ name: t('message'), value: this.msgHexToText(data) }]
} else if (type === 'eth_signTypedData') {
rows = data
} else if (type === 'eth_sign') {
- rows = [{ name: 'Message', value: data }]
- notice = `Signing this message can have
- dangerous side effects. Only sign messages from
- sites you fully trust with your entire account.
- This dangerous method will be removed in a future version. `
+ rows = [{ name: t('message'), value: data }]
+ notice = t('signNotice')
}
return h('div.request-signature__body', {}, [
@@ -227,10 +225,10 @@ SignatureRequest.prototype.renderFooter = function () {
return h('div.request-signature__footer', [
h('button.request-signature__footer__cancel-button', {
onClick: cancel,
- }, 'CANCEL'),
+ }, t('cancel')),
h('button.request-signature__footer__sign-button', {
onClick: sign,
- }, 'SIGN'),
+ }, t('sign')),
])
}
@@ -250,4 +248,3 @@ SignatureRequest.prototype.render = function () {
)
}
-
diff --git a/ui/app/components/template.js b/ui/app/components/template.js
deleted file mode 100644
index b6ed8eaa0..000000000
--- a/ui/app/components/template.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-
-module.exports = NewComponent
-
-inherits(NewComponent, Component)
-function NewComponent () {
- Component.call(this)
-}
-
-NewComponent.prototype.render = function () {
- const props = this.props
-
- return (
- h('span', props.message)
- )
-}
diff --git a/ui/app/components/token-list.js b/ui/app/components/token-list.js
index 8e06e0f27..01529aeda 100644
--- a/ui/app/components/token-list.js
+++ b/ui/app/components/token-list.js
@@ -5,6 +5,7 @@ const TokenTracker = require('eth-token-tracker')
const TokenCell = require('./token-cell.js')
const connect = require('react-redux').connect
const selectors = require('../selectors')
+const t = require('../../i18n')
function mapStateToProps (state) {
return {
@@ -42,7 +43,7 @@ TokenList.prototype.render = function () {
const { tokens, isLoading, error } = state
if (isLoading) {
- return this.message('Loading Tokens...')
+ return this.message(t('loadingTokens'))
}
if (error) {
@@ -52,7 +53,7 @@ TokenList.prototype.render = function () {
padding: '80px',
},
}, [
- 'We had trouble loading your token balances. You can view them ',
+ t('troubleTokenBalances'),
h('span.hotFix', {
style: {
color: 'rgba(247, 134, 28, 1)',
@@ -63,7 +64,7 @@ TokenList.prototype.render = function () {
url: `https://ethplorer.io/address/${userAddress}`,
})
},
- }, 'here'),
+ }, t('here')),
])
}
diff --git a/ui/app/components/transaction-list-item-icon.js b/ui/app/components/transaction-list-item-icon.js
deleted file mode 100644
index f442b05af..000000000
--- a/ui/app/components/transaction-list-item-icon.js
+++ /dev/null
@@ -1,68 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const Tooltip = require('./tooltip')
-
-const Identicon = require('./identicon')
-
-module.exports = TransactionIcon
-
-inherits(TransactionIcon, Component)
-function TransactionIcon () {
- Component.call(this)
-}
-
-TransactionIcon.prototype.render = function () {
- const { transaction, txParams, isMsg } = this.props
- switch (transaction.status) {
- case 'unapproved':
- return h(!isMsg ? '.unapproved-tx-icon' : 'i.fa.fa-certificate.fa-lg')
-
- case 'rejected':
- return h('i.fa.fa-exclamation-triangle.fa-lg.warning', {
- style: {
- width: '24px',
- },
- })
-
- case 'failed':
- return h('i.fa.fa-exclamation-triangle.fa-lg.error', {
- style: {
- width: '24px',
- },
- })
-
- case 'submitted':
- return h(Tooltip, {
- title: 'Pending',
- position: 'right',
- }, [
- h('i.fa.fa-ellipsis-h', {
- style: {
- fontSize: '27px',
- },
- }),
- ])
- }
-
- if (isMsg) {
- return h('i.fa.fa-certificate.fa-lg', {
- style: {
- width: '24px',
- },
- })
- }
-
- if (txParams.to) {
- return h(Identicon, {
- diameter: 24,
- address: txParams.to || transaction.hash,
- })
- } else {
- return h('i.fa.fa-file-text-o.fa-lg', {
- style: {
- width: '24px',
- },
- })
- }
-}
diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js
deleted file mode 100644
index a45cd441a..000000000
--- a/ui/app/components/transaction-list-item.js
+++ /dev/null
@@ -1,238 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const connect = require('react-redux').connect
-
-const EthBalance = require('./eth-balance')
-const addressSummary = require('../util').addressSummary
-const explorerLink = require('etherscan-link').createExplorerLink
-const CopyButton = require('./copyButton')
-const vreme = new (require('vreme'))()
-const Tooltip = require('./tooltip')
-const numberToBN = require('number-to-bn')
-const actions = require('../actions')
-
-const TransactionIcon = require('./transaction-list-item-icon')
-const ShiftListItem = require('./shift-list-item')
-
-const mapDispatchToProps = dispatch => {
- return {
- retryTransaction: transactionId => dispatch(actions.retryTransaction(transactionId)),
- }
-}
-
-module.exports = connect(null, mapDispatchToProps)(TransactionListItem)
-
-inherits(TransactionListItem, Component)
-function TransactionListItem () {
- Component.call(this)
-}
-
-TransactionListItem.prototype.showRetryButton = function () {
- const { transaction = {} } = this.props
- const { status, time } = transaction
- return status === 'submitted' && Date.now() - time > 30000
-}
-
-TransactionListItem.prototype.render = function () {
- const { transaction, network, conversionRate, currentCurrency } = this.props
- const { status } = transaction
- if (transaction.key === 'shapeshift') {
- if (network === '1') return h(ShiftListItem, transaction)
- }
- var date = formatDate(transaction.time)
-
- let isLinkable = false
- const numericNet = parseInt(network)
- isLinkable = numericNet === 1 || numericNet === 3 || numericNet === 4 || numericNet === 42
-
- var isMsg = ('msgParams' in transaction)
- var isTx = ('txParams' in transaction)
- var isPending = status === 'unapproved'
- let txParams
- if (isTx) {
- txParams = transaction.txParams
- } else if (isMsg) {
- txParams = transaction.msgParams
- }
-
- const nonce = txParams.nonce ? numberToBN(txParams.nonce).toString(10) : ''
-
- const isClickable = ('hash' in transaction && isLinkable) || isPending
- return (
- h('.transaction-list-item.flex-column', {
- onClick: (event) => {
- if (isPending) {
- this.props.showTx(transaction.id)
- }
- event.stopPropagation()
- if (!transaction.hash || !isLinkable) return
- var url = explorerLink(transaction.hash, parseInt(network))
- global.platform.openWindow({ url })
- },
- style: {
- padding: '20px 0',
- alignItems: 'center',
- },
- }, [
- h(`.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, {
- style: {
- width: '100%',
- },
- }, [
- h('.identicon-wrapper.flex-column.flex-center.select-none', [
- h(TransactionIcon, { txParams, transaction, isTx, isMsg }),
- ]),
-
- h(Tooltip, {
- title: 'Transaction Number',
- position: 'right',
- }, [
- h('span', {
- style: {
- display: 'flex',
- cursor: 'normal',
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'center',
- padding: '10px',
- },
- }, nonce),
- ]),
-
- h('.flex-column', {style: {width: '200px', overflow: 'hidden'}}, [
- domainField(txParams),
- h('div', date),
- recipientField(txParams, transaction, isTx, isMsg),
- ]),
-
- // Places a copy button if tx is successful, else places a placeholder empty div.
- transaction.hash ? h(CopyButton, { value: transaction.hash }) : h('div', {style: { display: 'flex', alignItems: 'center', width: '26px' }}),
-
- isTx ? h(EthBalance, {
- value: txParams.value,
- conversionRate,
- currentCurrency,
- width: '55px',
- shorten: true,
- showFiat: false,
- style: {fontSize: '15px'},
- }) : h('.flex-column'),
- ]),
-
- this.showRetryButton() && h('.transition-list-item__retry.grow-on-hover', {
- onClick: event => {
- event.stopPropagation()
- this.resubmit()
- },
- style: {
- height: '22px',
- borderRadius: '22px',
- color: '#F9881B',
- padding: '0 20px',
- backgroundColor: '#FFE3C9',
- display: 'flex',
- justifyContent: 'center',
- alignItems: 'center',
- fontSize: '8px',
- cursor: 'pointer',
- },
- }, [
- h('div', {
- style: {
- paddingRight: '2px',
- },
- }, 'Taking too long?'),
- h('div', {
- style: {
- textDecoration: 'underline',
- },
- }, 'Retry with a higher gas price here'),
- ]),
- ])
- )
-}
-
-TransactionListItem.prototype.resubmit = function () {
- const { transaction } = this.props
- this.props.retryTransaction(transaction.id)
-}
-
-function domainField (txParams) {
- return h('div', {
- style: {
- fontSize: 'x-small',
- color: '#ABA9AA',
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- width: '100%',
- },
- }, [
- txParams.origin,
- ])
-}
-
-function recipientField (txParams, transaction, isTx, isMsg) {
- let message
-
- if (isMsg) {
- message = 'Signature Requested'
- } else if (txParams.to) {
- message = addressSummary(txParams.to)
- } else {
- message = 'Contract Deployment'
- }
-
- return h('div', {
- style: {
- fontSize: 'x-small',
- color: '#ABA9AA',
- },
- }, [
- message,
- renderErrorOrWarning(transaction),
- ])
-}
-
-function formatDate (date) {
- return vreme.format(new Date(date), 'March 16 2014 14:30')
-}
-
-function renderErrorOrWarning (transaction) {
- const { status } = transaction
-
- // show rejected
- if (status === 'rejected') {
- return h('span.error', ' (Rejected)')
- }
- if (transaction.err || transaction.warning) {
- const { err, warning = {} } = transaction
- const errFirst = !!((err && warning) || err)
-
- errFirst ? err.message : warning.message
-
- // show error
- if (err) {
- const message = err.message || ''
- return (
- h(Tooltip, {
- title: message,
- position: 'bottom',
- }, [
- h(`span.error`, ` (Failed)`),
- ])
- )
- }
-
- // show warning
- if (warning) {
- const message = warning.message
- return h(Tooltip, {
- title: message,
- position: 'bottom',
- }, [
- h(`span.warning`, ` (Warning)`),
- ])
- }
- }
-}
diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js
deleted file mode 100644
index 69b72614c..000000000
--- a/ui/app/components/transaction-list.js
+++ /dev/null
@@ -1,87 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-
-const TransactionListItem = require('./transaction-list-item')
-
-module.exports = TransactionList
-
-
-inherits(TransactionList, Component)
-function TransactionList () {
- Component.call(this)
-}
-
-TransactionList.prototype.render = function () {
- const { transactions, network, unapprovedMsgs, conversionRate } = this.props
-
- var shapeShiftTxList
- if (network === '1') {
- shapeShiftTxList = this.props.shapeShiftTxList
- }
- const txsToRender = !shapeShiftTxList ? transactions.concat(unapprovedMsgs) : transactions.concat(unapprovedMsgs, shapeShiftTxList)
- .sort((a, b) => b.time - a.time)
-
- return (
-
- h('section.transaction-list.full-flex-height', {
- style: {
- justifyContent: 'center',
- },
- }, [
-
- h('style', `
- .transaction-list .transaction-list-item:not(:last-of-type) {
- border-bottom: 1px solid #D4D4D4;
- }
- .transaction-list .transaction-list-item .ether-balance-label {
- display: block !important;
- font-size: small;
- }
- `),
-
- h('.tx-list', {
- style: {
- overflowY: 'auto',
- height: '100%',
- padding: '0 20px',
- textAlign: 'center',
- },
- }, [
-
- txsToRender.length
- ? txsToRender.map((transaction, i) => {
- let key
- switch (transaction.key) {
- case 'shapeshift':
- const { depositAddress, time } = transaction
- key = `shift-tx-${depositAddress}-${time}-${i}`
- break
- default:
- key = `tx-${transaction.id}-${i}`
- }
- return h(TransactionListItem, {
- transaction, i, network, key,
- conversionRate,
- showTx: (txId) => {
- this.props.viewPendingTx(txId)
- },
- })
- })
- : h('.flex-center.full-flex-height', {
- style: {
- flexDirection: 'column',
- justifyContent: 'center',
- },
- }, [
- h('p', {
- style: {
- marginTop: '50px',
- },
- }, 'No transaction history.'),
- ]),
- ]),
- ])
- )
-}
-
diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js
index 1a13070c8..d104eda88 100644
--- a/ui/app/components/tx-list-item.js
+++ b/ui/app/components/tx-list-item.js
@@ -9,18 +9,28 @@ abiDecoder.addABI(abi)
const Identicon = require('./identicon')
const contractMap = require('eth-contract-metadata')
+const actions = require('../actions')
const { conversionUtil, multiplyCurrencies } = require('../conversion-util')
const { calcTokenAmount } = require('../token-util')
const { getCurrentCurrency } = require('../selectors')
+const t = require('../../i18n')
-module.exports = connect(mapStateToProps)(TxListItem)
+module.exports = connect(mapStateToProps, mapDispatchToProps)(TxListItem)
function mapStateToProps (state) {
return {
tokens: state.metamask.tokens,
currentCurrency: getCurrentCurrency(state),
tokenExchangeRates: state.metamask.tokenExchangeRates,
+ selectedAddressTxList: state.metamask.selectedAddressTxList,
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ setSelectedToken: tokenAddress => dispatch(actions.setSelectedToken(tokenAddress)),
+ retryTransaction: transactionId => dispatch(actions.retryTransaction(transactionId)),
}
}
@@ -31,6 +41,7 @@ function TxListItem () {
this.state = {
total: null,
fiatTotal: null,
+ isTokenTx: null,
}
}
@@ -39,12 +50,13 @@ TxListItem.prototype.componentDidMount = async function () {
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
const { name: txDataName } = decodedData || {}
+ const isTokenTx = txDataName === 'transfer'
- const { total, fiatTotal } = txDataName === 'transfer'
+ const { total, fiatTotal } = isTokenTx
? await this.getSendTokenTotal()
: this.getSendEtherTotal()
- this.setState({ total, fiatTotal })
+ this.setState({ total, fiatTotal, isTokenTx })
}
TxListItem.prototype.getAddressText = function () {
@@ -63,7 +75,7 @@ TxListItem.prototype.getAddressText = function () {
default:
return address
? `${address.slice(0, 10)}...${address.slice(-4)}`
- : 'Contract Deployment'
+ : t('contractDeployment')
}
}
@@ -167,22 +179,49 @@ TxListItem.prototype.getSendTokenTotal = async function () {
}
}
+TxListItem.prototype.showRetryButton = function () {
+ const {
+ transactionSubmittedTime,
+ selectedAddressTxList,
+ transactionId,
+ txParams,
+ } = this.props
+ const currentNonce = txParams.nonce
+ const currentNonceTxs = selectedAddressTxList.filter(tx => tx.txParams.nonce === currentNonce)
+ const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
+ const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[currentNonceSubmittedTxs.length - 1]
+ const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce
+ && lastSubmittedTxWithCurrentNonce.id === transactionId
+
+ return currentTxIsLatestWithNonce && Date.now() - transactionSubmittedTime > 30000
+}
+
+TxListItem.prototype.setSelectedToken = function (tokenAddress) {
+ this.props.setSelectedToken(tokenAddress)
+}
+
+TxListItem.prototype.resubmit = function () {
+ const { transactionId } = this.props
+ this.props.retryTransaction(transactionId)
+}
+
TxListItem.prototype.render = function () {
const {
transactionStatus,
transactionAmount,
onClick,
- transActionId,
+ transactionId,
dateString,
address,
className,
+ txParams,
} = this.props
- const { total, fiatTotal } = this.state
+ const { total, fiatTotal, isTokenTx } = this.state
const showFiatTotal = transactionAmount !== '0x0' && fiatTotal
return h(`div${className || ''}`, {
- key: transActionId,
- onClick: () => onClick && onClick(transActionId),
+ key: transactionId,
+ onClick: () => onClick && onClick(transactionId),
}, [
h(`div.flex-column.tx-list-item-wrapper`, {}, [
@@ -223,9 +262,10 @@ TxListItem.prototype.render = function () {
className: classnames('tx-list-status', {
'tx-list-status--rejected': transactionStatus === 'rejected',
'tx-list-status--failed': transactionStatus === 'failed',
+ 'tx-list-status--dropped': transactionStatus === 'dropped',
}),
},
- transactionStatus,
+ this.txStatusIndicator(),
),
]),
]),
@@ -240,6 +280,48 @@ TxListItem.prototype.render = function () {
]),
]),
+
+ this.showRetryButton() && h('div.tx-list-item-retry-container', [
+
+ h('span.tx-list-item-retry-copy', 'Taking too long?'),
+
+ h('span.tx-list-item-retry-link', {
+ onClick: (event) => {
+ event.stopPropagation()
+ if (isTokenTx) {
+ this.setSelectedToken(txParams.to)
+ }
+ this.resubmit()
+ },
+ }, 'Increase the gas price on your transaction'),
+
+ ]),
+
]), // holding on icon from design
])
}
+
+TxListItem.prototype.txStatusIndicator = function () {
+ const { transactionStatus } = this.props
+
+ let name
+
+ if (transactionStatus === 'unapproved') {
+ name = t('unapproved')
+ } else if (transactionStatus === 'rejected') {
+ name = t('rejected')
+ } else if (transactionStatus === 'approved') {
+ name = t('approved')
+ } else if (transactionStatus === 'signed') {
+ name = t('signed')
+ } else if (transactionStatus === 'submitted') {
+ name = t('submitted')
+ } else if (transactionStatus === 'confirmed') {
+ name = t('confirmed')
+ } else if (transactionStatus === 'failed') {
+ name = t('failed')
+ } else if (transactionStatus === 'dropped') {
+ name = t('dropped')
+ }
+ return name
+}
diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js
index 1729e6a6f..037c7de8c 100644
--- a/ui/app/components/tx-list.js
+++ b/ui/app/components/tx-list.js
@@ -10,6 +10,7 @@ const { formatDate } = require('../util')
const { showConfTxPage } = require('../actions')
const classnames = require('classnames')
const { tokenInfoGetter } = require('../token-util')
+const t = require('../../i18n')
module.exports = connect(mapStateToProps, mapDispatchToProps)(TxList)
@@ -39,7 +40,7 @@ TxList.prototype.render = function () {
return h('div.flex-column', [
h('div.flex-row.tx-list-header-wrapper', [
h('div.flex-row.tx-list-header', [
- h('div', 'transactions'),
+ h('div', t('transactions')),
]),
]),
h('div.flex-column.tx-list-container', {}, [
@@ -56,7 +57,7 @@ TxList.prototype.renderTransaction = function () {
: [h(
'div.tx-list-item.tx-list-item--empty',
{ key: 'tx-list-none' },
- [ 'No Transactions' ],
+ [ t('noTransactions') ],
)]
}
@@ -74,9 +75,10 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa
address: transaction.txParams.to,
transactionStatus: transaction.status,
transactionAmount: transaction.txParams.value,
- transActionId: transaction.id,
+ transactionId: transaction.id,
transactionHash: transaction.hash,
transactionNetworkId: transaction.metamaskNetworkId,
+ transactionSubmittedTime: transaction.submittedTime,
}
const {
@@ -84,30 +86,32 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa
transactionStatus,
transactionAmount,
dateString,
- transActionId,
+ transactionId,
transactionHash,
transactionNetworkId,
+ transactionSubmittedTime,
} = props
const { showConfTxPage } = this.props
const opts = {
- key: transActionId || transactionHash,
+ key: transactionId || transactionHash,
txParams: transaction.txParams,
transactionStatus,
- transActionId,
+ transactionId,
dateString,
address,
transactionAmount,
transactionHash,
conversionRate,
tokenInfoGetter: this.tokenInfoGetter,
+ transactionSubmittedTime,
}
const isUnapproved = transactionStatus === 'unapproved'
if (isUnapproved) {
- opts.onClick = () => showConfTxPage({id: transActionId})
- opts.transactionStatus = 'Not Started'
+ opts.onClick = () => showConfTxPage({id: transactionId})
+ opts.transactionStatus = t('Not Started')
} else if (transactionHash) {
opts.onClick = () => this.view(transactionHash, transactionNetworkId)
}
diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js
index b25d8e0f9..96d776270 100644
--- a/ui/app/components/tx-view.js
+++ b/ui/app/components/tx-view.js
@@ -5,6 +5,7 @@ const ethUtil = require('ethereumjs-util')
const inherits = require('util').inherits
const actions = require('../actions')
const selectors = require('../selectors')
+const t = require('../../i18n')
const BalanceComponent = require('./balance-component')
const TxList = require('./tx-list')
@@ -68,25 +69,25 @@ TxView.prototype.renderButtons = function () {
return !selectedToken
? (
h('div.flex-row.flex-center.hero-balance-buttons', [
- h('button.btn-clear.hero-balance-button', {
+ h('button.btn-clear.hero-balance-button.allcaps', {
onClick: () => showModal({
name: 'DEPOSIT_ETHER',
}),
- }, 'DEPOSIT'),
+ }, t('deposit')),
- h('button.btn-clear.hero-balance-button', {
+ h('button.btn-clear.hero-balance-button.allcaps', {
style: {
marginLeft: '0.8em',
},
onClick: showSendPage,
- }, 'SEND'),
+ }, t('send')),
])
)
: (
h('div.flex-row.flex-center.hero-balance-buttons', [
h('button.btn-clear.hero-balance-button', {
onClick: showSendTokenPage,
- }, 'SEND'),
+ }, t('send')),
])
)
}
@@ -100,9 +101,10 @@ TxView.prototype.render = function () {
h('div.flex-row.phone-visible', {
style: {
- margin: '1.5em 1.2em 0',
justifyContent: 'space-between',
alignItems: 'center',
+ flex: '0 0 auto',
+ margin: '10px',
},
}, [
@@ -110,11 +112,10 @@ TxView.prototype.render = function () {
style: {
fontSize: '1.3em',
cursor: 'pointer',
+ padding: '10px',
},
- onClick: () => {
- this.props.sidebarOpen ? this.props.hideSidebar() : this.props.showSidebar()
- },
- }, []),
+ onClick: () => this.props.sidebarOpen ? this.props.hideSidebar() : this.props.showSidebar(),
+ }),
h('.identicon-wrapper.select-none', {
style: {
diff --git a/ui/app/components/typed-message-renderer.js b/ui/app/components/typed-message-renderer.js
deleted file mode 100644
index d170d63b7..000000000
--- a/ui/app/components/typed-message-renderer.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const extend = require('xtend')
-
-module.exports = TypedMessageRenderer
-
-inherits(TypedMessageRenderer, Component)
-function TypedMessageRenderer () {
- Component.call(this)
-}
-
-TypedMessageRenderer.prototype.render = function () {
- const props = this.props
- const { value, style } = props
- const text = renderTypedData(value)
-
- const defaultStyle = extend({
- width: '315px',
- maxHeight: '210px',
- resize: 'none',
- border: 'none',
- background: 'white',
- padding: '3px',
- overflow: 'scroll',
- }, style)
-
- return (
- h('div.font-small', {
- style: defaultStyle,
- }, text)
- )
-}
-
-function renderTypedData (values) {
- return values.map(function (value) {
- return h('div', {}, [
- h('strong', {style: {display: 'block', fontWeight: 'bold'}}, String(value.name) + ':'),
- h('div', {}, value.value),
- ])
- })
-}
diff --git a/ui/app/components/wallet-content-display.js b/ui/app/components/wallet-content-display.js
deleted file mode 100644
index bfa061be4..000000000
--- a/ui/app/components/wallet-content-display.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-
-module.exports = WalletContentDisplay
-
-inherits(WalletContentDisplay, Component)
-function WalletContentDisplay () {
- Component.call(this)
-}
-
-WalletContentDisplay.prototype.render = function () {
- const { title, amount, fiatValue, active, style } = this.props
-
- // TODO: Separate component: wallet-content-account
- return h('div.flex-column', {
- style: {
- marginLeft: '1.3em',
- alignItems: 'flex-start',
- ...style,
- },
- }, [
-
- h('span', {
- style: {
- fontSize: '1.1em',
- },
- }, title),
-
- h('span', {
- style: {
- fontSize: '1.8em',
- margin: '0.4em 0em',
- },
- }, amount),
-
- h('span', {
- style: {
- fontSize: '1.3em',
- },
- }, fiatValue),
-
- active && h('div', {
- style: {
- position: 'absolute',
- marginLeft: '-1.3em',
- height: '6em',
- width: '0.3em',
- background: '#D8D8D8', // $alto
- },
- }, [
- ]),
- ])
-
-}
-
diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js
index 34f27ca2a..18452205c 100644
--- a/ui/app/components/wallet-view.js
+++ b/ui/app/components/wallet-view.js
@@ -11,6 +11,7 @@ const actions = require('../actions')
const BalanceComponent = require('./balance-component')
const TokenList = require('./token-list')
const selectors = require('../selectors')
+const t = require('../../i18n')
module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView)
@@ -116,7 +117,7 @@ WalletView.prototype.render = function () {
onClick: hideSidebar,
}),
- h('div.wallet-view__keyring-label', isLoose ? 'IMPORTED' : ''),
+ h('div.wallet-view__keyring-label.allcaps', isLoose ? t('imported') : ''),
h('div.flex-column.flex-center.wallet-view__name-container', {
style: { margin: '0 auto' },
@@ -133,13 +134,13 @@ WalletView.prototype.render = function () {
selectedIdentity.name,
]),
- h('button.btn-clear.wallet-view__details-button', 'DETAILS'),
+ h('button.btn-clear.wallet-view__details-button.allcaps', t('details')),
]),
]),
h(Tooltip, {
position: 'bottom',
- title: this.state.hasCopied ? 'Copied!' : 'Copy to clipboard',
+ title: this.state.hasCopied ? t('copiedExclamation') : t('copyToClipboard'),
wrapperClassName: 'wallet-view__tooltip',
}, [
h('button.wallet-view__address', {
@@ -172,7 +173,7 @@ WalletView.prototype.render = function () {
showAddTokenPage()
hideSidebar()
},
- }, 'Add Token'),
+ }, t('addToken')),
])
}
diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js
index b4ffc48b7..1070436c3 100644
--- a/ui/app/conf-tx.js
+++ b/ui/app/conf-tx.js
@@ -40,6 +40,7 @@ function mapStateToProps (state) {
currentCurrency: state.metamask.currentCurrency,
blockGasLimit: state.metamask.currentBlockGasLimit,
computedBalances: state.metamask.computedBalances,
+ selectedAddressTxList: state.metamask.selectedAddressTxList,
}
}
@@ -48,6 +49,23 @@ function ConfirmTxScreen () {
Component.call(this)
}
+ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) {
+ const {
+ unapprovedTxs,
+ network,
+ selectedAddressTxList,
+ } = this.props
+ const { index: prevIndex, unapprovedTxs: prevUnapprovedTxs } = prevProps
+ const prevUnconfTxList = txHelper(prevUnapprovedTxs, {}, {}, {}, network)
+ const prevTxData = prevUnconfTxList[prevIndex] || {}
+ const prevTx = selectedAddressTxList.find(({ id }) => id === prevTxData.id) || {}
+ const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network)
+
+ if (prevTx.status === 'dropped' && unconfTxList.length === 0) {
+ this.goHome({})
+ }
+}
+
ConfirmTxScreen.prototype.render = function () {
const props = this.props
const {
diff --git a/ui/app/conversion-util.js b/ui/app/conversion-util.js
index ee42ebea1..d484ed16d 100644
--- a/ui/app/conversion-util.js
+++ b/ui/app/conversion-util.js
@@ -187,6 +187,18 @@ const conversionGreaterThan = (
return firstValue.gt(secondValue)
}
+const conversionMax = (
+ { ...firstProps },
+ { ...secondProps },
+) => {
+ const firstIsGreater = conversionGreaterThan(
+ { ...firstProps },
+ { ...secondProps }
+ )
+
+ return firstIsGreater ? firstProps.value : secondProps.value
+}
+
const conversionGTE = (
{ ...firstProps },
{ ...secondProps },
@@ -216,6 +228,7 @@ module.exports = {
conversionGreaterThan,
conversionGTE,
conversionLTE,
+ conversionMax,
toNegative,
subtractCurrencies,
}
diff --git a/ui/app/css/itcss/components/account-menu.scss b/ui/app/css/itcss/components/account-menu.scss
index 4752741aa..c4037d862 100644
--- a/ui/app/css/itcss/components/account-menu.scss
+++ b/ui/app/css/itcss/components/account-menu.scss
@@ -87,7 +87,6 @@
flex: 1 0 auto;
display: flex;
flex-flow: column nowrap;
- padding-top: 4px;
}
&__check-mark {
@@ -115,13 +114,11 @@
color: $white;
font-size: 18px;
font-weight: 300;
- line-height: 16px;
}
&__balance {
color: $dusty-gray;
font-size: 14px;
- line-height: 19px;
}
&__action {
diff --git a/ui/app/css/itcss/components/buttons.scss b/ui/app/css/itcss/components/buttons.scss
index 1450b71cc..8df8829f2 100644
--- a/ui/app/css/itcss/components/buttons.scss
+++ b/ui/app/css/itcss/components/buttons.scss
@@ -45,6 +45,18 @@
}
}
+.btn-confirm {
+ background-color: $caribbean-green; // TODO: reusable color in colors.css
+ text-align: center;
+ padding: .8rem 1rem;
+ color: $white;
+ border: 2px solid $caribbean-green;
+ border-radius: 4px;
+ font-size: .85rem;
+ font-weight: 400;
+ transition: border-color .3s ease;
+}
+
// No longer used in flat design, remove when modal buttons done
// div.wallet-btn {
// border: 1px solid rgb(91, 93, 103);
diff --git a/ui/app/css/itcss/components/confirm.scss b/ui/app/css/itcss/components/confirm.scss
index 878495290..abe138f54 100644
--- a/ui/app/css/itcss/components/confirm.scss
+++ b/ui/app/css/itcss/components/confirm.scss
@@ -202,7 +202,7 @@
}
.confirm-screen-label {
- font-size: 18px;
+ font-size: 16px;
line-height: 40px;
color: $scorpion;
text-align: left;
@@ -229,7 +229,6 @@ section .confirm-screen-account-number,
.confirm-screen-row {
display: flex;
flex-flow: row nowrap;
- border-bottom: 1px solid $alto;
width: 100%;
align-items: center;
padding: 12px;
@@ -237,6 +236,26 @@ section .confirm-screen-account-number,
font-size: 16px;
line-height: 22px;
font-weight: 300;
+
+ &:not(:last-of-type) {
+ border-bottom: 1px solid $alto;
+ }
+}
+
+@media screen and (max-width: 379px) {
+ .confirm-screen-row {
+ span.confirm-screen-section-column {
+ flex: 0.4;
+ }
+
+ div.confirm-screen-section-column {
+ flex: 0.6;
+ }
+
+ .currency-display__input {
+ font-size: 14px;
+ }
+ }
}
.confirm-screen-row-detail {
@@ -247,12 +266,9 @@ section .confirm-screen-account-number,
.confirm-screen-total-box {
background-color: $wild-sand;
- padding: 20px;
- padding-left: 35px;
- border-bottom: 1px solid $alto;
.confirm-screen-label {
- line-height: 18px;
+ line-height: 21px;
}
.confirm-screen-row-detail {
@@ -261,7 +277,7 @@ section .confirm-screen-account-number,
&__subtitle {
font-size: 12px;
- line-height: 22px;
+ line-height: 16px;
}
.confirm-screen-row-info {
@@ -304,21 +320,3 @@ section .confirm-screen-account-number,
font-weight: 300;
margin: 0 5px;
}
-
-#pending-tx-form {
- flex: 1 0 auto;
- position: relative;
- display: flex;
- flex-flow: row nowrap;
- background-color: $white;
- padding: 12px;
- border-bottom-left-radius: 8px;
- border-bottom-right-radius: 8px;
- width: 100%;
-
- @media screen and (max-width: $break-small) {
- border-top: 1px solid $alto;
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- }
-}
diff --git a/ui/app/css/itcss/components/hero-balance.scss b/ui/app/css/itcss/components/hero-balance.scss
index 4af0c2c55..a3f051361 100644
--- a/ui/app/css/itcss/components/hero-balance.scss
+++ b/ui/app/css/itcss/components/hero-balance.scss
@@ -5,9 +5,6 @@
flex-direction: column;
justify-content: flex-start;
align-items: center;
- margin: .3em .9em 0;
- // height: 80vh;
- // max-height: 225px;
flex: 0 0 auto;
}
diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss
index 0219f9fb2..ffd43ecbf 100644
--- a/ui/app/css/itcss/components/index.scss
+++ b/ui/app/css/itcss/components/index.scss
@@ -55,3 +55,7 @@
@import './new-account.scss';
@import './tooltip.scss';
+
+@import './welcome-screen.scss';
+
+@import './sender-to-recipient.scss';
diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss
index 53e3bff00..a8d5e8dc2 100644
--- a/ui/app/css/itcss/components/modal.scss
+++ b/ui/app/css/itcss/components/modal.scss
@@ -641,32 +641,40 @@
&__buy-rows {
width: 100%;
- padding: 33px;
- padding-top: 0px;
+ padding: 0 30px;
display: flex;
flex-flow: column nowrap;
flex: 1;
- overflow-y: auto;
@media screen and (max-width: 575px) {
height: 0;
}
}
+ &__logo {
+ height: 60px;
+ background-repeat: no-repeat;
+ background-size: contain;
+ background-position: center;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
&__buy-row {
border-bottom: 1px solid $alto;
display: flex;
justify-content: space-between;
align-items: center;
- flex: 1;
- padding-bottom: 25px;
- padding-top: 25px;
+ flex: 1 0 auto;
+ padding: 30px 0 20px;
+ min-height: 170px;
@media screen and (max-width: 575px) {
- min-height: 360px;
+ min-height: 270px;
flex-flow: column;
- justify-content: center;
- padding-top: 45px;
+ justify-content: flex-start;
}
&__back {
@@ -692,34 +700,29 @@
}
}
- &__logo {
+ &__logo-container {
display: flex;
justify-content: center;
- flex: 0.3 1 auto;
+ flex: 0 0 auto;
+ padding: 0 20px;
- @media screen and (min-width: 575px) {
- min-width: 215px;
+ @media screen and (min-width: 576px) {
+ width: 12rem;
+ }
+
+ @media screen and (max-width: 575px) {
+ width: 100%;
+ max-height: 6rem;
+ padding-bottom: 20px;
}
}
&__coinbase-logo {
height: 40px;
- width: 180px;
}
&__shapeshift-logo {
height: 60px;
- width: 174px;
- }
-
- &__eth-logo {
- border-radius: 50%;
- width: 68px;
- height: 68px;
- border: 3px solid $tundora;
- z-index: 25;
- padding: 4px;
- background-color: #fff;
}
&__right {
@@ -728,10 +731,11 @@
&__description {
color: $cape-cod;
- flex: 0.5 1 auto;
+ padding-bottom: 20px;
+ align-self: flex-start;
@media screen and (min-width: 575px) {
- min-width: 315px;
+ width: 15rem;
}
&__title {
diff --git a/ui/app/css/itcss/components/network.scss b/ui/app/css/itcss/components/network.scss
index c32d1de5e..374cb71b6 100644
--- a/ui/app/css/itcss/components/network.scss
+++ b/ui/app/css/itcss/components/network.scss
@@ -10,8 +10,9 @@
.network-component.pointer {
border: 2px solid $silver;
border-radius: 82px;
- padding: 3px;
+ padding: 7px 3px;
flex: 0 0 auto;
+ display: flex;
&.ethereum-network .menu-icon-circle div {
background-color: rgba(3, 135, 137, .7) !important;
diff --git a/ui/app/css/itcss/components/new-account.scss b/ui/app/css/itcss/components/new-account.scss
index 08cff867d..c2cefe4ad 100644
--- a/ui/app/css/itcss/components/new-account.scss
+++ b/ui/app/css/itcss/components/new-account.scss
@@ -161,15 +161,14 @@
display: flex;
flex-flow: column;
align-items: center;
+ padding: 30px 30px 0;
&__input-label {
color: $scorpion;
font-family: Roboto;
font-size: 16px;
line-height: 21px;
- margin-top: 29px;
align-self: flex-start;
- margin-left: 30px;
}
&__input {
diff --git a/ui/app/css/itcss/components/newui-sections.scss b/ui/app/css/itcss/components/newui-sections.scss
index ecf5e1036..777a82318 100644
--- a/ui/app/css/itcss/components/newui-sections.scss
+++ b/ui/app/css/itcss/components/newui-sections.scss
@@ -51,6 +51,7 @@ $wallet-view-bg: $alabaster;
cursor: pointer;
display: flex;
justify-content: center;
+ padding: 10px;
}
// wallet view and sidebar
@@ -264,7 +265,6 @@ $wallet-view-bg: $alabaster;
.account-name {
font-size: 24px;
font-weight: 300;
- line-height: 20px;
color: $black;
margin-top: 8px;
margin-bottom: .9rem;
@@ -291,7 +291,6 @@ $wallet-view-bg: $alabaster;
padding-right: 6px;
}
-
// first time
.first-view-main {
display: flex;
@@ -313,4 +312,23 @@ $wallet-view-bg: $alabaster;
@media screen and (min-width: 1281px) {
width: 62vw;
}
-} \ No newline at end of file
+}
+
+.unlock-screen-container {
+ z-index: $main-container-z-index;
+ font-family: Roboto;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex: 1 0 auto;
+ background: #f7f7f7;
+ width: 100%;
+}
+
+.unlock-screen {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ flex: 1 0 auto;
+}
diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss
index bb17e53cd..bdea1b008 100644
--- a/ui/app/css/itcss/components/send.scss
+++ b/ui/app/css/itcss/components/send.scss
@@ -660,6 +660,13 @@
&__gas-fee-display {
width: 100%;
+ position: relative;
+
+ .currency-display--message {
+ padding: 8px 38px 8px 10px;
+ display: flex;
+ align-items: center;
+ }
}
&__sliders-icon-container {
@@ -885,3 +892,23 @@
}
}
}
+
+.sliders-icon-container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 24px;
+ width: 24px;
+ border: 1px solid $curious-blue;
+ border-radius: 4px;
+ background-color: $white;
+ position: absolute;
+ right: 15px;
+ top: 14px;
+ cursor: pointer;
+ font-size: 1em;
+}
+
+.sliders-icon {
+ color: $curious-blue;
+} \ No newline at end of file
diff --git a/ui/app/css/itcss/components/sender-to-recipient.scss b/ui/app/css/itcss/components/sender-to-recipient.scss
new file mode 100644
index 000000000..f16013cdf
--- /dev/null
+++ b/ui/app/css/itcss/components/sender-to-recipient.scss
@@ -0,0 +1,58 @@
+.sender-to-recipient {
+ &__container {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ border-bottom: 1px solid $geyser;
+ position: relative;
+ }
+
+ &__sender,
+ &__recipient {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ flex: 1;
+ padding: 10px 20px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ &__sender {
+ padding-right: 30px;
+ }
+
+ &__recipient {
+ border-left: 1px solid $geyser;
+ padding-left: 30px;
+ }
+
+ &__arrow-container {
+ position: absolute;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ &__arrow-circle {
+ background: $white;
+ padding: 5px;
+ border: 1px solid $geyser;
+ border-radius: 20px;
+ height: 30px;
+ width: 30px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ &__name {
+ padding-left: 5px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+}
diff --git a/ui/app/css/itcss/components/transaction-list.scss b/ui/app/css/itcss/components/transaction-list.scss
index c3df493df..d03faf486 100644
--- a/ui/app/css/itcss/components/transaction-list.scss
+++ b/ui/app/css/itcss/components/transaction-list.scss
@@ -97,7 +97,7 @@
.tx-list-content-wrapper {
align-items: stretch;
- margin-bottom: 4px;
+ margin: 4px 0;
flex: 1 0 auto;
width: 100%;
display: flex;
@@ -126,6 +126,54 @@
}
}
+.tx-list-item-retry-container {
+ background: #d1edff;
+ width: 100%;
+ border-radius: 4px;
+ font-size: 0.8em;
+ display: flex;
+ justify-content: center;
+ margin-left: 44px;
+ width: calc(100% - 44px);
+
+ @media screen and (min-width: 576px) and (max-width: 679px) {
+ flex-flow: column;
+ align-items: center;
+ }
+
+ @media screen and (min-width: 380px) and (max-width: 575px) {
+ flex-flow: row;
+ }
+
+ @media screen and (max-width: 379px) {
+ flex-flow: column;
+ align-items: center;
+ }
+}
+
+.tx-list-item-retry-copy {
+ font-family: Roboto;
+}
+
+.tx-list-item-retry-link {
+ text-decoration: underline;
+ margin-left: 6px;
+ cursor: pointer;
+
+ @media screen and (min-width: 576px) and (max-width: 679px) {
+ margin-left: 0px;
+ }
+
+ @media screen and (min-width: 380px) and (max-width: 575px) {
+ margin-left: 6px;
+ }
+
+ @media screen and (max-width: 379px) {
+ margin-left: 0px;
+ text-align: center;
+ }
+}
+
.tx-list-date {
color: $dusty-gray;
font-size: 12px;
@@ -136,6 +184,7 @@
align-self: center;
flex: 0 0 auto;
margin-right: 16px;
+ display: flex;
}
.tx-list-account-and-status-wrapper {
@@ -189,6 +238,10 @@
.tx-list-status--failed {
color: $monzo;
}
+
+ .tx-list-status--dropped {
+ opacity: 0.5;
+ }
}
.tx-list-item {
diff --git a/ui/app/css/itcss/components/welcome-screen.scss b/ui/app/css/itcss/components/welcome-screen.scss
new file mode 100644
index 000000000..bfd174ad9
--- /dev/null
+++ b/ui/app/css/itcss/components/welcome-screen.scss
@@ -0,0 +1,59 @@
+.welcome-screen {
+ display: flex;
+ flex-flow: column;
+ justify-content: center;
+ align-items: center;
+ font-family: Roboto;
+ font-weight: 400;
+ width: 100%;
+ flex: 1 0 auto;
+ padding: 70px 0;
+ background: $white;
+
+ @media screen and (max-width: 575px) {
+ padding: 0;
+ }
+
+ &__info {
+ display: flex;
+ flex-flow: column;
+ width: 100%;
+ height: 100%;
+ align-items: center;
+
+ &__header {
+ font-size: 1.65em;
+ margin-bottom: 14px;
+
+ @media screen and (max-width: 575px) {
+ font-size: 1.5em;
+ }
+ }
+
+ &__copy {
+ font-size: 1em;
+ width: 400px;
+ max-width: 90vw;
+ text-align: center;
+
+ @media screen and (max-width: 575px) {
+ font-size: 0.9em;
+ }
+ }
+ }
+
+ &__button {
+ height: 54px;
+ width: 198px;
+ box-shadow: 0 2px 4px 0 rgba(0,0,0,0.14);
+ color: #FFFFFF;
+ font-size: 20px;
+ font-weight: 500;
+ line-height: 26px;
+ text-align: center;
+ text-transform: uppercase;
+ margin: 35px 0 14px;
+ transition: 200ms ease-in-out;
+ background-color: rgba(247, 134, 28, 0.9);
+ }
+}
diff --git a/ui/app/css/itcss/generic/index.scss b/ui/app/css/itcss/generic/index.scss
index 9b3d7475b..1e226b93e 100644
--- a/ui/app/css/itcss/generic/index.scss
+++ b/ui/app/css/itcss/generic/index.scss
@@ -13,7 +13,6 @@ body {
font-family: Roboto, Arial;
color: #4d4d4d;
font-weight: 300;
- line-height: 1.4em;
background: #f7f7f7;
width: 100%;
height: 100%;
@@ -70,6 +69,10 @@ input.large-input {
height: 36px;
}
+.allcaps {
+ text-transform: uppercase;
+}
+
.page-container {
width: 400px;
background-color: $white;
@@ -77,25 +80,30 @@ input.large-input {
z-index: 25;
display: flex;
flex-flow: column;
+ border-radius: 7px;
&__header {
display: flex;
flex-flow: column;
border-bottom: 1px solid $geyser;
- padding: 1.15rem 0.95rem;
+ padding: 20px;
flex: 0 0 auto;
- background: $alabaster;
position: relative;
}
- &__header-close::after {
- content: '\00D7';
- font-size: 40px;
+ &__header-close {
color: $tundora;
position: absolute;
- top: 21.5px;
- right: 28.5px;
+ top: 20px;
+ right: 20px;
cursor: pointer;
+ overflow: hidden;
+
+ &::after {
+ content: '\00D7';
+ font-size: 40px;
+ line-height: 20px;
+ }
}
&__footer {
@@ -107,14 +115,15 @@ input.large-input {
flex: 0 0 auto;
.btn-clear,
- .btn-cancel {
+ .btn-cancel,
+ .btn-confirm {
font-size: 1rem;
}
}
&__footer-button {
width: 165px;
- height: 60px;
+ height: 55px;
font-size: 1rem;
text-transform: uppercase;
margin-right: 1rem;
@@ -125,12 +134,19 @@ input.large-input {
}
}
+ &__back-button {
+ color: #2f9ae0;
+ font-size: 1rem;
+ cursor: pointer;
+ padding-bottom: 10px;
+ font-weight: 400;
+ }
+
&__title {
color: $black;
- font-family: Roboto;
font-size: 2rem;
font-weight: 500;
- line-height: initial;
+ line-height: 2rem;
}
&__subtitle {
@@ -174,6 +190,19 @@ input.large-input {
}
}
}
+
+ &--full-width {
+ width: initial;
+ }
+
+ &--full-height {
+ height: 100%;
+ }
+
+ &__content {
+ height: 100%;
+ overflow-y: auto;
+ }
}
@media screen and (max-width: 250px) {
@@ -200,5 +229,6 @@ input.large-input {
width: 100%;
overflow-y: auto;
background-color: $white;
+ border-radius: 0;
}
}
diff --git a/ui/app/css/itcss/generic/reset.scss b/ui/app/css/itcss/generic/reset.scss
index e054d533e..a417a0453 100644
--- a/ui/app/css/itcss/generic/reset.scss
+++ b/ui/app/css/itcss/generic/reset.scss
@@ -112,10 +112,6 @@ section {
display: block;
}
-body {
- line-height: 1;
-}
-
ol,
ul {
list-style: none;
diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss
index d96c1ae43..640fd95b8 100644
--- a/ui/app/css/itcss/settings/variables.scss
+++ b/ui/app/css/itcss/settings/variables.scss
@@ -46,6 +46,7 @@ $manatee: #93949d;
$spindle: #c7ddec;
$mid-gray: #5b5d67;
$cape-cod: #38393a;
+$onahau: #d1edff;
$java: #29b6af;
$wild-strawberry: #ff4a8d;
$cornflower-blue: #7057ff;
diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js
index 0e08da8db..370fdd5b7 100644
--- a/ui/app/first-time/init-menu.js
+++ b/ui/app/first-time/init-menu.js
@@ -6,6 +6,7 @@ const h = require('react-hyperscript')
const Mascot = require('../components/mascot')
const actions = require('../actions')
const Tooltip = require('../components/tooltip')
+const t = require('../../i18n')
const getCaretCoordinates = require('textarea-caret')
const environmentType = require('../../../app/scripts/lib/environment-type')
const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums
@@ -59,7 +60,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
color: '#7F8082',
marginBottom: 10,
},
- }, 'MetaMask'),
+ }, t('appName')),
h('div', [
@@ -69,10 +70,10 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
color: '#7F8082',
display: 'inline',
},
- }, 'Encrypt your new DEN'),
+ }, t('encryptNewDen')),
h(Tooltip, {
- title: 'Your DEN is your password-encrypted storage within MetaMask.',
+ title: t('denExplainer'),
}, [
h('i.fa.fa-question-circle.pointer', {
style: {
@@ -92,7 +93,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
h('input.large-input.letter-spacey', {
type: 'password',
id: 'password-box',
- placeholder: 'New Password (min 8 chars)',
+ placeholder: t('newPassword'),
onInput: this.inputChanged.bind(this),
style: {
width: 260,
@@ -104,7 +105,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
h('input.large-input.letter-spacey', {
type: 'password',
id: 'password-box-confirm',
- placeholder: 'Confirm Password',
+ placeholder: t('confirmPassword'),
onKeyPress: this.createVaultOnEnter.bind(this),
onInput: this.inputChanged.bind(this),
style: {
@@ -119,7 +120,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
style: {
margin: 12,
},
- }, 'Create'),
+ }, t('createDen')),
h('.flex-row.flex-center.flex-grow', [
h('p.pointer', {
@@ -129,7 +130,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
color: 'rgb(247, 134, 28)',
textDecoration: 'underline',
},
- }, 'Import Existing DEN'),
+ }, t('importDen')),
]),
h('.flex-row.flex-center.flex-grow', [
@@ -178,12 +179,12 @@ InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () {
var passwordConfirm = passwordConfirmBox.value
if (password.length < 8) {
- this.warning = 'password not long enough'
+ this.warning = t('passwordShort')
this.props.dispatch(actions.displayWarning(this.warning))
return
}
if (password !== passwordConfirm) {
- this.warning = 'passwords don\'t match'
+ this.warning = t('passwordMismatch')
this.props.dispatch(actions.displayWarning(this.warning))
return
}
diff --git a/ui/app/info.js b/ui/app/info.js
deleted file mode 100644
index 49ff9f24a..000000000
--- a/ui/app/info.js
+++ /dev/null
@@ -1,154 +0,0 @@
-const inherits = require('util').inherits
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const connect = require('react-redux').connect
-const actions = require('./actions')
-
-module.exports = connect(mapStateToProps)(InfoScreen)
-
-function mapStateToProps (state) {
- return {}
-}
-
-inherits(InfoScreen, Component)
-function InfoScreen () {
- Component.call(this)
-}
-
-InfoScreen.prototype.render = function () {
- const state = this.props
- const version = global.platform.getVersion()
-
- return (
- h('.flex-column.flex-grow', {
- style: {
- maxWidth: '400px',
- },
- }, [
-
- // subtitle and nav
- h('.section-title.flex-row.flex-center', [
- h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
- onClick: (event) => {
- state.dispatch(actions.goHome())
- },
- }),
- h('h2.page-subtitle', 'Info'),
- ]),
-
- // main view
- h('.flex-column.flex-justify-center.flex-grow.select-none', [
- h('.flex-space-around', {
- style: {
- padding: '20px',
- },
- }, [
- // current version number
-
- h('.info.info-gray', [
- h('div', 'Metamask'),
- h('div', {
- style: {
- marginBottom: '10px',
- },
- }, `Version: ${version}`),
- ]),
-
- h('div', {
- style: {
- marginBottom: '5px',
- }},
- [
- h('div', [
- h('a', {
- href: 'https://metamask.io/privacy.html',
- target: '_blank',
- onClick (event) { this.navigateTo(event.target.href) },
- }, [
- h('div.info', 'Privacy Policy'),
- ]),
- ]),
- h('div', [
- h('a', {
- href: 'https://metamask.io/terms.html',
- target: '_blank',
- onClick (event) { this.navigateTo(event.target.href) },
- }, [
- h('div.info', 'Terms of Use'),
- ]),
- ]),
- h('div', [
- h('a', {
- href: 'https://metamask.io/attributions.html',
- target: '_blank',
- onClick (event) { this.navigateTo(event.target.href) },
- }, [
- h('div.info', 'Attributions'),
- ]),
- ]),
- ]
- ),
-
- h('hr', {
- style: {
- margin: '10px 0 ',
- width: '7em',
- },
- }),
-
- h('div', {
- style: {
- paddingLeft: '30px',
- }},
- [
- h('div.fa.fa-support', [
- h('a.info', {
- href: 'https://metamask.helpscoutdocs.com/',
- target: '_blank',
- }, 'Visit our Knowledge Base'),
- ]),
-
- h('div', [
- h('a', {
- href: 'https://metamask.io/',
- target: '_blank',
- }, [
- h('img.icon-size', {
- src: 'images/icon-128.png',
- style: {
- // IE6-9
- filter: 'grayscale(100%)',
- // Microsoft Edge and Firefox 35+
- WebkitFilter: 'grayscale(100%)',
- },
- }),
- h('div.info', 'Visit our web site'),
- ]),
- ]),
-
- h('div', [
- h('.fa.fa-twitter', [
- h('a.info', {
- href: 'https://twitter.com/metamask_io',
- target: '_blank',
- }, 'Follow us on Twitter'),
- ]),
- ]),
-
- h('div.fa.fa-envelope', [
- h('a.info', {
- target: '_blank',
- href: 'mailto:support@metamask.io?subject=MetaMask Support',
- }, 'Email us!'),
- ]),
- ]),
- ]),
- ]),
- ])
- )
-}
-
-InfoScreen.prototype.navigateTo = function (url) {
- global.platform.openWindow({ url })
-}
-
diff --git a/ui/app/keychains/hd/recover-seed/confirmation.js b/ui/app/keychains/hd/recover-seed/confirmation.js
index 4335186a5..bc5339549 100644
--- a/ui/app/keychains/hd/recover-seed/confirmation.js
+++ b/ui/app/keychains/hd/recover-seed/confirmation.js
@@ -4,6 +4,7 @@ const Component = require('react').Component
const connect = require('react-redux').connect
const h = require('react-hyperscript')
const actions = require('../../../actions')
+const t = require('../../../../i18n')
module.exports = connect(mapStateToProps)(RevealSeedConfirmation)
@@ -49,13 +50,13 @@ RevealSeedConfirmation.prototype.render = function () {
},
}, [
- h('h4', 'Do not recover your seed words in a public place! These words can be used to steal all your accounts.'),
+ h('h4', t('revealSeedWordsWarning')),
// confirmation
h('input.large-input.letter-spacey', {
type: 'password',
id: 'password-box',
- placeholder: 'Enter your password to confirm',
+ placeholder: t('enterPasswordConfirm'),
onKeyPress: this.checkConfirmation.bind(this),
style: {
width: 260,
@@ -91,7 +92,7 @@ RevealSeedConfirmation.prototype.render = function () {
),
props.inProgress && (
- h('span.in-progress-notification', 'Generating Seed...')
+ h('span.in-progress-notification', t('generatingSeed'))
),
]),
])
diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js
index d1761f17d..5e4e004cf 100644
--- a/ui/app/keychains/hd/restore-vault.js
+++ b/ui/app/keychains/hd/restore-vault.js
@@ -2,6 +2,7 @@ const inherits = require('util').inherits
const PersistentForm = require('../../../lib/persistent-form')
const connect = require('react-redux').connect
const h = require('react-hyperscript')
+const t = require('../../../i18n')
const actions = require('../../actions')
module.exports = connect(mapStateToProps)(RestoreVaultScreen)
@@ -36,23 +37,23 @@ RestoreVaultScreen.prototype.render = function () {
padding: 6,
},
}, [
- 'Restore Vault',
+ t('restoreVault'),
]),
// wallet seed entry
- h('h3', 'Wallet Seed'),
+ h('h3', t('walletSeed')),
h('textarea.twelve-word-phrase.letter-spacey', {
dataset: {
persistentFormId: 'wallet-seed',
},
- placeholder: 'Enter your secret twelve word phrase here to restore your vault.',
+ placeholder: t('secretPhrase'),
}),
// password
h('input.large-input.letter-spacey', {
type: 'password',
id: 'password-box',
- placeholder: 'New Password (min 8 chars)',
+ placeholder: t('newPassword8Chars'),
dataset: {
persistentFormId: 'password',
},
@@ -66,7 +67,7 @@ RestoreVaultScreen.prototype.render = function () {
h('input.large-input.letter-spacey', {
type: 'password',
id: 'password-box-confirm',
- placeholder: 'Confirm Password',
+ placeholder: t('confirmPassword'),
onKeyPress: this.createOnEnter.bind(this),
dataset: {
persistentFormId: 'password-confirmation',
@@ -93,16 +94,20 @@ RestoreVaultScreen.prototype.render = function () {
// cancel
h('button.primary', {
onClick: this.showInitializeMenu.bind(this),
- }, 'CANCEL'),
+ style: {
+ textTransform: 'uppercase',
+ },
+ }, t('cancel')),
// submit
h('button.primary', {
onClick: this.createNewVaultAndRestore.bind(this),
- }, 'OK'),
-
+ style: {
+ textTransform: 'uppercase',
+ },
+ }, t('ok')),
]),
])
-
)
}
@@ -131,21 +136,34 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () {
var passwordConfirmBox = document.getElementById('password-box-confirm')
var passwordConfirm = passwordConfirmBox.value
if (password.length < 8) {
- this.warning = 'Password not long enough'
+ this.warning = t('passwordNotLongEnough')
this.props.dispatch(actions.displayWarning(this.warning))
return
}
if (password !== passwordConfirm) {
- this.warning = 'Passwords don\'t match'
+ this.warning = t('passwordsDontMatch')
this.props.dispatch(actions.displayWarning(this.warning))
return
}
// check seed
var seedBox = document.querySelector('textarea.twelve-word-phrase')
var seed = seedBox.value.trim()
+
+ // true if the string has more than a space between words.
+ if (seed.split(' ').length > 1) {
+ this.warning = t('spaceBetween')
+ this.props.dispatch(actions.displayWarning(this.warning))
+ return
+ }
+ // true if seed contains a character that is not between a-z or a space
+ if (!seed.match(/^[a-z ]+$/)) {
+ this.warning = t('loweCaseWords')
+ this.props.dispatch(actions.displayWarning(this.warning))
+ return
+ }
if (seed.split(' ').length !== 12) {
- this.warning = 'seed phrases are 12 words long'
+ this.warning = t('seedPhraseReq')
this.props.dispatch(actions.displayWarning(this.warning))
return
}
diff --git a/ui/app/main-container.js b/ui/app/main-container.js
index 292abcc3d..eed4bd164 100644
--- a/ui/app/main-container.js
+++ b/ui/app/main-container.js
@@ -32,19 +32,7 @@ MainContainer.prototype.render = function () {
return h(Settings, {key: 'config'})
default:
log.debug('rendering locked screen')
- contents = {
- component: UnlockScreen,
- style: {
- boxShadow: 'none',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- background: '#F7F7F7',
- // must force 100%, because lock screen is full-width
- width: '100%',
- },
- key: 'locked',
- }
+ return h('.unlock-screen-container', {}, h(UnlockScreen, { key: 'locked' }))
}
}
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index 029d830ec..e6e02d057 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -38,12 +38,14 @@ function reduceMetamask (state, action) {
errors: {},
maxModeOn: false,
editingTransactionId: null,
+ forceGasMin: null,
},
coinOptions: {},
useBlockie: false,
featureFlags: {},
networkEndpointType: OLD_UI_NETWORK_TYPE,
isRevealingSeedWords: false,
+ welcomeScreenSeen: false,
}, state.metamask)
switch (action.type) {
@@ -296,6 +298,7 @@ function reduceMetamask (state, action) {
memo: '',
errors: {},
editingTransactionId: null,
+ forceGasMin: null,
},
})
@@ -347,6 +350,11 @@ function reduceMetamask (state, action) {
networkEndpointType: action.value,
})
+ case actions.CLOSE_WELCOME_SCREEN:
+ return extend(metamaskState, {
+ welcomeScreenSeen: true,
+ })
+
default:
return metamaskState
diff --git a/ui/app/selectors.js b/ui/app/selectors.js
index 5d2635775..d37c26f7e 100644
--- a/ui/app/selectors.js
+++ b/ui/app/selectors.js
@@ -18,6 +18,7 @@ const selectors = {
getCurrentAccountWithSendEtherInfo,
getGasPrice,
getGasLimit,
+ getForceGasMin,
getAddressBook,
getSendFrom,
getCurrentCurrency,
@@ -130,6 +131,10 @@ function getGasLimit (state) {
return state.metamask.send.gasLimit
}
+function getForceGasMin (state) {
+ return state.metamask.send.forceGasMin
+}
+
function getSendFrom (state) {
return state.metamask.send.from
}
diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js
index fc1df1f51..31118378d 100644
--- a/ui/app/send-v2.js
+++ b/ui/app/send-v2.js
@@ -1,6 +1,7 @@
const { inherits } = require('util')
const PersistentForm = require('../lib/persistent-form')
const h = require('react-hyperscript')
+const t = require('../i18n')
const ethAbi = require('ethereumjs-abi')
const ethUtil = require('ethereumjs-util')
@@ -42,6 +43,7 @@ function SendTransactionScreen () {
to: null,
amount: null,
},
+ gasLoadingError: false,
}
this.handleToChange = this.handleToChange.bind(this)
@@ -128,6 +130,10 @@ SendTransactionScreen.prototype.updateGas = function () {
.then(([gasPrice, gas]) => {
const newGasTotal = this.getGasTotal(gas, gasPrice)
updateGasTotal(newGasTotal)
+ this.setState({ gasLoadingError: false })
+ })
+ .catch(err => {
+ this.setState({ gasLoadingError: true })
})
} else {
const newGasTotal = this.getGasTotal(gasLimit, gasPrice)
@@ -180,13 +186,12 @@ SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
SendTransactionScreen.prototype.renderHeader = function () {
const { selectedToken, clearSend, goHome } = this.props
- const tokenText = selectedToken ? 'tokens' : 'ETH'
return h('div.page-container__header', [
- h('div.page-container__title', selectedToken ? 'Send Tokens' : 'Send ETH'),
+ h('div.page-container__title', selectedToken ? t('sendTokens') : t('sendETH')),
- h('div.page-container__subtitle', `Only send ${tokenText} to an Ethereum address.`),
+ h('div.page-container__subtitle', t('onlySendToEtherAddress')),
h('div.page-container__header-close', {
onClick: () => {
@@ -257,11 +262,11 @@ SendTransactionScreen.prototype.handleToChange = function (to) {
let toError = null
if (!to) {
- toError = 'Required'
+ toError = t('required')
} else if (!isValidAddress(to)) {
- toError = 'Recipient address is invalid'
+ toError = t('invalidAddressRecipient')
} else if (to === from) {
- toError = 'From and To address cannot be the same'
+ toError = t('fromToSame')
}
updateSendTo(to)
@@ -277,9 +282,9 @@ SendTransactionScreen.prototype.renderToRow = function () {
h('div.send-v2__form-label', [
- 'To:',
+ t('to'),
- this.renderErrorMessage('to'),
+ this.renderErrorMessage(t('to')),
]),
@@ -377,11 +382,11 @@ SendTransactionScreen.prototype.validateAmount = function (value) {
)
if (conversionRate && !sufficientBalance) {
- amountError = 'Insufficient funds.'
+ amountError = t('insufficientFunds')
} else if (verifyTokenBalance && !sufficientTokens) {
- amountError = 'Insufficient tokens.'
+ amountError = t('insufficientTokens')
} else if (amountLessThanZero) {
- amountError = 'Can not send negative amounts of ETH.'
+ amountError = t('negativeETH')
}
updateSendErrors({ amount: amountError })
@@ -411,7 +416,7 @@ SendTransactionScreen.prototype.renderAmountRow = function () {
setMaxModeTo(true)
this.setAmountToMax()
},
- }, [ !maxModeOn ? 'Max' : '' ]),
+ }, [ !maxModeOn ? t('max') : '' ]),
]),
h('div.send-v2__form-field', [
@@ -436,10 +441,11 @@ SendTransactionScreen.prototype.renderGasRow = function () {
showCustomizeGasModal,
gasTotal,
} = this.props
+ const { gasLoadingError } = this.state
return h('div.send-v2__form-row', [
- h('div.send-v2__form-label', 'Gas fee:'),
+ h('div.send-v2__form-label', h('gasFee')),
h('div.send-v2__form-field', [
@@ -448,6 +454,7 @@ SendTransactionScreen.prototype.renderGasRow = function () {
conversionRate,
convertedCurrency,
onClick: showCustomizeGasModal,
+ gasLoadingError,
}),
]),
@@ -507,11 +514,11 @@ SendTransactionScreen.prototype.renderFooter = function () {
clearSend()
goHome()
},
- }, 'Cancel'),
+ }, t('cancel')),
h('button.btn-clear.page-container__footer-button', {
disabled: !noErrors || !gasTotal || missingTokenBalance,
onClick: event => this.onSubmit(event),
- }, 'Next'),
+ }, t('next')),
])
}
@@ -571,9 +578,11 @@ SendTransactionScreen.prototype.getEditedTx = function () {
data,
})
} else {
+ const data = unapprovedTxs[editingTransactionId].txParams.data
Object.assign(editingTx.txParams, {
value: ethUtil.addHexPrefix(amount),
to: ethUtil.addHexPrefix(to),
+ data,
})
}
diff --git a/ui/app/send.js b/ui/app/send.js
deleted file mode 100644
index 517b7690d..000000000
--- a/ui/app/send.js
+++ /dev/null
@@ -1,547 +0,0 @@
-// const { inherits } = require('util')
-// const PersistentForm = require('../lib/persistent-form')
-// const h = require('react-hyperscript')
-// const connect = require('react-redux').connect
-// const Identicon = require('./components/identicon')
-// const EnsInput = require('./components/ens-input')
-// const GasTooltip = require('./components/send/gas-tooltip')
-// const CurrencyToggle = require('./components/send/currency-toggle')
-// const GasFeeDisplay = require('./components/send/gas-fee-display')
-// const { getSelectedIdentity } = require('./selectors')
-
-// const {
-// showAccountsPage,
-// backToAccountDetail,
-// displayWarning,
-// hideWarning,
-// addToAddressBook,
-// signTx,
-// estimateGas,
-// getGasPrice,
-// } = require('./actions')
-// const { stripHexPrefix, addHexPrefix } = require('ethereumjs-util')
-// const { isHex, numericBalance, isValidAddress, allNull } = require('./util')
-// const { conversionUtil, conversionGreaterThan } = require('./conversion-util')
-
-// module.exports = connect(mapStateToProps)(SendTransactionScreen)
-
-// function mapStateToProps (state) {
-// const {
-// selectedAddress: address,
-// accounts,
-// identities,
-// network,
-// addressBook,
-// conversionRate,
-// currentBlockGasLimit: blockGasLimit,
-// } = state.metamask
-// const { warning } = state.appState
-// const selectedIdentity = getSelectedIdentity(state)
-// const account = accounts[address]
-
-// return {
-// address,
-// accounts,
-// identities,
-// network,
-// addressBook,
-// conversionRate,
-// blockGasLimit,
-// warning,
-// selectedIdentity,
-// error: warning && warning.split('.')[0],
-// account,
-// identity: identities[address],
-// balance: account ? account.balance : null,
-// }
-// }
-
-// inherits(SendTransactionScreen, PersistentForm)
-// function SendTransactionScreen () {
-// PersistentForm.call(this)
-
-// // [WIP] These are the bare minimum of tx props needed to sign a transaction
-// // We will need a few more for contract-related interactions
-// this.state = {
-// newTx: {
-// from: '',
-// to: '',
-// amountToSend: '0x0',
-// gasPrice: null,
-// gas: null,
-// amount: '0x0',
-// txData: null,
-// memo: '',
-// },
-// activeCurrency: 'USD',
-// tooltipIsOpen: false,
-// errors: {},
-// isValid: false,
-// }
-
-// this.back = this.back.bind(this)
-// this.closeTooltip = this.closeTooltip.bind(this)
-// this.onSubmit = this.onSubmit.bind(this)
-// this.setActiveCurrency = this.setActiveCurrency.bind(this)
-// this.toggleTooltip = this.toggleTooltip.bind(this)
-// this.validate = this.validate.bind(this)
-// this.getAmountToSend = this.getAmountToSend.bind(this)
-// this.setErrorsFor = this.setErrorsFor.bind(this)
-// this.clearErrorsFor = this.clearErrorsFor.bind(this)
-
-// this.renderFromInput = this.renderFromInput.bind(this)
-// this.renderToInput = this.renderToInput.bind(this)
-// this.renderAmountInput = this.renderAmountInput.bind(this)
-// this.renderGasInput = this.renderGasInput.bind(this)
-// this.renderMemoInput = this.renderMemoInput.bind(this)
-// this.renderErrorMessage = this.renderErrorMessage.bind(this)
-// }
-
-// SendTransactionScreen.prototype.componentWillMount = function () {
-// const { newTx } = this.state
-// const { address } = this.props
-
-// Promise.all([
-// this.props.dispatch(getGasPrice()),
-// this.props.dispatch(estimateGas({
-// from: address,
-// gas: '746a528800',
-// })),
-// ])
-// .then(([blockGasPrice, estimatedGas]) => {
-// console.log({ blockGasPrice, estimatedGas})
-// this.setState({
-// newTx: {
-// ...newTx,
-// gasPrice: blockGasPrice,
-// gas: estimatedGas,
-// },
-// })
-// })
-// }
-
-// SendTransactionScreen.prototype.renderErrorMessage = function(errorType, warning) {
-// const { errors } = this.state
-// const errorMessage = errors[errorType];
-
-// return errorMessage || warning
-// ? h('div.send-screen-input-wrapper__error-message', [ errorMessage || warning ])
-// : null
-// }
-
-// SendTransactionScreen.prototype.renderFromInput = function (from, identities) {
-// return h('div.send-screen-input-wrapper', [
-
-// h('div', 'From:'),
-
-// h('input.large-input.send-screen-input', {
-// list: 'accounts',
-// placeholder: 'Account',
-// value: from,
-// onChange: (event) => {
-// this.setState({
-// newTx: {
-// ...this.state.newTx,
-// from: event.target.value,
-// },
-// })
-// },
-// onBlur: () => this.setErrorsFor('from'),
-// onFocus: event => {
-// this.clearErrorsFor('from')
-// this.state.newTx.from && event.target.select()
-// },
-// }),
-
-// h('datalist#accounts', [
-// Object.entries(identities).map(([key, { address, name }]) => {
-// return h('option', {
-// value: address,
-// label: name,
-// key: address,
-// })
-// }),
-// ]),
-
-// this.renderErrorMessage('from'),
-
-// ])
-// }
-
-// SendTransactionScreen.prototype.renderToInput = function (to, identities, addressBook) {
-// return h('div.send-screen-input-wrapper', [
-
-// h('div', 'To:'),
-
-// h('input.large-input.send-screen-input', {
-// name: 'address',
-// list: 'addresses',
-// placeholder: 'Address',
-// value: to,
-// onChange: (event) => {
-// this.setState({
-// newTx: {
-// ...this.state.newTx,
-// to: event.target.value,
-// },
-// })
-// },
-// onBlur: () => {
-// this.setErrorsFor('to')
-// },
-// onFocus: event => {
-// this.clearErrorsFor('to')
-// this.state.newTx.to && event.target.select()
-// },
-// }),
-
-// h('datalist#addresses', [
-// // Corresponds to the addresses owned.
-// ...Object.entries(identities).map(([key, { address, name }]) => {
-// return h('option', {
-// value: address,
-// label: name,
-// key: address,
-// })
-// }),
-// // Corresponds to previously sent-to addresses.
-// ...addressBook.map(({ address, name }) => {
-// return h('option', {
-// value: address,
-// label: name,
-// key: address,
-// })
-// }),
-// ]),
-
-// this.renderErrorMessage('to'),
-
-// ])
-// }
-
-// SendTransactionScreen.prototype.renderAmountInput = function (activeCurrency) {
-// return h('div.send-screen-input-wrapper', [
-
-// h('div.send-screen-amount-labels', [
-// h('span', 'Amount'),
-// h(CurrencyToggle, {
-// activeCurrency,
-// onClick: (newCurrency) => this.setActiveCurrency(newCurrency),
-// }), // holding on icon from design
-// ]),
-
-// h('input.large-input.send-screen-input', {
-// placeholder: `0 ${activeCurrency}`,
-// type: 'number',
-// onChange: (event) => {
-// const amountToSend = event.target.value
-// ? this.getAmountToSend(event.target.value)
-// : '0x0'
-
-// this.setState({
-// newTx: Object.assign(
-// this.state.newTx,
-// {
-// amount: event.target.value,
-// amountToSend: amountToSend,
-// }
-// ),
-// })
-// },
-// onBlur: () => {
-// this.setErrorsFor('amount')
-// },
-// onFocus: () => this.clearErrorsFor('amount'),
-// }),
-
-// this.renderErrorMessage('amount'),
-
-// ])
-// }
-
-// SendTransactionScreen.prototype.renderGasInput = function (gasPrice, gas, activeCurrency, conversionRate, blockGasLimit) {
-// return h('div.send-screen-input-wrapper', [
-// this.state.tooltipIsOpen && h(GasTooltip, {
-// className: 'send-tooltip',
-// gasPrice,
-// gasLimit: gas,
-// onClose: this.closeTooltip,
-// onFeeChange: ({gasLimit, gasPrice}) => {
-// this.setState({
-// newTx: {
-// ...this.state.newTx,
-// gas: gasLimit,
-// gasPrice,
-// },
-// })
-// },
-// }),
-
-// h('div.send-screen-gas-labels', [
-// h('span', [
-// h('i.fa.fa-bolt'),
-// 'Gas fee:',
-// ]),
-// h('span', 'What\'s this?'),
-// ]),
-
-// // TODO: handle loading time when switching to USD
-// h('div.large-input.send-screen-gas-input', {}, [
-// h(GasFeeDisplay, {
-// activeCurrency,
-// conversionRate,
-// gas,
-// gasPrice,
-// blockGasLimit,
-// }),
-// h('div.send-screen-gas-input-customize', {
-// onClick: this.toggleTooltip,
-// }, [
-// 'Customize',
-// ]),
-// ]),
-
-// ])
-// }
-
-// SendTransactionScreen.prototype.renderMemoInput = function () {
-// return h('div.send-screen-input-wrapper', [
-// h('div', 'Transaction memo (optional)'),
-// h('input.large-input.send-screen-input', {
-// onChange: () => {
-// this.setState({
-// newTx: Object.assign(
-// this.state.newTx,
-// {
-// memo: event.target.value,
-// }
-// ),
-// })
-// },
-// }),
-// ])
-// }
-
-// SendTransactionScreen.prototype.render = function () {
-// this.persistentFormParentId = 'send-tx-form'
-
-// const props = this.props
-// const {
-// warning,
-// identities,
-// addressBook,
-// conversionRate,
-// } = props
-
-// const {
-// blockGasLimit,
-// newTx,
-// activeCurrency,
-// isValid,
-// } = this.state
-// const { gas, gasPrice } = newTx
-
-// return (
-
-// h('div.send-screen-wrapper', [
-// // Main Send token Card
-// h('div.send-screen-card', [
-
-// h('img.send-eth-icon', { src: '../images/eth_logo.svg' }),
-
-// h('div.send-screen__title', 'Send'),
-
-// h('div.send-screen__subtitle', 'Send Ethereum to anyone with an Ethereum account'),
-
-// this.renderFromInput(this.state.newTx.from, identities),
-
-// this.renderToInput(this.state.newTx.to, identities, addressBook),
-
-// this.renderAmountInput(activeCurrency),
-
-// this.renderGasInput(
-// gasPrice || '0x0',
-// gas || '0x0',
-// activeCurrency,
-// conversionRate,
-// blockGasLimit
-// ),
-
-// this.renderMemoInput(),
-
-// this.renderErrorMessage(null, warning),
-
-// ]),
-
-// // Buttons underneath card
-// h('section.flex-column.flex-center', [
-// h('button.btn-secondary.send-screen__send-button', {
-// className: !isValid && 'send-screen__send-button__disabled',
-// onClick: (event) => isValid && this.onSubmit(event),
-// }, 'Next'),
-// h('button.btn-tertiary.send-screen__cancel-button', {
-// onClick: this.back,
-// }, 'Cancel'),
-// ]),
-// ])
-
-// )
-// }
-
-// SendTransactionScreen.prototype.toggleTooltip = function () {
-// this.setState({ tooltipIsOpen: !this.state.tooltipIsOpen })
-// }
-
-// SendTransactionScreen.prototype.closeTooltip = function () {
-// this.setState({ tooltipIsOpen: false })
-// }
-
-// SendTransactionScreen.prototype.setActiveCurrency = function (newCurrency) {
-// this.setState({ activeCurrency: newCurrency })
-// }
-
-// SendTransactionScreen.prototype.back = function () {
-// var address = this.props.address
-// this.props.dispatch(backToAccountDetail(address))
-// }
-
-// SendTransactionScreen.prototype.validate = function (balance, amountToSend, { to, from }) {
-// const sufficientBalance = conversionGreaterThan(
-// {
-// value: balance,
-// fromNumericBase: 'hex',
-// },
-// {
-// value: amountToSend,
-// fromNumericBase: 'hex',
-// },
-// )
-
-// const amountLessThanZero = conversionGreaterThan(
-// {
-// value: 0,
-// fromNumericBase: 'dec',
-// },
-// {
-// value: amountToSend,
-// fromNumericBase: 'hex',
-// },
-// )
-
-// const errors = {}
-
-// if (!sufficientBalance) {
-// errors.amount = 'Insufficient funds.'
-// }
-
-// if (amountLessThanZero) {
-// errors.amount = 'Can not send negative amounts of ETH.'
-// }
-
-// if (!from) {
-// errors.from = 'Required'
-// }
-
-// if (from && !isValidAddress(from)) {
-// errors.from = 'Sender address is invalid.'
-// }
-
-// if (!to) {
-// errors.to = 'Required'
-// }
-
-// if (to && !isValidAddress(to)) {
-// errors.to = 'Recipient address is invalid.'
-// }
-
-// // if (txData && !isHex(stripHexPrefix(txData))) {
-// // message = 'Transaction data must be hex string.'
-// // return this.props.dispatch(displayWarning(message))
-// // }
-
-// return {
-// isValid: allNull(errors),
-// errors,
-// }
-// }
-
-// SendTransactionScreen.prototype.getAmountToSend = function (amount) {
-// const { activeCurrency } = this.state
-// const { conversionRate } = this.props
-
-// return conversionUtil(amount, {
-// fromNumericBase: 'dec',
-// toNumericBase: 'hex',
-// fromCurrency: activeCurrency,
-// toCurrency: 'ETH',
-// toDenomination: 'WEI',
-// conversionRate,
-// invertConversionRate: activeCurrency !== 'ETH',
-// })
-// }
-
-// SendTransactionScreen.prototype.setErrorsFor = function (field) {
-// const { balance } = this.props
-// const { newTx, errors: previousErrors } = this.state
-// const { amountToSend } = newTx
-
-// const {
-// isValid,
-// errors: newErrors
-// } = this.validate(balance, amountToSend, newTx)
-
-// const nextErrors = Object.assign({}, previousErrors, {
-// [field]: newErrors[field] || null
-// })
-
-// if (!isValid) {
-// this.setState({
-// errors: nextErrors,
-// isValid,
-// })
-// }
-// }
-
-// SendTransactionScreen.prototype.clearErrorsFor = function (field) {
-// const { errors: previousErrors } = this.state
-// const nextErrors = Object.assign({}, previousErrors, {
-// [field]: null
-// })
-
-// this.setState({
-// errors: nextErrors,
-// isValid: allNull(nextErrors),
-// })
-// }
-
-// SendTransactionScreen.prototype.onSubmit = function (event) {
-// event.preventDefault()
-// const { warning, balance } = this.props
-// const state = this.state || {}
-
-// const recipient = state.newTx.to
-// const sender = state.newTx.from
-// const nickname = state.nickname || ' '
-
-// // TODO: convert this to hex when created and include it in send
-// const txData = state.newTx.memo
-
-// this.props.dispatch(hideWarning())
-
-// this.props.dispatch(addToAddressBook(recipient, nickname))
-
-// var txParams = {
-// from: this.state.newTx.from,
-// to: this.state.newTx.to,
-
-// value: this.state.newTx.amountToSend,
-
-// gas: this.state.newTx.gas,
-// gasPrice: this.state.newTx.gasPrice,
-// }
-
-// if (recipient) txParams.to = addHexPrefix(recipient)
-// if (txData) txParams.data = txData
-
-// this.props.dispatch(signTx(txParams))
-// }
diff --git a/ui/app/settings.js b/ui/app/settings.js
index 466f739d5..105cbb40b 100644
--- a/ui/app/settings.js
+++ b/ui/app/settings.js
@@ -10,6 +10,7 @@ const TabBar = require('./components/tab-bar')
const SimpleDropdown = require('./components/dropdowns/simple-dropdown')
const ToggleButton = require('react-toggle-button')
const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
+const t = require('../i18n')
const getInfuraCurrencyOptions = () => {
const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => {
@@ -44,8 +45,8 @@ class Settings extends Component {
return h('div.settings__tabs', [
h(TabBar, {
tabs: [
- { content: 'Settings', key: 'settings' },
- { content: 'Info', key: 'info' },
+ { content: t('settings'), key: 'settings' },
+ { content: t('info'), key: 'info' },
],
defaultTab: activeTab,
tabSelected: key => this.setState({ activeTab: key }),
@@ -58,7 +59,7 @@ class Settings extends Component {
return h('div.settings__content-row', [
h('div.settings__content-item', [
- h('span', 'Use Blockies Identicon'),
+ h('span', t('blockiesIdenticon')),
]),
h('div.settings__content-item', [
h('div.settings__content-item-col', [
@@ -78,13 +79,13 @@ class Settings extends Component {
return h('div.settings__content-row', [
h('div.settings__content-item', [
- h('span', 'Current Conversion'),
+ h('span', t('currentConversion')),
h('span.settings__content-description', `Updated ${Date(conversionDate)}`),
]),
h('div.settings__content-item', [
h('div.settings__content-item-col', [
h(SimpleDropdown, {
- placeholder: 'Select Currency',
+ placeholder: t('selectCurrency'),
options: getInfuraCurrencyOptions(),
selectedOption: currentCurrency,
onSelect: newCurrency => setCurrentCurrency(newCurrency),
@@ -101,31 +102,31 @@ class Settings extends Component {
switch (provider.type) {
case 'mainnet':
- title = 'Current Network'
- value = 'Main Ethereum Network'
+ title = t('currentNetwork')
+ value = t('mainnet')
color = '#038789'
break
case 'ropsten':
- title = 'Current Network'
- value = 'Ropsten Test Network'
+ title = t('currentNetwork')
+ value = t('ropsten')
color = '#e91550'
break
case 'kovan':
- title = 'Current Network'
- value = 'Kovan Test Network'
+ title = t('currentNetwork')
+ value = t('kovan')
color = '#690496'
break
case 'rinkeby':
- title = 'Current Network'
- value = 'Rinkeby Test Network'
+ title = t('currentNetwork')
+ value = t('rinkeby')
color = '#ebb33f'
break
default:
- title = 'Current RPC'
+ title = t('currentRpc')
value = provider.rpcTarget
}
@@ -146,12 +147,12 @@ class Settings extends Component {
return (
h('div.settings__content-row', [
h('div.settings__content-item', [
- h('span', 'New RPC URL'),
+ h('span', t('newRPC')),
]),
h('div.settings__content-item', [
h('div.settings__content-item-col', [
h('input.settings__input', {
- placeholder: 'New RPC URL',
+ placeholder: t('newRPC'),
onChange: event => this.setState({ newRpc: event.target.value }),
onKeyPress: event => {
if (event.key === 'Enter') {
@@ -164,7 +165,7 @@ class Settings extends Component {
event.preventDefault()
this.validateRpc(this.state.newRpc)
},
- }, 'Save'),
+ }, t('save')),
]),
]),
])
@@ -180,9 +181,9 @@ class Settings extends Component {
const appendedRpc = `http://${newRpc}`
if (validUrl.isWebUri(appendedRpc)) {
- displayWarning('URIs require the appropriate HTTP/HTTPS prefix.')
+ displayWarning(t('uriErrorMsg'))
} else {
- displayWarning('Invalid RPC URI')
+ displayWarning(t('invalidRPC'))
}
}
}
@@ -191,10 +192,10 @@ class Settings extends Component {
return (
h('div.settings__content-row', [
h('div.settings__content-item', [
- h('div', 'State Logs'),
+ h('div', t('stateLogs')),
h(
'div.settings__content-description',
- 'State logs contain your public account addresses and sent transactions.'
+ t('stateLogsDescription')
),
]),
h('div.settings__content-item', [
@@ -203,13 +204,13 @@ class Settings extends Component {
onClick (event) {
window.logStateString((err, result) => {
if (err) {
- this.state.dispatch(actions.displayWarning('Error in retrieving state logs.'))
+ this.state.dispatch(actions.displayWarning(t('stateLogError')))
} else {
exportAsFile('MetaMask State Logs.json', result)
}
})
},
- }, 'Download State Logs'),
+ }, t('downloadStateLogs')),
]),
]),
])
@@ -221,7 +222,7 @@ class Settings extends Component {
return (
h('div.settings__content-row', [
- h('div.settings__content-item', 'Reveal Seed Words'),
+ h('div.settings__content-item', t('revealSeedWords')),
h('div.settings__content-item', [
h('div.settings__content-item-col', [
h('button.settings__clear-button.settings__clear-button--red', {
@@ -229,7 +230,7 @@ class Settings extends Component {
event.preventDefault()
revealSeedConfirmation()
},
- }, 'Reveal Seed Words'),
+ }, t('revealSeedWords')),
]),
]),
])
@@ -241,7 +242,7 @@ class Settings extends Component {
return (
h('div.settings__content-row', [
- h('div.settings__content-item', 'Use old UI'),
+ h('div.settings__content-item', t('useOldUI')),
h('div.settings__content-item', [
h('div.settings__content-item-col', [
h('button.settings__clear-button.settings__clear-button--orange', {
@@ -249,7 +250,7 @@ class Settings extends Component {
event.preventDefault()
setFeatureFlagToBeta()
},
- }, 'Use old UI'),
+ }, t('useOldUI')),
]),
]),
])
@@ -260,7 +261,7 @@ class Settings extends Component {
const { showResetAccountConfirmationModal } = this.props
return h('div.settings__content-row', [
- h('div.settings__content-item', 'Reset Account'),
+ h('div.settings__content-item', t('resetAccount')),
h('div.settings__content-item', [
h('div.settings__content-item-col', [
h('button.settings__clear-button.settings__clear-button--orange', {
@@ -268,7 +269,7 @@ class Settings extends Component {
event.preventDefault()
showResetAccountConfirmationModal()
},
- }, 'Reset Account'),
+ }, t('resetAccount')),
]),
]),
])
@@ -303,13 +304,13 @@ class Settings extends Component {
renderInfoLinks () {
return (
h('div.settings__content-item.settings__content-item--without-height', [
- h('div.settings__info-link-header', 'Links'),
+ h('div.settings__info-link-header', t('links')),
h('div.settings__info-link-item', [
h('a', {
href: 'https://metamask.io/privacy.html',
target: '_blank',
}, [
- h('span.settings__info-link', 'Privacy Policy'),
+ h('span.settings__info-link', t('privacyMsg')),
]),
]),
h('div.settings__info-link-item', [
@@ -317,7 +318,7 @@ class Settings extends Component {
href: 'https://metamask.io/terms.html',
target: '_blank',
}, [
- h('span.settings__info-link', 'Terms of Use'),
+ h('span.settings__info-link', t('terms')),
]),
]),
h('div.settings__info-link-item', [
@@ -325,7 +326,7 @@ class Settings extends Component {
href: 'https://metamask.io/attributions.html',
target: '_blank',
}, [
- h('span.settings__info-link', 'Attributions'),
+ h('span.settings__info-link', t('attributions')),
]),
]),
h('hr.settings__info-separator'),
@@ -334,7 +335,7 @@ class Settings extends Component {
href: 'https://support.metamask.io',
target: '_blank',
}, [
- h('span.settings__info-link', 'Visit our Support Center'),
+ h('span.settings__info-link', t('supportCenter')),
]),
]),
h('div.settings__info-link-item', [
@@ -342,7 +343,7 @@ class Settings extends Component {
href: 'https://metamask.io/',
target: '_blank',
}, [
- h('span.settings__info-link', 'Visit our web site'),
+ h('span.settings__info-link', t('visitWebSite')),
]),
]),
h('div.settings__info-link-item', [
@@ -350,7 +351,7 @@ class Settings extends Component {
target: '_blank',
href: 'mailto:help@metamask.io?subject=Feedback',
}, [
- h('span.settings__info-link', 'Email us!'),
+ h('span.settings__info-link', t('emailUs')),
]),
]),
])
@@ -372,7 +373,7 @@ class Settings extends Component {
h('div.settings__info-item', [
h(
'div.settings__info-about',
- 'MetaMask is designed and built in California.'
+ t('builtInCalifornia')
),
]),
]),
@@ -445,3 +446,4 @@ const mapDispatchToProps = dispatch => {
}
module.exports = connect(mapStateToProps, mapDispatchToProps)(Settings)
+
diff --git a/ui/app/template.js b/ui/app/template.js
deleted file mode 100644
index d15b30fd2..000000000
--- a/ui/app/template.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const inherits = require('util').inherits
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const connect = require('react-redux').connect
-
-module.exports = connect(mapStateToProps)(COMPONENTNAME)
-
-function mapStateToProps (state) {
- return {}
-}
-
-inherits(COMPONENTNAME, Component)
-function COMPONENTNAME () {
- Component.call(this)
-}
-
-COMPONENTNAME.prototype.render = function () {
- const props = this.props
-
- return (
- h('div', {
- style: {
- background: 'blue',
- },
- }, [
- `Hello, ${props.sender}`,
- ])
- )
-}
-
diff --git a/ui/app/token-tracker.js b/ui/app/token-tracker.js
deleted file mode 100644
index e69de29bb..000000000
--- a/ui/app/token-tracker.js
+++ /dev/null
diff --git a/ui/app/unlock.js b/ui/app/unlock.js
index cafe3a859..322808619 100644
--- a/ui/app/unlock.js
+++ b/ui/app/unlock.js
@@ -5,6 +5,7 @@ const connect = require('react-redux').connect
const actions = require('./actions')
const getCaretCoordinates = require('textarea-caret')
const EventEmitter = require('events').EventEmitter
+const t = require('../i18n')
const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
const environmentType = require('../../app/scripts/lib/environment-type')
@@ -28,83 +29,72 @@ UnlockScreen.prototype.render = function () {
const state = this.props
const warning = state.warning
return (
- h('.flex-column', {
- style: {
- width: 'inherit',
- },
- }, [
- h('.unlock-screen.flex-column.flex-center.flex-grow', [
-
- h(Mascot, {
- animationEventEmitter: this.animationEventEmitter,
- }),
-
- h('h1', {
- style: {
- fontSize: '1.4em',
- textTransform: 'uppercase',
- color: '#7F8082',
- },
- }, 'MetaMask'),
-
- h('input.large-input', {
- type: 'password',
- id: 'password-box',
- placeholder: 'enter password',
- style: {
- background: 'white',
- },
- onKeyPress: this.onKeyPress.bind(this),
- onInput: this.inputChanged.bind(this),
- }),
-
- h('.error', {
- style: {
- display: warning ? 'block' : 'none',
- padding: '0 20px',
- textAlign: 'center',
- },
- }, warning),
-
- h('button.primary.cursor-pointer', {
- onClick: this.onSubmit.bind(this),
- style: {
- margin: 10,
- },
- }, 'Log In'),
- ]),
-
- h('.flex-row.flex-center.flex-grow', [
- h('p.pointer', {
- onClick: () => {
- this.props.dispatch(actions.markPasswordForgotten())
- if (environmentType() === 'popup') {
- global.platform.openExtensionInBrowser()
- }
- },
- style: {
- fontSize: '0.8em',
- color: 'rgb(247, 134, 28)',
- textDecoration: 'underline',
- },
- }, 'Restore from seed phrase'),
- ]),
-
- h('.flex-row.flex-center.flex-grow', [
- h('p.pointer', {
- onClick: () => {
- this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
- .then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
- },
- style: {
- fontSize: '0.8em',
- color: '#aeaeae',
- textDecoration: 'underline',
- marginTop: '32px',
- },
- }, 'Use classic interface'),
- ]),
-
+ h('.unlock-screen', [
+
+ h(Mascot, {
+ animationEventEmitter: this.animationEventEmitter,
+ }),
+
+ h('h1', {
+ style: {
+ fontSize: '1.4em',
+ textTransform: 'uppercase',
+ color: '#7F8082',
+ },
+ }, t('appName')),
+
+ h('input.large-input', {
+ type: 'password',
+ id: 'password-box',
+ placeholder: 'enter password',
+ style: {
+ background: 'white',
+ },
+ onKeyPress: this.onKeyPress.bind(this),
+ onInput: this.inputChanged.bind(this),
+ }),
+
+ h('.error', {
+ style: {
+ display: warning ? 'block' : 'none',
+ padding: '0 20px',
+ textAlign: 'center',
+ },
+ }, warning),
+
+ h('button.primary.cursor-pointer', {
+ onClick: this.onSubmit.bind(this),
+ style: {
+ margin: 10,
+ },
+ }, t('login')),
+
+ h('p.pointer', {
+ onClick: () => {
+ this.props.dispatch(actions.markPasswordForgotten())
+ if (environmentType() === 'popup') {
+ global.platform.openExtensionInBrowser()
+ }
+ },
+ style: {
+ fontSize: '0.8em',
+ color: 'rgb(247, 134, 28)',
+ textDecoration: 'underline',
+ },
+ }, t('restoreFromSeed')),
+
+ h('p.pointer', {
+ onClick: () => {
+ this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
+ .then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
+ },
+ style: {
+ fontSize: '0.8em',
+ color: '#aeaeae',
+ textDecoration: 'underline',
+ marginTop: '32px',
+ },
+ }, t('classicInterface')),
])
)
}
diff --git a/ui/app/welcome-screen.js b/ui/app/welcome-screen.js
new file mode 100644
index 000000000..cdbb6dba8
--- /dev/null
+++ b/ui/app/welcome-screen.js
@@ -0,0 +1,56 @@
+import EventEmitter from 'events'
+import h from 'react-hyperscript'
+import { Component } from 'react'
+import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
+import {closeWelcomeScreen} from './actions'
+import Mascot from './components/mascot'
+
+class WelcomeScreen extends Component {
+ static propTypes = {
+ closeWelcomeScreen: PropTypes.func.isRequired,
+ }
+
+ constructor(props) {
+ super(props)
+ this.animationEventEmitter = new EventEmitter()
+ }
+
+ initiateAccountCreation = () => {
+ this.props.closeWelcomeScreen()
+ }
+
+ render () {
+ return h('div.welcome-screen', [
+
+ h('div.welcome-screen__info', [
+
+ h(Mascot, {
+ animationEventEmitter: this.animationEventEmitter,
+ width: '225',
+ height: '225',
+ }),
+
+ h('div.welcome-screen__info__header', 'Welcome to MetaMask Beta'),
+
+ h('div.welcome-screen__info__copy', 'MetaMask is a secure identity vault for Ethereum.'),
+
+ h('div.welcome-screen__info__copy', `It allows you to hold ether & tokens,
+ and serves as your bridge to decentralized applications.`),
+
+ h('button.welcome-screen__button', {
+ onClick: this.initiateAccountCreation,
+ }, 'Continue'),
+
+ ]),
+
+ ])
+ }
+}
+
+export default connect(
+ null,
+ dispatch => ({
+ closeWelcomeScreen: () => dispatch(closeWelcomeScreen()),
+ })
+)(WelcomeScreen)