aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorAlexander Tseung <alextsg@gmail.com>2018-01-30 10:22:52 +0800
committerAlexander Tseung <alextsg@gmail.com>2018-01-30 10:22:52 +0800
commitecc39c5a7abd8c8794d5565c1bc7d213d3514d61 (patch)
tree746f0a2bada5d8cd6636789d3c498c1ef13901fb /ui
parentd905b86ba775aad888d1dfd22257958fd9415909 (diff)
parentb05d21b1ba308bdb5b758d53dd79593a7a2bf26e (diff)
downloadtangerine-wallet-browser-ecc39c5a7abd8c8794d5565c1bc7d213d3514d61.tar
tangerine-wallet-browser-ecc39c5a7abd8c8794d5565c1bc7d213d3514d61.tar.gz
tangerine-wallet-browser-ecc39c5a7abd8c8794d5565c1bc7d213d3514d61.tar.bz2
tangerine-wallet-browser-ecc39c5a7abd8c8794d5565c1bc7d213d3514d61.tar.lz
tangerine-wallet-browser-ecc39c5a7abd8c8794d5565c1bc7d213d3514d61.tar.xz
tangerine-wallet-browser-ecc39c5a7abd8c8794d5565c1bc7d213d3514d61.tar.zst
tangerine-wallet-browser-ecc39c5a7abd8c8794d5565c1bc7d213d3514d61.zip
Merge branch 'uat' of https://github.com/MetaMask/metamask-extension into cb-254
Diffstat (limited to 'ui')
-rw-r--r--ui/app/accounts/import/index.js34
-rw-r--r--ui/app/accounts/new-account/create-form.js96
-rw-r--r--ui/app/accounts/new-account/index.js81
-rw-r--r--ui/app/actions.js108
-rw-r--r--ui/app/app.js29
-rw-r--r--ui/app/components/account-menu/index.js28
-rw-r--r--ui/app/components/balance-component.js5
-rw-r--r--ui/app/components/coinbase-form.js2
-rw-r--r--ui/app/components/currency-input.js14
-rw-r--r--ui/app/components/dropdowns/components/account-dropdowns.js10
-rw-r--r--ui/app/components/mascot.js6
-rw-r--r--ui/app/components/modals/account-details-modal.js4
-rw-r--r--ui/app/components/modals/buy-options-modal.js2
-rw-r--r--ui/app/components/modals/deposit-ether-modal.js184
-rw-r--r--ui/app/components/modals/export-private-key-modal.js10
-rw-r--r--ui/app/components/modals/hide-token-confirmation-modal.js4
-rw-r--r--ui/app/components/modals/modal.js32
-rw-r--r--ui/app/components/network.js41
-rw-r--r--ui/app/components/pages/add-token.js30
-rw-r--r--ui/app/components/pages/import-account/json.js40
-rw-r--r--ui/app/components/pages/import-account/private-key.js61
-rw-r--r--ui/app/components/pages/keychains/restore-vault.js5
-rw-r--r--ui/app/components/pages/settings/settings.js14
-rw-r--r--ui/app/components/pending-tx/confirm-send-ether.js28
-rw-r--r--ui/app/components/pending-tx/confirm-send-token.js43
-rw-r--r--ui/app/components/send/gas-fee-display-v2.js3
-rw-r--r--ui/app/components/send/send-constants.js3
-rw-r--r--ui/app/components/send/send-v2-container.js4
-rw-r--r--ui/app/components/shapeshift-form.js468
-rw-r--r--ui/app/components/shift-list-item.js50
-rw-r--r--ui/app/components/token-cell.js6
-rw-r--r--ui/app/components/transaction-list-item.js129
-rw-r--r--ui/app/components/tx-list-item.js10
-rw-r--r--ui/app/components/tx-list.js19
-rw-r--r--ui/app/components/tx-view.js20
-rw-r--r--ui/app/components/wallet-view.js4
-rw-r--r--ui/app/css/itcss/components/add-token.scss22
-rw-r--r--ui/app/css/itcss/components/buttons.scss38
-rw-r--r--ui/app/css/itcss/components/confirm.scss26
-rw-r--r--ui/app/css/itcss/components/header.scss21
-rw-r--r--ui/app/css/itcss/components/hero-balance.scss46
-rw-r--r--ui/app/css/itcss/components/index.scss2
-rw-r--r--ui/app/css/itcss/components/modal.scss306
-rw-r--r--ui/app/css/itcss/components/network.scss42
-rw-r--r--ui/app/css/itcss/components/new-account.scss192
-rw-r--r--ui/app/css/itcss/components/newui-sections.scss52
-rw-r--r--ui/app/css/itcss/components/send.scss36
-rw-r--r--ui/app/css/itcss/components/token-list.scss15
-rw-r--r--ui/app/css/itcss/components/transaction-list.scss30
-rw-r--r--ui/app/css/itcss/components/wallet-balance.scss19
-rw-r--r--ui/app/css/itcss/settings/typography.scss4
-rw-r--r--ui/app/css/itcss/settings/variables.scss4
-rw-r--r--ui/app/info.js7
-rw-r--r--ui/app/keychains/hd/restore-vault.js156
-rw-r--r--ui/app/reducers/app.js92
-rw-r--r--ui/app/reducers/metamask.js7
-rw-r--r--ui/app/select-app.js58
-rw-r--r--ui/app/selectors.js6
-rw-r--r--ui/app/send-v2.js192
-rw-r--r--ui/app/util.js8
-rw-r--r--ui/index.js7
61 files changed, 2059 insertions, 956 deletions
diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js
index b7d9a9537..0c901c09b 100644
--- a/ui/app/accounts/import/index.js
+++ b/ui/app/accounts/import/index.js
@@ -2,7 +2,6 @@ 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')
import Select from 'react-select'
// Subviews
@@ -34,37 +33,14 @@ AccountImportSubview.prototype.render = function () {
const { type } = state
return (
- h('div.flex-center', {
- style: {
- flexDirection: 'column',
- marginTop: '32px',
- },
- }, [
- h('.section-title.flex-row.flex-center', [
- h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
- onClick: (event) => {
- props.dispatch(actions.goHome())
- },
- }),
- h('h2.page-subtitle', 'Import Accounts'),
- ]),
- h('div', {
- style: {
- padding: '10px 0',
- width: '260px',
- color: 'rgb(174, 174, 174)',
- },
- }, [
+ h('div.new-account-import-form', [
- h('h3', { style: { padding: '3px' } }, 'SELECT TYPE'),
+ h('div.new-account-import-form__select-section', [
- h('style', `
- .has-value.Select--single > .Select-control .Select-value .Select-value-label, .Select-value-label {
- color: rgb(174,174,174);
- }
- `),
+ h('div.new-account-import-form__select-label', 'SELECT TYPE'),
h(Select, {
+ className: 'new-account-import-form__select',
name: 'import-type-select',
clearable: false,
value: type || menuItems[0],
@@ -75,10 +51,10 @@ AccountImportSubview.prototype.render = function () {
}
}),
onChange: (opt) => {
- props.dispatch(actions.showImportPage())
this.setState({ type: opt.value })
},
}),
+
]),
this.renderImportView(),
diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js
new file mode 100644
index 000000000..494726ae4
--- /dev/null
+++ b/ui/app/accounts/new-account/create-form.js
@@ -0,0 +1,96 @@
+const { Component } = require('react')
+const PropTypes = require('prop-types')
+const h = require('react-hyperscript')
+const { connect } = require('react-redux')
+const actions = require('../../actions')
+
+class NewAccountCreateForm extends Component {
+ constructor (props) {
+ super(props)
+ const { numberOfExistingAccounts = 0 } = props
+ const newAccountNumber = numberOfExistingAccounts + 1
+
+ this.state = {
+ newAccountName: `Account ${newAccountNumber}`,
+ }
+ }
+
+ render () {
+ const { newAccountName } = this.state
+
+ return h('div.new-account-create-form', [
+
+ h('div.new-account-create-form__input-label', {}, [
+ 'Account Name',
+ ]),
+
+ h('div.new-account-create-form__input-wrapper', {}, [
+ h('input.new-account-create-form__input', {
+ value: this.state.newAccountName,
+ placeholder: 'E.g. My new account',
+ onChange: event => this.setState({ newAccountName: event.target.value }),
+ }, []),
+ ]),
+
+ h('div.new-account-create-form__buttons', {}, [
+
+ h('button.new-account-create-form__button-cancel', {
+ onClick: () => this.props.goHome(),
+ }, [
+ 'CANCEL',
+ ]),
+
+ h('button.new-account-create-form__button-create', {
+ onClick: () => this.props.createAccount(newAccountName),
+ }, [
+ 'CREATE',
+ ]),
+
+ ]),
+
+ ])
+ }
+}
+
+NewAccountCreateForm.propTypes = {
+ hideModal: PropTypes.func,
+ showImportPage: PropTypes.func,
+ createAccount: PropTypes.func,
+ goHome: PropTypes.func,
+ numberOfExistingAccounts: PropTypes.number,
+}
+
+const mapStateToProps = state => {
+ const { metamask: { network, selectedAddress, identities = {} } } = state
+ const numberOfExistingAccounts = Object.keys(identities).length
+
+ return {
+ network,
+ address: selectedAddress,
+ numberOfExistingAccounts,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ toCoinbase: (address) => {
+ dispatch(actions.buyEth({ network: '1', address, amount: 0 }))
+ },
+ hideModal: () => {
+ dispatch(actions.hideModal())
+ },
+ createAccount: (newAccountName) => {
+ dispatch(actions.addNewAccount())
+ .then((newAccountAddress) => {
+ if (newAccountName) {
+ dispatch(actions.saveAccountLabel(newAccountAddress, newAccountName))
+ }
+ dispatch(actions.goHome())
+ })
+ },
+ showImportPage: () => dispatch(actions.showImportPage()),
+ goHome: () => dispatch(actions.goHome()),
+ }
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(NewAccountCreateForm)
diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js
new file mode 100644
index 000000000..acf0dc6e4
--- /dev/null
+++ b/ui/app/accounts/new-account/index.js
@@ -0,0 +1,81 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const actions = require('../../actions')
+const { getCurrentViewContext } = require('../../selectors')
+const classnames = require('classnames')
+
+const NewAccountCreateForm = require('./create-form')
+const NewAccountImportForm = require('../import')
+
+function mapStateToProps (state) {
+ return {
+ displayedForm: getCurrentViewContext(state),
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ displayForm: form => dispatch(actions.setNewAccountForm(form)),
+ showQrView: (selected, identity) => dispatch(actions.showQrView(selected, identity)),
+ showExportPrivateKeyModal: () => {
+ dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
+ },
+ hideModal: () => dispatch(actions.hideModal()),
+ saveAccountLabel: (address, label) => dispatch(actions.saveAccountLabel(address, label)),
+ }
+}
+
+inherits(AccountDetailsModal, Component)
+function AccountDetailsModal (props) {
+ Component.call(this)
+
+ this.state = {
+ displayedForm: props.displayedForm,
+ }
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDetailsModal)
+
+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__tabs', [
+
+ h('div.new-account__tabs__tab', {
+ className: classnames('new-account__tabs__tab', {
+ 'new-account__tabs__selected': displayedForm === 'CREATE',
+ 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'CREATE',
+ }),
+ onClick: () => displayForm('CREATE'),
+ }, 'Create'),
+
+ h('div.new-account__tabs__tab', {
+ className: classnames('new-account__tabs__tab', {
+ 'new-account__tabs__selected': displayedForm === 'IMPORT',
+ 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'IMPORT',
+ }),
+ onClick: () => displayForm('IMPORT'),
+ }, 'Import'),
+
+ ]),
+
+ ]),
+
+ h('div.new-account__form', [
+
+ displayedForm === 'CREATE'
+ ? h(NewAccountCreateForm)
+ : h(NewAccountImportForm),
+
+ ]),
+
+ ])
+}
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 60bd4a1ee..da69b8195 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -1,5 +1,6 @@
const abi = require('human-standard-token-abi')
const getBuyEthUrl = require('../../app/scripts/lib/buy-eth-url')
+const { getTokenAddressFromTokenObject } = require('./util')
const ethUtil = require('ethereumjs-util')
var actions = {
@@ -50,12 +51,16 @@ var actions = {
SHOW_NEW_VAULT_SEED: 'SHOW_NEW_VAULT_SEED',
SHOW_INFO_PAGE: 'SHOW_INFO_PAGE',
SHOW_IMPORT_PAGE: 'SHOW_IMPORT_PAGE',
+ SHOW_NEW_ACCOUNT_PAGE: 'SHOW_NEW_ACCOUNT_PAGE',
+ SET_NEW_ACCOUNT_FORM: 'SET_NEW_ACCOUNT_FORM',
unlockMetamask: unlockMetamask,
unlockFailed: unlockFailed,
showCreateVault: showCreateVault,
showRestoreVault: showRestoreVault,
showInitializeMenu: showInitializeMenu,
showImportPage,
+ showNewAccountPage,
+ setNewAccountForm,
createNewVaultAndKeychain: createNewVaultAndKeychain,
createNewVaultAndRestore: createNewVaultAndRestore,
createNewVaultInProgress: createNewVaultInProgress,
@@ -125,6 +130,7 @@ var actions = {
sendTx: sendTx,
signTx: signTx,
signTokenTx: signTokenTx,
+ updateTransaction,
updateAndApproveTx,
cancelTx: cancelTx,
completedTx: completedTx,
@@ -239,11 +245,18 @@ var actions = {
SET_USE_BLOCKIE: 'SET_USE_BLOCKIE',
setUseBlockie,
-
+
// Feature Flags
setFeatureFlag,
updateFeatureFlags,
UPDATE_FEATURE_FLAGS: 'UPDATE_FEATURE_FLAGS',
+
+ // Network
+ setNetworkEndpoints,
+ updateNetworkEndpointType,
+ UPDATE_NETWORK_ENDPOINT_TYPE: 'UPDATE_NETWORK_ENDPOINT_TYPE',
+
+ retryTransaction,
}
module.exports = actions
@@ -714,6 +727,23 @@ function signTokenTx (tokenAddress, toAddress, amount, txData) {
}
}
+function updateTransaction (txData) {
+ log.info('actions: updateTx: ' + JSON.stringify(txData))
+ return (dispatch) => {
+ log.debug(`actions calling background.updateTx`)
+ background.updateTransaction(txData, (err) => {
+ dispatch(actions.hideLoadingIndication())
+ dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
+ if (err) {
+ dispatch(actions.txError(err))
+ dispatch(actions.goHome())
+ return log.error(err.message)
+ }
+ dispatch(actions.showConfTxPage({ id: txData.id }))
+ })
+ }
+}
+
function updateAndApproveTx (txData) {
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
return (dispatch) => {
@@ -829,6 +859,7 @@ function cancelTx (txData) {
log.debug(`background.cancelTransaction`)
return new Promise((resolve, reject) => {
background.cancelTransaction(txData.id, () => {
+ dispatch(actions.clearSend())
dispatch(actions.completedTx(txData.id))
resolve(txData)
})
@@ -880,6 +911,20 @@ function showImportPage () {
}
}
+function showNewAccountPage (formToSelect) {
+ return {
+ type: actions.SHOW_NEW_ACCOUNT_PAGE,
+ formToSelect,
+ }
+}
+
+function setNewAccountForm (formToSelect) {
+ return {
+ type: actions.SET_NEW_ACCOUNT_FORM,
+ formToSelect,
+ }
+}
+
function createNewVaultInProgress () {
return {
type: actions.CREATE_NEW_VAULT_IN_PROGRESS,
@@ -976,9 +1021,13 @@ function lockMetamask () {
})
.then(newState => {
dispatch(actions.updateMetamaskState(newState))
+ dispatch(actions.hideLoadingIndication())
+ dispatch({ type: actions.LOCK_METAMASK })
+ })
+ .catch(() => {
+ dispatch(actions.hideLoadingIndication())
dispatch({ type: actions.LOCK_METAMASK })
})
- .catch(() => dispatch({ type: actions.LOCK_METAMASK }))
}
}
@@ -1123,10 +1172,12 @@ function removeToken (address) {
function addTokens (tokens) {
return dispatch => {
if (Array.isArray(tokens)) {
+ dispatch(actions.setSelectedToken(getTokenAddressFromTokenObject(tokens[0])))
return Promise.all(tokens.map(({ address, symbol, decimals }) => (
dispatch(addToken(address, symbol, decimals))
)))
} else {
+ dispatch(actions.setSelectedToken(getTokenAddressFromTokenObject(tokens)))
return Promise.all(
Object
.entries(tokens)
@@ -1196,6 +1247,19 @@ function markAccountsFound () {
return callBackgroundThenUpdate(background.markAccountsFound)
}
+function retryTransaction (txId) {
+ log.debug(`background.retryTransaction`)
+ return (dispatch) => {
+ background.retryTransaction(txId, (err, newState) => {
+ if (err) {
+ return dispatch(actions.displayWarning(err.message))
+ }
+ dispatch(actions.updateMetamaskState(newState))
+ dispatch(actions.viewPendingTx(txId))
+ })
+ }
+}
+
//
// config
//
@@ -1472,7 +1536,6 @@ function pairUpdate (coin) {
function shapeShiftSubview (network) {
var pair = 'btc_eth'
-
return (dispatch) => {
dispatch(actions.showSubLoadingIndication())
shapeShiftRequest('marketinfo', {pair}, (mktResponse) => {
@@ -1498,7 +1561,7 @@ function coinShiftRquest (data, marketData) {
dispatch(actions.hideLoadingIndication())
if (response.error) return dispatch(actions.displayWarning(response.error))
var message = `
- Deposit your ${response.depositType} to the address bellow:`
+ Deposit your ${response.depositType} to the address below:`
log.debug(`background.createShapeShiftTx`)
background.createShapeShiftTx(response.deposit, response.depositType)
dispatch(actions.showQrView(response.deposit, [message].concat(marketData)))
@@ -1532,9 +1595,9 @@ function reshowQrCode (data, coin) {
dispatch(actions.showLoadingIndication())
shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => {
if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error))
-
+
var message = [
- `Deposit your ${coin} to the address bellow:`,
+ `Deposit your ${coin} to the address below:`,
`Deposit Limit: ${mktResponse.limit}`,
`Deposit Minimum:${mktResponse.minimum}`,
]
@@ -1600,10 +1663,7 @@ function updateTokenExchangeRate (token = '') {
}
}
-function setFeatureFlag (feature, activated) {
- const notificationType = activated
- ? 'BETA_UI_NOTIFICATION_MODAL'
- : 'OLD_UI_NOTIFICATION_MODAL'
+function setFeatureFlag (feature, activated, notificationType) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => {
@@ -1611,10 +1671,10 @@ function setFeatureFlag (feature, activated) {
dispatch(actions.hideLoadingIndication())
if (err) {
dispatch(actions.displayWarning(err.message))
- reject(err)
+ return reject(err)
}
dispatch(actions.updateFeatureFlags(updatedFeatureFlags))
- dispatch(actions.showModal({ name: notificationType }))
+ notificationType && dispatch(actions.showModal({ name: notificationType }))
resolve(updatedFeatureFlags)
})
})
@@ -1698,3 +1758,27 @@ function setUseBlockie (val) {
})
}
}
+
+function setNetworkEndpoints (networkEndpointType) {
+ return dispatch => {
+ log.debug('background.setNetworkEndpoints')
+ return new Promise((resolve, reject) => {
+ background.setNetworkEndpoints(networkEndpointType, err => {
+ if (err) {
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
+
+ dispatch(actions.updateNetworkEndpointType(networkEndpointType))
+ resolve(networkEndpointType)
+ })
+ })
+ }
+}
+
+function updateNetworkEndpointType (networkEndpointType) {
+ return {
+ type: actions.UPDATE_NETWORK_ENDPOINT_TYPE,
+ value: networkEndpointType,
+ }
+}
diff --git a/ui/app/app.js b/ui/app/app.js
index 07be459fc..22dc8c343 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -5,6 +5,8 @@ const { Switch, Redirect, withRouter } = require('react-router-dom')
const { compose } = require('recompose')
const h = require('react-hyperscript')
const actions = require('./actions')
+const classnames = require('classnames')
+
// mascara
const MascaraCreatePassword = require('../../mascara/src/app/first-time/create-password-screen').default
const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default
@@ -234,22 +236,22 @@ class App extends Component {
showNetworkDropdown,
hideNetworkDropdown,
currentView,
- isMascara,
- isOnboarding,
- history,
} = this.props
if (window.METAMASK_UI_TYPE === 'notification') {
return null
}
+ const props = this.props
+ const {isMascara, isOnboarding} = props
+
// Do not render header if user is in mascara onboarding
if (isMascara && isOnboarding) {
return null
}
// Do not render header if user is in mascara buy ether
- if (isMascara && currentView.name === 'buyEth') {
+ if (isMascara && props.currentView.name === 'buyEth') {
return null
}
@@ -260,7 +262,9 @@ class App extends Component {
}, [
h('.app-header.flex-row.flex-space-between', {
- style: {},
+ className: classnames({
+ 'app-header--initialized': !isOnboarding,
+ }),
}, [
h('div.app-header-contents', {}, [
h('div.left-menu-wrapper', {
@@ -268,19 +272,13 @@ class App extends Component {
}, [
// mini logo
h('img.metafox-icon', {
- height: 29,
- width: 29,
- src: '/images/icon-128.png',
+ height: 42,
+ width: 42,
+ src: '/images/metamask-fox.svg',
}),
// metamask name
- h('h1', {
- style: {
- position: 'relative',
- paddingLeft: '9px',
- color: '#5B5D67',
- },
- }, 'MetaMask'),
+ h('h1', 'MetaMask'),
]),
@@ -313,6 +311,7 @@ class App extends Component {
]),
]),
]),
+
])
)
}
diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js
index 0d3b43ae9..f031f2446 100644
--- a/ui/app/components/account-menu/index.js
+++ b/ui/app/components/account-menu/index.js
@@ -33,15 +33,28 @@ function mapDispatchToProps (dispatch) {
toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()),
showAccountDetail: address => {
dispatch(actions.showAccountDetail(address))
+ dispatch(actions.hideSidebar())
dispatch(actions.toggleAccountMenu())
},
lockMetamask: () => {
dispatch(actions.lockMetamask())
- dispatch(actions.displayWarning(null))
+ dispatch(actions.hideWarning())
+ dispatch(actions.hideSidebar())
dispatch(actions.toggleAccountMenu())
},
- showNewAccountModal: () => {
- dispatch(actions.showModal({ name: 'NEW_ACCOUNT' }))
+ showConfigPage: () => {
+ dispatch(actions.showConfigPage())
+ dispatch(actions.hideSidebar())
+ dispatch(actions.toggleAccountMenu())
+ },
+ showNewAccountPage: (formToSelect) => {
+ dispatch(actions.showNewAccountPage(formToSelect))
+ dispatch(actions.hideSidebar())
+ dispatch(actions.toggleAccountMenu())
+ },
+ showInfoPage: () => {
+ dispatch(actions.showInfoPage())
+ dispatch(actions.hideSidebar())
dispatch(actions.toggleAccountMenu())
},
}
@@ -51,7 +64,7 @@ AccountMenu.prototype.render = function () {
const {
isAccountMenuOpen,
toggleAccountMenu,
- showNewAccountModal,
+ showNewAccountPage,
lockMetamask,
history,
} = this.props
@@ -73,15 +86,12 @@ AccountMenu.prototype.render = function () {
h('div.account-menu__accounts', this.renderAccounts()),
h(Divider),
h(Item, {
- onClick: showNewAccountModal,
+ onClick: () => showNewAccountPage('CREATE'),
icon: h('img', { src: 'images/plus-btn-white.svg' }),
text: 'Create Account',
}),
h(Item, {
- onClick: () => {
- toggleAccountMenu()
- history.push(IMPORT_ACCOUNT_ROUTE)
- },
+ onClick: () => showNewAccountPage('IMPORT'),
icon: h('img', { src: 'images/import-account.svg' }),
text: 'Import Account',
}),
diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js
index d14aa675f..d591ab455 100644
--- a/ui/app/components/balance-component.js
+++ b/ui/app/components/balance-component.js
@@ -40,7 +40,7 @@ BalanceComponent.prototype.render = function () {
// style: {},
// }),
h(Identicon, {
- diameter: 45,
+ diameter: 50,
address: token && token.address,
network,
}),
@@ -94,7 +94,8 @@ BalanceComponent.prototype.renderFiatValue = function (formattedBalance) {
}
BalanceComponent.prototype.renderFiatAmount = function (fiatDisplayNumber, fiatSuffix, fiatPrefix) {
- if (fiatDisplayNumber === 'N/A') return null
+ const shouldNotRenderFiat = fiatDisplayNumber === 'N/A' || Number(fiatDisplayNumber) === 0
+ if (shouldNotRenderFiat) return null
return h('div.fiat-amount', {
style: {},
diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js
index f44d86045..f70208625 100644
--- a/ui/app/components/coinbase-form.js
+++ b/ui/app/components/coinbase-form.js
@@ -40,7 +40,7 @@ CoinbaseForm.prototype.render = function () {
}, 'Continue to Coinbase'),
h('button.btn-red', {
- onClick: () => props.dispatch(actions.backTobuyView(props.accounts.address)),
+ onClick: () => props.dispatch(actions.goHome()),
}, 'Cancel'),
]),
])
diff --git a/ui/app/components/currency-input.js b/ui/app/components/currency-input.js
index 66880091f..6f7862e51 100644
--- a/ui/app/components/currency-input.js
+++ b/ui/app/components/currency-input.js
@@ -50,10 +50,18 @@ function sanitizeValue (value) {
CurrencyInput.prototype.handleChange = function (newValue) {
const { onInputChange } = this.props
+ const { value } = this.state
- this.setState({ value: sanitizeValue(newValue) })
+ let parsedValue = newValue
+ const newValueLastIndex = newValue.length - 1
- onInputChange(sanitizeValue(newValue))
+ if (value === '0' && newValue[newValueLastIndex] === '0') {
+ parsedValue = parsedValue.slice(0, newValueLastIndex)
+ }
+
+ const sanitizedValue = sanitizeValue(parsedValue)
+ this.setState({ value: sanitizedValue })
+ onInputChange(sanitizedValue)
}
// If state.value === props.value plus a decimal point, or at least one
@@ -90,6 +98,6 @@ CurrencyInput.prototype.render = function () {
size: valueToRender.length * inputSizeMultiplier,
readOnly,
onChange: e => this.handleChange(e.target.value),
- ref: inputRef,
+ ref: inputRef,
})
}
diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js
index 58326b13c..f97ac0691 100644
--- a/ui/app/components/dropdowns/components/account-dropdowns.js
+++ b/ui/app/components/dropdowns/components/account-dropdowns.js
@@ -199,7 +199,7 @@ class AccountDropdowns extends Component {
{},
menuItemStyles,
),
- onClick: () => actions.showNewAccountModal(),
+ onClick: () => actions.showNewAccountPageCreateForm(),
},
[
h(
@@ -228,7 +228,7 @@ class AccountDropdowns extends Component {
actions.hideSidebar()
}
},
- onClick: () => actions.showImportPage(),
+ onClick: () => actions.showNewAccountPageImportForm(),
style: Object.assign(
{},
menuItemStyles,
@@ -457,9 +457,7 @@ const mapDispatchToProps = (dispatch) => {
identity,
}))
},
- showNewAccountModal: () => {
- dispatch(actions.showModal({ name: 'NEW_ACCOUNT' }))
- },
+ showNewAccountPageCreateForm: () => dispatch(actions.showNewAccountPage({ form: 'CREATE' })),
showExportPrivateKeyModal: () => {
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
},
@@ -467,7 +465,7 @@ const mapDispatchToProps = (dispatch) => {
dispatch(actions.showAddTokenPage())
},
addNewAccount: () => dispatch(actions.addNewAccount()),
- showImportPage: () => dispatch(actions.showImportPage()),
+ showNewAccountPageImportForm: () => dispatch(actions.showNewAccountPage({ form: 'IMPORT' })),
showQrView: (selected, identity) => dispatch(actions.showQrView(selected, identity)),
},
}
diff --git a/ui/app/components/mascot.js b/ui/app/components/mascot.js
index 973ec2cad..3b0d3e31b 100644
--- a/ui/app/components/mascot.js
+++ b/ui/app/components/mascot.js
@@ -7,13 +7,13 @@ const debounce = require('debounce')
module.exports = Mascot
inherits(Mascot, Component)
-function Mascot () {
+function Mascot ({width = '200', height = '200'}) {
Component.call(this)
this.logo = metamaskLogo({
followMouse: true,
pxNotRatio: true,
- width: 200,
- height: 200,
+ width,
+ height,
})
this.refollowMouse = debounce(this.logo.setFollowMouse.bind(this.logo, true), 1000)
diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js
index 4bf671834..c1f7a3236 100644
--- a/ui/app/components/modals/account-details-modal.js
+++ b/ui/app/components/modals/account-details-modal.js
@@ -62,12 +62,12 @@ AccountDetailsModal.prototype.render = function () {
h('div.account-modal-divider'),
- h('button.btn-clear', {
+ h('button.btn-clear.account-modal__button', {
onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }),
}, 'View account on Etherscan'),
// Holding on redesign for Export Private Key functionality
- h('button.btn-clear', {
+ h('button.btn-clear.account-modal__button', {
onClick: () => showExportPrivateKeyModal(),
}, 'Export private key'),
diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js
index d735983f9..74a7a847e 100644
--- a/ui/app/components/modals/buy-options-modal.js
+++ b/ui/app/components/modals/buy-options-modal.js
@@ -69,7 +69,7 @@ BuyOptions.prototype.render = function () {
// h('div.buy-modal-content-option', {}, [
// h('div.buy-modal-content-option-title', {}, 'Shapeshift'),
// h('div.buy-modal-content-option-subtitle', {}, 'Trade any digital asset for any other'),
- // ]),
+ // ]),,
this.renderModalContentOption(
'Direct Deposit',
diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js
new file mode 100644
index 000000000..532d66653
--- /dev/null
+++ b/ui/app/components/modals/deposit-ether-modal.js
@@ -0,0 +1,184 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+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}`
+
+function mapStateToProps (state) {
+ return {
+ network: state.metamask.network,
+ address: state.metamask.selectedAddress,
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ toCoinbase: (address) => {
+ dispatch(actions.buyEth({ network: '1', address, amount: 0 }))
+ },
+ hideModal: () => {
+ dispatch(actions.hideModal())
+ },
+ showAccountDetailModal: () => {
+ dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' }))
+ },
+ toFaucet: network => dispatch(actions.buyEth({ network })),
+ }
+}
+
+inherits(DepositEtherModal, Component)
+function DepositEtherModal () {
+ Component.call(this)
+
+ this.state = {
+ buyingWithShapeshift: false,
+ }
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(DepositEtherModal)
+
+DepositEtherModal.prototype.renderRow = function ({
+ logo,
+ title,
+ text,
+ buttonLabel,
+ onButtonClick,
+ hide,
+ className,
+ hideButton,
+ hideTitle,
+ onBackClick,
+ showBackButton,
+}) {
+ if (hide) {
+ return null
+ }
+
+ return h('div', {
+ className: className || 'deposit-ether-modal__buy-row',
+ }, [
+
+ onBackClick && showBackButton && h('div.deposit-ether-modal__buy-row__back', {
+ onClick: onBackClick,
+ }, [
+
+ h('i.fa.fa-arrow-left.cursor-pointer'),
+
+ ]),
+
+ h('div.deposit-ether-modal__buy-row__logo', [logo]),
+
+ h('div.deposit-ether-modal__buy-row__description', [
+
+ !hideTitle && h('div.deposit-ether-modal__buy-row__description__title', [title]),
+
+ h('div.deposit-ether-modal__buy-row__description__text', [text]),
+
+ ]),
+
+ !hideButton && h('div.deposit-ether-modal__buy-row__button', [
+ h('button.deposit-ether-modal__deposit-button', {
+ onClick: onButtonClick,
+ }, [buttonLabel]),
+ ]),
+
+ ])
+}
+
+DepositEtherModal.prototype.render = function () {
+ const { network, toCoinbase, address, toFaucet } = this.props
+ const { buyingWithShapeshift } = this.state
+
+ const isTestNetwork = ['3', '4', '42'].find(n => n === network)
+ const networkName = networkNames[network]
+
+ return h('div.deposit-ether-modal', {}, [
+
+ h('div.deposit-ether-modal__header', [
+
+ h('div.deposit-ether-modal__header__title', ['Deposit Ether']),
+
+ h('div.deposit-ether-modal__header__description', [
+ 'To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet.',
+ ]),
+
+ h('div.deposit-ether-modal__header__close', {
+ onClick: () => {
+ this.setState({ buyingWithShapeshift: false })
+ this.props.hideModal()
+ },
+ }),
+
+ ]),
+
+ h('div.deposit-ether-modal__buy-rows', [
+
+ 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,
+ }),
+
+ 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__buy-row__coinbase-logo', {
+ src: '../../../images/coinbase logo.png',
+ }),
+ 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',
+ }),
+ 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),
+
+ ]),
+ ])
+}
+
+DepositEtherModal.prototype.goToAccountDetailsModal = function () {
+ this.props.hideModal()
+ this.props.showAccountDetailModal()
+}
diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js
index 193755df5..422f23f44 100644
--- a/ui/app/components/modals/export-private-key-modal.js
+++ b/ui/app/components/modals/export-private-key-modal.js
@@ -79,11 +79,15 @@ ExportPrivateKeyModal.prototype.renderButton = function (className, onClick, lab
ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, address, hideModal) {
return h('div.export-private-key-buttons', {}, [
- !privateKey && this.renderButton('btn-clear btn-cancel', () => hideModal(), 'Cancel'),
+ !privateKey && this.renderButton(
+ 'btn-cancel export-private-key__button export-private-key__button--cancel',
+ () => hideModal(),
+ 'Cancel'
+ ),
(privateKey
- ? this.renderButton('btn-clear', () => hideModal(), 'Done')
- : this.renderButton('btn-clear', () => this.exportAccountAndGetPrivateKey(this.state.password, address), 'Show')
+ ? 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')
),
])
diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js
index fa3ad0b1e..56c7ba299 100644
--- a/ui/app/components/modals/hide-token-confirmation-modal.js
+++ b/ui/app/components/modals/hide-token-confirmation-modal.js
@@ -58,12 +58,12 @@ HideTokenConfirmationModal.prototype.render = function () {
]),
h('div.hide-token-confirmation__buttons', {}, [
- h('button.btn-clear', {
+ h('button.btn-cancel.hide-token-confirmation__button', {
onClick: () => hideModal(),
}, [
'CANCEL',
]),
- h('button.btn-clear', {
+ h('button.btn-clear.hide-token-confirmation__button', {
onClick: () => hideToken(address),
}, [
'HIDE',
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index 2ff6accaa..afb2a2175 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -9,6 +9,7 @@ const isPopupOrNotification = require('../../../../app/scripts/lib/is-popup-or-n
// Modal Components
const BuyOptions = require('./buy-options-modal')
+const DepositEtherModal = require('./deposit-ether-modal')
const AccountDetailsModal = require('./account-details-modal')
const EditAccountNameModal = require('./edit-account-name-modal')
const ExportPrivateKeyModal = require('./export-private-key-modal')
@@ -73,6 +74,37 @@ const MODALS = {
},
},
+ DEPOSIT_ETHER: {
+ contents: [
+ h(DepositEtherModal, {}, []),
+ ],
+ mobileModalStyle: {
+ width: '100%',
+ height: '100%',
+ transform: 'none',
+ left: '0',
+ right: '0',
+ margin: '0 auto',
+ boxShadow: '0 0 7px 0 rgba(0,0,0,0.08)',
+ top: '0',
+ display: 'flex',
+ },
+ laptopModalStyle: {
+ width: '900px',
+ maxWidth: '900px',
+ top: 'calc(10% + 10px)',
+ left: '0',
+ right: '0',
+ margin: '0 auto',
+ boxShadow: '0 0 6px 0 rgba(0,0,0,0.3)',
+ borderRadius: '8px',
+ transform: 'none',
+ },
+ contentStyle: {
+ borderRadius: '8px',
+ },
+ },
+
EDIT_ACCOUNT_NAME: {
contents: [
h(EditAccountNameModal, {}, []),
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index 5a8d0763d..3f147159b 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -39,7 +39,6 @@ Network.prototype.render = function () {
},
src: 'images/loading.svg',
}),
- h('i.fa.fa-caret-down.network-caret'),
])
} else if (providerName === 'mainnet') {
hoverText = 'Main Ethereum Network'
@@ -85,12 +84,8 @@ Network.prototype.render = function () {
backgroundColor: '#038789', // $blue-lagoon
nonSelectBackgroundColor: '#15afb2',
}),
- h('.network-name', {
- style: {
- color: '#039396',
- }},
- 'Main Network'),
- h('i.fa.fa-caret-down.fa-lg.network-caret'),
+ h('.network-name', 'Main Network'),
+ h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
case 'ropsten-test-network':
return h('.network-indicator', [
@@ -98,12 +93,8 @@ Network.prototype.render = function () {
backgroundColor: '#e91550', // $crimson
nonSelectBackgroundColor: '#ec2c50',
}),
- h('.network-name', {
- style: {
- color: '#ff6666',
- }},
- 'Ropsten Test Net'),
- h('i.fa.fa-caret-down.fa-lg.network-caret'),
+ h('.network-name', 'Ropsten Test Net'),
+ h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
case 'kovan-test-network':
return h('.network-indicator', [
@@ -111,12 +102,8 @@ Network.prototype.render = function () {
backgroundColor: '#690496', // $purple
nonSelectBackgroundColor: '#b039f3',
}),
- h('.network-name', {
- style: {
- color: '#690496',
- }},
- 'Kovan Test Net'),
- h('i.fa.fa-caret-down.fa-lg.network-caret'),
+ h('.network-name', 'Kovan Test Net'),
+ h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
case 'rinkeby-test-network':
return h('.network-indicator', [
@@ -124,12 +111,8 @@ Network.prototype.render = function () {
backgroundColor: '#ebb33f', // $tulip-tree
nonSelectBackgroundColor: '#ecb23e',
}),
- h('.network-name', {
- style: {
- color: '#e7a218',
- }},
- 'Rinkeby Test Net'),
- h('i.fa.fa-caret-down.fa-lg.network-caret'),
+ h('.network-name', 'Rinkeby Test Net'),
+ h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
default:
return h('.network-indicator', [
@@ -140,12 +123,8 @@ Network.prototype.render = function () {
},
}),
- h('.network-name', {
- style: {
- color: '#AEAEAE',
- }},
- 'Private Network'),
- h('i.fa.fa-caret-down.fa-lg.network-caret'),
+ h('.network-name', 'Private Network'),
+ h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
}
})(),
diff --git a/ui/app/components/pages/add-token.js b/ui/app/components/pages/add-token.js
index 7f0c37475..0454ee2f1 100644
--- a/ui/app/components/pages/add-token.js
+++ b/ui/app/components/pages/add-token.js
@@ -3,6 +3,7 @@ const Component = require('react').Component
const classnames = require('classnames')
const h = require('react-hyperscript')
const connect = require('react-redux').connect
+const R = require('ramda')
const Fuse = require('fuse.js')
const contractMap = require('eth-contract-metadata')
const TokenBalance = require('../../components/token-balance')
@@ -17,7 +18,10 @@ const fuse = new Fuse(contractList, {
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
- keys: ['address', 'name', 'symbol'],
+ keys: [
+ { name: 'name', weight: 0.5 },
+ { name: 'symbol', weight: 0.5 },
+ ],
})
// const actions = require('./actions')
const actions = require('../../actions')
@@ -219,9 +223,11 @@ AddTokenScreen.prototype.renderCustomForm = function () {
AddTokenScreen.prototype.renderTokenList = function () {
const { searchQuery = '', selectedTokens } = this.state
- const results = searchQuery
- ? fuse.search(searchQuery) || []
- : contractList
+ const fuseSearchResult = fuse.search(searchQuery)
+ const addressSearchResult = contractList.filter(token => {
+ return token.address.toLowerCase() === searchQuery.toLowerCase()
+ })
+ const results = [...addressSearchResult, ...fuseSearchResult]
return Array(6).fill(undefined)
.map((_, i) => {
@@ -297,12 +303,12 @@ AddTokenScreen.prototype.renderConfirmation = function () {
]),
]),
h('div.add-token__buttons', [
- h('button.btn-secondary', {
- onClick: () => addTokens(tokens).then(() => history.push(DEFAULT_ROUTE)),
- }, 'Add Tokens'),
- h('button.btn-tertiary', {
+ h('button.btn-cancel.add-token__button', {
onClick: () => this.setState({ isShowingConfirmation: false }),
}, 'Back'),
+ h('button.btn-clear.add-token__button', {
+ onClick: () => addTokens(tokens).then(() => history.push(DEFAULT_ROUTE)),
+ }, 'Add Tokens'),
]),
])
)
@@ -347,12 +353,12 @@ AddTokenScreen.prototype.render = function () {
]),
]),
h('div.add-token__buttons', [
- h('button.btn-secondary', {
- onClick: this.onNext,
- }, 'Next'),
- h('button.btn-tertiary', {
+ h('button.btn-cancel.add-token__button', {
onClick: () => history.goBack(),
}, 'Cancel'),
+ h('button.btn-clear.add-token__button', {
+ onClick: this.onNext,
+ }, 'Next'),
]),
])
)
diff --git a/ui/app/components/pages/import-account/json.js b/ui/app/components/pages/import-account/json.js
index 63a44b4b7..c7d232d30 100644
--- a/ui/app/components/pages/import-account/json.js
+++ b/ui/app/components/pages/import-account/json.js
@@ -24,14 +24,7 @@ JsonImportSubview.prototype.render = function () {
const { error } = this.props
return (
- h('div', {
- style: {
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- padding: '5px 15px 0px 15px',
- },
- }, [
+ h('div.new-account-import-form__json', [
h('p', 'Used by a variety of different clients'),
h('a.warning', { href: HELP_LINK, target: '_blank' }, 'File import not working? Click here!'),
@@ -40,28 +33,35 @@ JsonImportSubview.prototype.render = function () {
readAs: 'text',
onLoad: this.onLoad.bind(this),
style: {
- margin: '20px 0px 12px 20px',
+ margin: '20px 0px 12px 34%',
fontSize: '15px',
+ display: 'flex',
+ justifyContent: 'center',
},
}),
- h('input.large-input.letter-spacey', {
+ h('input.new-account-import-form__input-password', {
type: 'password',
placeholder: 'Enter password',
id: 'json-password-box',
onKeyPress: this.createKeyringOnEnter.bind(this),
- style: {
- width: 260,
- marginTop: 12,
- },
}),
- h('button.primary', {
- onClick: this.createNewKeychain.bind(this),
- style: {
- margin: 12,
- },
- }, 'Import'),
+ h('div.new-account-create-form__buttons', {}, [
+
+ h('button.new-account-create-form__button-cancel', {
+ onClick: () => this.props.goHome(),
+ }, [
+ 'CANCEL',
+ ]),
+
+ h('button.new-account-create-form__button-create', {
+ onClick: () => this.createNewKeychain.bind(this),
+ }, [
+ 'IMPORT',
+ ]),
+
+ ]),
error ? h('span.error', error) : null,
])
diff --git a/ui/app/components/pages/import-account/private-key.js b/ui/app/components/pages/import-account/private-key.js
index 217e6d9f9..a236d90ee 100644
--- a/ui/app/components/pages/import-account/private-key.js
+++ b/ui/app/components/pages/import-account/private-key.js
@@ -4,7 +4,7 @@ const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('../../../actions')
-module.exports = connect(mapStateToProps)(PrivateKeyImportView)
+module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView)
function mapStateToProps (state) {
return {
@@ -12,45 +12,49 @@ function mapStateToProps (state) {
}
}
+function mapDispatchToProps (dispatch) {
+ return {
+ goHome: () => dispatch(actions.goHome()),
+ importNewAccount: (strategy, [ privateKey ]) => {
+ dispatch(actions.importNewAccount(strategy, [ privateKey ]))
+ },
+ displayWarning: () => dispatch(actions.displayWarning(null)),
+ }
+}
+
inherits(PrivateKeyImportView, Component)
function PrivateKeyImportView () {
Component.call(this)
}
-PrivateKeyImportView.prototype.componentWillUnmount = function () {
- this.props.dispatch(actions.displayWarning(null))
-}
-
PrivateKeyImportView.prototype.render = function () {
- const { error } = this.props
+ const { error, goHome } = this.props
return (
- h('div', {
- style: {
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- padding: '5px 15px 0px 15px',
- },
- }, [
- h('span', 'Paste your private key string here'),
+ h('div.new-account-import-form__private-key', [
+ h('span.new-account-create-form__instruction', 'Paste your private key string here:'),
- h('input.large-input.letter-spacey', {
+ h('input.new-account-import-form__input-password', {
type: 'password',
id: 'private-key-box',
- onKeyPress: this.createKeyringOnEnter.bind(this),
- style: {
- width: 260,
- marginTop: 12,
- },
+ onKeyPress: () => this.createKeyringOnEnter(),
}),
- h('button.primary', {
- onClick: this.createNewKeychain.bind(this),
- style: {
- margin: 12,
- },
- }, 'Import'),
+ h('div.new-account-create-form__buttons', {}, [
+
+ h('button.new-account-create-form__button-cancel', {
+ onClick: () => goHome(),
+ }, [
+ 'CANCEL',
+ ]),
+
+ h('button.new-account-create-form__button-create', {
+ onClick: () => this.createNewKeychain(),
+ }, [
+ 'IMPORT',
+ ]),
+
+ ]),
error ? h('span.error', error) : null,
])
@@ -67,5 +71,6 @@ PrivateKeyImportView.prototype.createKeyringOnEnter = function (event) {
PrivateKeyImportView.prototype.createNewKeychain = function () {
const input = document.getElementById('private-key-box')
const privateKey = input.value
- this.props.dispatch(actions.importNewAccount('Private Key', [ privateKey ]))
+
+ this.props.importNewAccount('Private Key', [ privateKey ])
}
diff --git a/ui/app/components/pages/keychains/restore-vault.js b/ui/app/components/pages/keychains/restore-vault.js
index 5573f2dd2..749da9758 100644
--- a/ui/app/components/pages/keychains/restore-vault.js
+++ b/ui/app/components/pages/keychains/restore-vault.js
@@ -52,7 +52,10 @@ class RestoreVaultPage extends PersistentForm {
// submit
this.props.createNewVaultAndRestore(password, seed)
.then(() => history.push(DEFAULT_ROUTE))
- .catch(({ message }) => this.setState({ error: message }))
+ .catch(({ message }) => {
+ this.setState({ error: message })
+ log.error(message)
+ })
}
render () {
diff --git a/ui/app/components/pages/settings/settings.js b/ui/app/components/pages/settings/settings.js
index 537270dee..fb3f20a95 100644
--- a/ui/app/components/pages/settings/settings.js
+++ b/ui/app/components/pages/settings/settings.js
@@ -11,6 +11,7 @@ const { exportAsFile } = require('../../../util')
const SimpleDropdown = require('../../dropdowns/simple-dropdown')
const ToggleButton = require('react-toggle-button')
const { REVEAL_SEED_ROUTE } = require('../../../routes')
+const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
const getInfuraCurrencyOptions = () => {
const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => {
@@ -230,18 +231,18 @@ class Settings extends Component {
}
render () {
- const { warning } = this.props
+ const { warning, isMascara } = this.props
return (
h('div.settings__content', [
warning && h('div.settings__error', warning),
- this.renderBlockieOptIn(),
this.renderCurrentConversion(),
// this.renderCurrentProvider(),
this.renderNewRpcUrl(),
this.renderStateLogs(),
this.renderSeedWords(),
- this.renderOldUI(),
+ !isMascara && this.renderOldUI(),
+ this.renderBlockieOptIn(),
])
)
}
@@ -257,12 +258,14 @@ Settings.propTypes = {
setFeatureFlagToBeta: PropTypes.func,
warning: PropTypes.string,
history: PropTypes.object,
+ isMascara: PropTypes.bool,
}
const mapStateToProps = state => {
return {
metamask: state.metamask,
warning: state.appState.warning,
+ isMascara: state.metamask.isMascara,
}
}
@@ -273,7 +276,10 @@ const mapDispatchToProps = dispatch => {
displayWarning: warning => dispatch(actions.displayWarning(warning)),
revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()),
setUseBlockie: value => dispatch(actions.setUseBlockie(value)),
- setFeatureFlagToBeta: () => dispatch(actions.setFeatureFlag('betaUI', false)),
+ setFeatureFlagToBeta: () => {
+ return dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
+ .then(() => dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
+ },
}
}
diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js
index 8a167f7cd..e63415194 100644
--- a/ui/app/components/pending-tx/confirm-send-ether.js
+++ b/ui/app/components/pending-tx/confirm-send-ether.js
@@ -231,8 +231,8 @@ ConfirmSendEther.prototype.render = function () {
// 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', {
- onClick: () => this.editTransaction(txMeta),
+ h('button.btn-clear.confirm-screen-back-button', {
+ onClick: () => editTransaction(txMeta),
}, 'EDIT'),
h('div.confirm-screen-title', 'Confirm Transaction'),
h('div.confirm-screen-header-tip'),
@@ -433,7 +433,9 @@ ConfirmSendEther.prototype.onSubmit = function (event) {
ConfirmSendEther.prototype.cancel = function (event, txMeta) {
event.preventDefault()
- this.props.cancelTransaction(txMeta)
+ const { cancelTransaction } = this.props
+
+ cancelTransaction(txMeta)
.then(() => this.props.history.push(DEFAULT_ROUTE))
}
@@ -458,26 +460,6 @@ ConfirmSendEther.prototype.gatherTxMeta = function () {
const state = this.state
const txData = clone(state.txData) || clone(props.txData)
- if (props.send.editingTransactionId) {
- const {
- send: {
- memo,
- amount: value,
- gasLimit: gas,
- gasPrice,
- },
- } = props
- const { txParams: { from, to } } = txData
- txData.txParams = {
- from: ethUtil.addHexPrefix(from),
- to: ethUtil.addHexPrefix(to),
- memo: memo && ethUtil.addHexPrefix(memo),
- value: ethUtil.addHexPrefix(value),
- gas: ethUtil.addHexPrefix(gas),
- gasPrice: ethUtil.addHexPrefix(gasPrice),
- }
- }
-
// 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 8087e431f..da3a92fa8 100644
--- a/ui/app/components/pending-tx/confirm-send-token.js
+++ b/ui/app/components/pending-tx/confirm-send-token.js
@@ -4,7 +4,6 @@ const { withRouter } = require('react-router-dom')
const { compose } = require('recompose')
const h = require('react-hyperscript')
const inherits = require('util').inherits
-const ethAbi = require('ethereumjs-abi')
const tokenAbi = require('human-standard-token-abi')
const abiDecoder = require('abi-decoder')
abiDecoder.addABI(tokenAbi)
@@ -305,6 +304,7 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () {
}
ConfirmSendToken.prototype.render = function () {
+ const { editTransaction } = this.props
const txMeta = this.gatherTxMeta()
const {
from: {
@@ -326,8 +326,8 @@ ConfirmSendToken.prototype.render = function () {
// 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', {
- onClick: () => this.editTransaction(txMeta),
+ h('button.btn-clear.confirm-screen-back-button', {
+ onClick: () => editTransaction(txMeta),
}, 'EDIT'),
h('div.confirm-screen-title', 'Confirm Transaction'),
h('div.confirm-screen-header-tip'),
@@ -426,7 +426,9 @@ ConfirmSendToken.prototype.onSubmit = function (event) {
ConfirmSendToken.prototype.cancel = function (event, txMeta) {
event.preventDefault()
- this.props.cancelTransaction(txMeta)
+ const { cancelTransaction } = this.props
+
+ cancelTransaction(txMeta)
.then(() => this.props.history.push(DEFAULT_ROUTE))
}
@@ -451,39 +453,6 @@ ConfirmSendToken.prototype.gatherTxMeta = function () {
const state = this.state
const txData = clone(state.txData) || clone(props.txData)
- if (props.send.editingTransactionId) {
- const {
- send: {
- memo,
- amount,
- gasLimit: gas,
- gasPrice,
- to,
- },
- } = props
-
- const { txParams: { from, to: tokenAddress } } = txData
-
- const tokenParams = {
- from: ethUtil.addHexPrefix(from),
- value: '0',
- gas: ethUtil.addHexPrefix(gas),
- gasPrice: ethUtil.addHexPrefix(gasPrice),
- }
-
- const data = '0xa9059cbb' + Array.prototype.map.call(
- ethAbi.rawEncode(['address', 'uint256'], [to, ethUtil.addHexPrefix(amount)]),
- x => ('00' + x.toString(16)).slice(-2)
- ).join('')
-
- txData.txParams = {
- ...tokenParams,
- to: ethUtil.addHexPrefix(tokenAddress),
- memo: memo && ethUtil.addHexPrefix(memo),
- data,
- }
- }
-
// log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
return txData
}
diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js
index 806c33f0a..0c4c3f7a9 100644
--- a/ui/app/components/send/gas-fee-display-v2.js
+++ b/ui/app/components/send/gas-fee-display-v2.js
@@ -32,8 +32,9 @@ GasFeeDisplay.prototype.render = function () {
})
: h('div.currency-display', 'Loading...'),
- h('div.send-v2__sliders-icon-container', {
+ h('button.send-v2__sliders-icon-container', {
onClick,
+ disabled: !gasTotal,
}, [
h('i.fa.fa-sliders.send-v2__sliders-icon'),
]),
diff --git a/ui/app/components/send/send-constants.js b/ui/app/components/send/send-constants.js
index 9c240972f..b3ee0899a 100644
--- a/ui/app/components/send/send-constants.js
+++ b/ui/app/components/send/send-constants.js
@@ -20,6 +20,8 @@ const MIN_GAS_TOTAL = multiplyCurrencies(MIN_GAS_LIMIT_HEX, MIN_GAS_PRICE_HEX, {
multiplierBase: 16,
})
+const TOKEN_TRANSFER_FUNCTION_SIGNATURE = '0xa9059cbb'
+
module.exports = {
MIN_GAS_PRICE_GWEI,
MIN_GAS_PRICE_HEX,
@@ -27,4 +29,5 @@ module.exports = {
MIN_GAS_LIMIT_HEX,
MIN_GAS_LIMIT_DEC,
MIN_GAS_TOTAL,
+ TOKEN_TRANSFER_FUNCTION_SIGNATURE,
}
diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js
index 5998bd252..1ebbe597c 100644
--- a/ui/app/components/send/send-v2-container.js
+++ b/ui/app/components/send/send-v2-container.js
@@ -55,6 +55,8 @@ function mapStateToProps (state) {
data,
amountConversionRate: selectedToken ? tokenToFiatRate : conversionRate,
tokenContract: getSelectedTokenContract(state),
+ unapprovedTxs: state.metamask.unapprovedTxs,
+ network: state.metamask.network,
}
}
@@ -69,6 +71,7 @@ function mapDispatchToProps (dispatch) {
),
signTx: txParams => dispatch(actions.signTx(txParams)),
updateAndApproveTx: txParams => dispatch(actions.updateAndApproveTx(txParams)),
+ updateTx: txData => dispatch(actions.updateTransaction(txData)),
setSelectedAddress: address => dispatch(actions.setSelectedAddress(address)),
addToAddressBook: address => dispatch(actions.addToAddressBook(address)),
updateGasTotal: newTotal => dispatch(actions.updateGasTotal(newTotal)),
@@ -82,7 +85,6 @@ function mapDispatchToProps (dispatch) {
updateSendErrors: newError => dispatch(actions.updateSendErrors(newError)),
goHome: () => dispatch(actions.goHome()),
clearSend: () => dispatch(actions.clearSend()),
- backToConfirmScreen: editingTransactionId => dispatch(actions.showConfTxPage({ id: editingTransactionId })),
setMaxModeTo: bool => dispatch(actions.setMaxModeTo(bool)),
}
}
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
index c5993e3d3..2270b8236 100644
--- a/ui/app/components/shapeshift-form.js
+++ b/ui/app/components/shapeshift-form.js
@@ -1,308 +1,242 @@
-const PersistentForm = require('../../lib/persistent-form')
const h = require('react-hyperscript')
const inherits = require('util').inherits
+const Component = require('react').Component
const connect = require('react-redux').connect
-const actions = require('../actions')
-const Qr = require('./qr-code')
-const isValidAddress = require('../util').isValidAddress
-module.exports = connect(mapStateToProps)(ShapeshiftForm)
+const classnames = require('classnames')
+const { qrcode } = require('qrcode-npm')
+const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../actions')
+const { isValidAddress } = require('../util')
+const SimpleDropdown = require('./dropdowns/simple-dropdown')
function mapStateToProps (state) {
+ const {
+ coinOptions,
+ tokenExchangeRates,
+ selectedAddress,
+ } = state.metamask
+
return {
- warning: state.appState.warning,
- isSubLoading: state.appState.isSubLoading,
- qrRequested: state.appState.qrRequested,
+ coinOptions,
+ tokenExchangeRates,
+ selectedAddress,
}
}
-inherits(ShapeshiftForm, PersistentForm)
+function mapDispatchToProps (dispatch) {
+ return {
+ shapeShiftSubview: () => dispatch(shapeShiftSubview()),
+ pairUpdate: coin => dispatch(pairUpdate(coin)),
+ buyWithShapeShift: data => dispatch(buyWithShapeShift(data)),
+ }
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(ShapeshiftForm)
+inherits(ShapeshiftForm, Component)
function ShapeshiftForm () {
- PersistentForm.call(this)
- this.persistentFormParentId = 'shapeshift-buy-form'
+ Component.call(this)
+
+ this.state = {
+ depositCoin: 'btc',
+ refundAddress: '',
+ showQrCode: false,
+ depositAddress: '',
+ errorMessage: '',
+ isLoading: false,
+ bought: false,
+ }
}
-ShapeshiftForm.prototype.render = function () {
- return this.props.qrRequested ? h(Qr, {key: 'qr'}) : this.renderMain()
+ShapeshiftForm.prototype.componentWillMount = function () {
+ this.props.shapeShiftSubview()
}
-ShapeshiftForm.prototype.renderMain = function () {
- const marketinfo = this.props.buyView.formView.marketinfo
- const coinOptions = this.props.buyView.formView.coinOptions
- var coin = marketinfo.pair.split('_')[0].toUpperCase()
-
- return h('.flex-column', {
- style: {
- position: 'relative',
- padding: '25px',
- paddingTop: '5px',
- width: '90%',
- minHeight: '215px',
- alignItems: 'center',
- overflowY: 'auto',
- },
- }, [
- h('.flex-row', {
- style: {
- justifyContent: 'center',
- alignItems: 'baseline',
- height: '42px',
- },
- }, [
- h('img', {
- src: coinOptions[coin].image,
- width: '25px',
- height: '25px',
- style: {
- marginRight: '5px',
- },
- }),
-
- h('.input-container', {
- position: 'relative',
- }, [
- h('input#fromCoin.buy-inputs.ex-coins', {
- type: 'text',
- list: 'coinList',
- autoFocus: true,
- dataset: {
- persistentFormId: 'input-coin',
- },
- style: {
- boxSizing: 'border-box',
- },
- onChange: this.handleLiveInput.bind(this),
- defaultValue: 'BTC',
- }),
+ShapeshiftForm.prototype.onCoinChange = function (e) {
+ const coin = e.target.value
+ this.setState({
+ depositCoin: coin,
+ errorMessage: '',
+ })
+ this.props.pairUpdate(coin)
+}
- this.renderCoinList(),
+ShapeshiftForm.prototype.onBuyWithShapeShift = function () {
+ this.setState({
+ isLoading: true,
+ showQrCode: true,
+ })
- h('i.fa.fa-pencil-square-o.edit-text', {
- style: {
- fontSize: '12px',
- color: '#F7861C',
- position: 'absolute',
- },
- }),
- ]),
+ const {
+ buyWithShapeShift,
+ selectedAddress: withdrawal,
+ } = this.props
+ const {
+ refundAddress: returnAddress,
+ depositCoin,
+ } = this.state
+ const pair = `${depositCoin}_eth`
+ const data = {
+ withdrawal,
+ pair,
+ returnAddress,
+ // Public api key
+ 'apiKey': '803d1f5df2ed1b1476e4b9e6bcd089e34d8874595dda6a23b67d93c56ea9cc2445e98a6748b219b2b6ad654d9f075f1f1db139abfa93158c04e825db122c14b6',
+ }
- h('.icon-control', {
- style: {
- position: 'relative',
- },
- }, [
- // Not visible on the screen, can't see it on master.
-
- // h('i.fa.fa-refresh.fa-4.orange', {
- // style: {
- // bottom: '5px',
- // left: '5px',
- // color: '#F7861C',
- // },
- // onClick: this.updateCoin.bind(this),
- // }),
- h('i.fa.fa-chevron-right.fa-4.orange', {
- style: {
- position: 'absolute',
- bottom: '35%',
- left: '0%',
- color: '#F7861C',
- },
- onClick: this.updateCoin.bind(this),
- }),
- ]),
+ if (isValidAddress(withdrawal)) {
+ buyWithShapeShift(data)
+ .then(d => this.setState({
+ showQrCode: true,
+ depositAddress: d.deposit,
+ isLoading: false,
+ }))
+ .catch(() => this.setState({
+ showQrCode: false,
+ errorMessage: 'Invalid Request',
+ isLoading: false,
+ }))
+ }
+}
- h('#toCoin.ex-coins', marketinfo.pair.split('_')[1].toUpperCase()),
+ShapeshiftForm.prototype.renderMetadata = function (label, value) {
+ return h('div', {className: 'shapeshift-form__metadata-wrapper'}, [
- h('img', {
- src: coinOptions[marketinfo.pair.split('_')[1].toUpperCase()].image,
- width: '25px',
- height: '25px',
- style: {
- marginLeft: '5px',
- },
- }),
+ h('div.shapeshift-form__metadata-label', {}, [
+ h('span', `${label}:`),
]),
- h('.flex-column', {
- style: {
- marginTop: '1%',
- alignItems: 'flex-start',
- },
- }, [
- this.props.warning ?
- this.props.warning &&
- h('span.error.flex-center', {
- style: {
- textAlign: 'center',
- width: '229px',
- height: '82px',
- },
- }, this.props.warning)
- : this.renderInfo(),
-
- this.renderRefundAddressForCoin(coin),
+ h('div.shapeshift-form__metadata-value', {}, [
+ h('span', value),
]),
])
}
-ShapeshiftForm.prototype.renderRefundAddressForCoin = function (coin) {
- return h(this.activeToggle('.input-container'), {
- style: {
- marginTop: '1%',
- },
- }, [
-
- h('div', `${coin} Address:`),
-
- h('input#fromCoinAddress.buy-inputs', {
- type: 'text',
- placeholder: `Your ${coin} Refund Address`,
- dataset: {
- persistentFormId: 'refund-address',
-
- },
- style: {
- boxSizing: 'border-box',
- width: '227px',
- height: '30px',
- padding: ' 5px ',
- },
- }),
-
- h('i.fa.fa-pencil-square-o.edit-text', {
- style: {
- fontSize: '12px',
- color: '#F7861C',
- position: 'absolute',
- },
- }),
- h('div.flex-row', {
- style: {
- justifyContent: 'flex-start',
- },
- }, [
- h('button', {
- onClick: this.shift.bind(this),
- style: {
- marginTop: '1%',
- },
- },
- 'Submit'),
- ]),
+ShapeshiftForm.prototype.renderMarketInfo = function () {
+ const { depositCoin } = this.state
+ const coinPair = `${depositCoin}_eth`
+ const { tokenExchangeRates } = this.props
+ const {
+ limit,
+ rate,
+ minimum,
+ } = tokenExchangeRates[coinPair] || {}
+
+ 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),
+
])
}
-ShapeshiftForm.prototype.shift = function () {
- var props = this.props
- var withdrawal = this.props.buyView.buyAddress
- var returnAddress = document.getElementById('fromCoinAddress').value
- var pair = this.props.buyView.formView.marketinfo.pair
- var data = {
- 'withdrawal': withdrawal,
- 'pair': pair,
- 'returnAddress': returnAddress,
- // Public api key
- 'apiKey': '803d1f5df2ed1b1476e4b9e6bcd089e34d8874595dda6a23b67d93c56ea9cc2445e98a6748b219b2b6ad654d9f075f1f1db139abfa93158c04e825db122c14b6',
- }
- var message = [
- `Deposit Limit: ${props.buyView.formView.marketinfo.limit}`,
- `Deposit Minimum:${props.buyView.formView.marketinfo.minimum}`,
- ]
- if (isValidAddress(withdrawal)) {
- this.props.dispatch(actions.coinShiftRquest(data, message))
- }
-}
+ShapeshiftForm.prototype.renderQrCode = function () {
+ const { depositAddress, isLoading } = this.state
+ const qrImage = qrcode(4, 'M')
+ qrImage.addData(depositAddress)
+ qrImage.make()
-ShapeshiftForm.prototype.renderCoinList = function () {
- var list = Object.keys(this.props.buyView.formView.coinOptions).map((item) => {
- return h('option', {
- value: item,
- }, item)
- })
+ return h('div.shapeshift-form', {}, [
- return h('datalist#coinList', {
- onClick: (event) => {
- event.preventDefault()
- },
- }, list)
-}
+ h('div.shapeshift-form__deposit-instruction', [
+ 'Deposit your BTC to the address below:',
+ ]),
-ShapeshiftForm.prototype.updateCoin = function (event) {
- event.preventDefault()
- const props = this.props
- var coinOptions = this.props.buyView.formView.coinOptions
- var coin = document.getElementById('fromCoin').value
-
- if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') {
- var message = 'Not a valid coin'
- return props.dispatch(actions.displayWarning(message))
- } else {
- return props.dispatch(actions.pairUpdate(coin))
- }
-}
+ h('div', depositAddress),
-ShapeshiftForm.prototype.handleLiveInput = function () {
- const props = this.props
- var coinOptions = this.props.buyView.formView.coinOptions
- var coin = document.getElementById('fromCoin').value
+ h('div.shapeshift-form__qr-code', [
+ isLoading
+ ? h('img', {
+ src: 'images/loading.svg',
+ style: { width: '60px'},
+ })
+ : h('div', {
+ dangerouslySetInnerHTML: { __html: qrImage.createTableTag(4) },
+ }),
+ ]),
- if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') {
- return null
- } else {
- return props.dispatch(actions.pairUpdate(coin))
- }
-}
+ this.renderMarketInfo(),
-ShapeshiftForm.prototype.renderInfo = function () {
- const marketinfo = this.props.buyView.formView.marketinfo
- const coinOptions = this.props.buyView.formView.coinOptions
- var coin = marketinfo.pair.split('_')[0].toUpperCase()
-
- return h('span', {
- style: {
- },
- }, [
- h('h3.flex-row.text-transform-uppercase', {
- style: {
- color: '#868686',
- paddingTop: '4px',
- justifyContent: 'space-around',
- textAlign: 'center',
- fontSize: '17px',
- },
- }, `Market Info for ${marketinfo.pair.replace('_', ' to ').toUpperCase()}:`),
- h('.marketinfo', ['Status : ', `${coinOptions[coin].status}`]),
- h('.marketinfo', ['Exchange Rate: ', `${marketinfo.rate}`]),
- h('.marketinfo', ['Limit: ', `${marketinfo.limit}`]),
- h('.marketinfo', ['Minimum : ', `${marketinfo.minimum}`]),
])
}
-ShapeshiftForm.prototype.activeToggle = function (elementType) {
- if (!this.props.buyView.formView.response || this.props.warning) return elementType
- return `${elementType}.inactive`
-}
-ShapeshiftForm.prototype.renderLoading = function () {
- return h('span', {
- style: {
- position: 'absolute',
- left: '70px',
- bottom: '194px',
- background: 'transparent',
- width: '229px',
- height: '82px',
- display: 'flex',
- justifyContent: 'center',
- },
- }, [
- h('img', {
- style: {
- width: '60px',
- },
- src: 'images/loading.svg',
- }),
- ])
+ShapeshiftForm.prototype.render = function () {
+ const { coinOptions, btnClass } = this.props
+ const { depositCoin, errorMessage, showQrCode, depositAddress } = this.state
+ const coinPair = `${depositCoin}_eth`
+ const { tokenExchangeRates } = this.props
+ const token = tokenExchangeRates[coinPair]
+
+ return h('div.shapeshift-form-wrapper', [
+ showQrCode
+ ? this.renderQrCode()
+ : h('div.shapeshift-form', [
+ h('div.shapeshift-form__selectors', [
+
+ h('div.shapeshift-form__selector', [
+
+ h('div.shapeshift-form__selector-label', 'Deposit'),
+
+ h(SimpleDropdown, {
+ selectedOption: this.state.depositCoin,
+ onSelect: this.onCoinChange,
+ options: Object.entries(coinOptions).map(([coin]) => ({
+ value: coin.toLowerCase(),
+ displayValue: coin,
+ })),
+ }),
+
+ ]),
+
+ h('div.icon.shapeshift-form__caret', {
+ style: { backgroundImage: 'url(images/caret-right.svg)'},
+ }),
+
+ h('div.shapeshift-form__selector', [
+
+ h('div.shapeshift-form__selector-label', [
+ 'Receive',
+ ]),
+
+ h('div.shapeshift-form__selector-input', ['ETH']),
+
+ ]),
+
+ ]),
+
+ h('div', {
+ className: classnames('shapeshift-form__address-input-wrapper', {
+ 'shapeshift-form__address-input-wrapper--error': errorMessage,
+ }),
+ }, [
+
+ h('div.shapeshift-form__address-input-label', [
+ 'Your Refund Address',
+ ]),
+
+ h('input.shapeshift-form__address-input', {
+ type: 'text',
+ onChange: e => this.setState({
+ refundAddress: e.target.value,
+ errorMessage: '',
+ }),
+ }),
+
+ h('divshapeshift-form__address-input-error-message', [errorMessage]),
+ ]),
+
+ this.renderMarketInfo(),
+
+ ]),
+
+ !depositAddress && h('button.shapeshift-form__shapeshift-buy-btn', {
+ className: btnClass,
+ disabled: !token,
+ onClick: () => this.onBuyWithShapeShift(),
+ }, ['Buy']),
+
+ ])
}
diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js
index 43973de63..111a77df4 100644
--- a/ui/app/components/shift-list-item.js
+++ b/ui/app/components/shift-list-item.js
@@ -16,6 +16,7 @@ module.exports = connect(mapStateToProps)(ShiftListItem)
function mapStateToProps (state) {
return {
+ selectedAddress: state.metamask.selectedAddress,
conversionRate: state.metamask.conversionRate,
currentCurrency: state.metamask.currentCurrency,
}
@@ -28,36 +29,39 @@ function ShiftListItem () {
}
ShiftListItem.prototype.render = function () {
+ const { selectedAddress, receivingAddress } = this.props
return (
- h('div.tx-list-item.tx-list-clickable', {
- style: {
- paddingTop: '20px',
- paddingBottom: '20px',
- justifyContent: 'space-around',
- alignItems: 'center',
- },
- }, [
- h('div', {
+ selectedAddress === receivingAddress
+ ? h('div.tx-list-item.tx-list-clickable', {
style: {
- width: '0px',
- position: 'relative',
- bottom: '19px',
+ paddingTop: '20px',
+ paddingBottom: '20px',
+ justifyContent: 'space-around',
+ alignItems: 'center',
},
}, [
- h('img', {
- src: 'https://info.shapeshift.io/sites/default/files/logo.png',
+ h('div', {
style: {
- height: '35px',
- width: '132px',
- position: 'absolute',
- clip: 'rect(0px,23px,34px,0px)',
+ width: '0px',
+ position: 'relative',
+ bottom: '19px',
},
- }),
- ]),
+ }, [
+ h('img', {
+ src: 'https://info.shapeshift.io/sites/default/files/logo.png',
+ style: {
+ height: '35px',
+ width: '132px',
+ position: 'absolute',
+ clip: 'rect(0px,23px,34px,0px)',
+ },
+ }),
+ ]),
- this.renderInfo(),
- this.renderUtilComponents(),
- ])
+ this.renderInfo(),
+ this.renderUtilComponents(),
+ ])
+ : null
)
}
diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js
index b40c0ec0d..59552f4a0 100644
--- a/ui/app/components/token-cell.js
+++ b/ui/app/components/token-cell.js
@@ -86,7 +86,9 @@ TokenCell.prototype.render = function () {
numberOfDecimals: 2,
conversionRate: currentTokenToFiatRate,
})
- formattedFiat = `${currentTokenInFiat} ${currentCurrency.toUpperCase()}`
+ formattedFiat = currentTokenInFiat.toString() === '0'
+ ? ''
+ : `${currentTokenInFiat} ${currentCurrency.toUpperCase()}`
}
const showFiat = Boolean(currentTokenInFiat) && currentCurrency.toUpperCase() !== symbol
@@ -104,7 +106,7 @@ TokenCell.prototype.render = function () {
h(Identicon, {
className: 'token-list-item__identicon',
- diameter: 45,
+ diameter: 50,
address,
network,
}),
diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js
index 255f0e5eb..4e3d2cb93 100644
--- a/ui/app/components/transaction-list-item.js
+++ b/ui/app/components/transaction-list-item.js
@@ -1,6 +1,7 @@
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
@@ -9,18 +10,33 @@ 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')
-module.exports = TransactionListItem
+
+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)
}
@@ -32,7 +48,7 @@ TransactionListItem.prototype.render = function () {
var isMsg = ('msgParams' in transaction)
var isTx = ('txParams' in transaction)
- var isPending = transaction.status === 'unapproved'
+ var isPending = status === 'unapproved'
let txParams
if (isTx) {
txParams = transaction.txParams
@@ -44,7 +60,7 @@ TransactionListItem.prototype.render = function () {
const isClickable = ('hash' in transaction && isLinkable) || isPending
return (
- h(`.transaction-list-item.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, {
+ h('.transaction-list-item.flex-column', {
onClick: (event) => {
if (isPending) {
this.props.showTx(transaction.id)
@@ -56,51 +72,92 @@ TransactionListItem.prototype.render = function () {
},
style: {
padding: '20px 0',
+ alignItems: 'center',
},
}, [
-
- h('.identicon-wrapper.flex-column.flex-center.select-none', [
- h(TransactionIcon, { txParams, transaction, isTx, isMsg }),
+ 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'),
]),
- h(Tooltip, {
- title: 'Transaction Number',
- position: 'right',
+ 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('span', {
+ h('div', {
style: {
- display: 'flex',
- cursor: 'normal',
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'center',
- padding: '10px',
+ paddingRight: '2px',
},
- }, nonce),
- ]),
-
- h('.flex-column', {style: {width: '200px', overflow: 'hidden'}}, [
- domainField(txParams),
- h('div', date),
- recipientField(txParams, transaction, isTx, isMsg),
+ }, 'Taking too long?'),
+ h('div', {
+ style: {
+ textDecoration: 'underline',
+ },
+ }, 'Retry with a higher gas price here'),
]),
-
- // 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'),
])
)
}
+TransactionListItem.prototype.resubmit = function () {
+ const { transaction } = this.props
+ this.props.retryTransaction(transaction.id)
+}
+
function domainField (txParams) {
return h('div', {
style: {
diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js
index 4e76147a1..7ccc5c315 100644
--- a/ui/app/components/tx-list-item.js
+++ b/ui/app/components/tx-list-item.js
@@ -170,6 +170,7 @@ TxListItem.prototype.getSendTokenTotal = async function () {
TxListItem.prototype.render = function () {
const {
transactionStatus,
+ transactionAmount,
onClick,
transActionId,
dateString,
@@ -177,6 +178,7 @@ TxListItem.prototype.render = function () {
className,
} = this.props
const { total, fiatTotal } = this.state
+ const showFiatTotal = transactionAmount !== '0x0' && fiatTotal
return h(`div${className || ''}`, {
key: transActionId,
@@ -232,13 +234,9 @@ TxListItem.prototype.render = function () {
style: {},
}, [
- h('span', {
- className: classnames('tx-list-value', {
- 'tx-list-value--confirmed': transactionStatus === 'confirmed',
- }),
- }, total),
+ h('span.tx-list-value', total),
- fiatTotal && h('span.tx-list-fiat-value', fiatTotal),
+ showFiatTotal && h('span.tx-list-fiat-value', fiatTotal),
]),
]),
diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js
index 2c4c3dd31..ca4fd81d6 100644
--- a/ui/app/components/tx-list.js
+++ b/ui/app/components/tx-list.js
@@ -42,23 +42,22 @@ TxList.prototype.componentWillMount = function () {
}
TxList.prototype.render = function () {
- return h('div.flex-column.tx-list-container', {}, [
-
+ return h('div.flex-column', [
h('div.flex-row.tx-list-header-wrapper', [
h('div.flex-row.tx-list-header', [
h('div', 'transactions'),
]),
]),
-
- this.renderTransaction(),
-
+ h('div.flex-column.tx-list-container', {}, [
+ this.renderTransaction(),
+ ]),
])
}
TxList.prototype.renderTransaction = function () {
const { txsToRender, conversionRate } = this.props
return txsToRender.length
- ? txsToRender.map((transaction, i) => this.renderTransactionListItem(transaction, conversionRate))
+ ? txsToRender.map((transaction, i) => this.renderTransactionListItem(transaction, conversionRate, i))
: [h(
'div.tx-list-item.tx-list-item--empty',
{ key: 'tx-list-none' },
@@ -67,12 +66,16 @@ TxList.prototype.renderTransaction = function () {
}
// TODO: Consider moving TxListItem into a separate component
-TxList.prototype.renderTransactionListItem = function (transaction, conversionRate) {
+TxList.prototype.renderTransactionListItem = function (transaction, conversionRate, index) {
// console.log({transaction})
// refer to transaction-list.js:line 58
if (transaction.key === 'shapeshift') {
- return h(ShiftListItem, transaction)
+ return h('div', {
+ key: `shapeshift${index}`,
+ }, [
+ h(ShiftListItem, transaction),
+ ])
}
const props = {
diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js
index 46029166e..60c108c36 100644
--- a/ui/app/components/tx-view.js
+++ b/ui/app/components/tx-view.js
@@ -74,18 +74,14 @@ TxView.prototype.renderButtons = function () {
return !selectedToken
? (
h('div.flex-row.flex-center.hero-balance-buttons', [
- h('button.btn-clear', {
- style: {
- textAlign: 'center',
- },
+ h('button.btn-clear.hero-balance-button', {
onClick: () => showModal({
- name: 'BUY',
+ name: 'DEPOSIT_ETHER',
}),
}, 'DEPOSIT'),
- h('button.btn-clear', {
+ h('button.btn-clear.hero-balance-button', {
style: {
- textAlign: 'center',
marginLeft: '0.8em',
},
onClick: () => history.push(SEND_ROUTE),
@@ -94,11 +90,7 @@ TxView.prototype.renderButtons = function () {
)
: (
h('div.flex-row.flex-center.hero-balance-buttons', [
- h('button.btn-clear', {
- style: {
- textAlign: 'center',
- marginLeft: '0.8em',
- },
+ h('button.btn-clear.hero-balance-button', {
onClick: () => history.push(SEND_ROUTE),
}, 'SEND'),
])
@@ -114,7 +106,7 @@ TxView.prototype.render = function () {
h('div.flex-row.phone-visible', {
style: {
- margin: '1em 0.9em',
+ margin: '1.5em 1.2em 0',
justifyContent: 'space-between',
alignItems: 'center',
},
@@ -150,7 +142,7 @@ TxView.prototype.render = function () {
!isMascara && h('div.open-in-browser', {
onClick: () => global.platform.openExtensionInBrowser(),
- }, [h('img', { src: 'images/open.svg' })]),
+ }, [h('img', { src: 'images/popout.svg' })]),
]),
diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js
index 72ffc5d65..c7f81a305 100644
--- a/ui/app/components/wallet-view.js
+++ b/ui/app/components/wallet-view.js
@@ -136,7 +136,7 @@ WalletView.prototype.render = function () {
selectedIdentity.name,
]),
- h('button.wallet-view__details-button', 'DETAILS'),
+ h('button.btn-clear.wallet-view__details-button', 'DETAILS'),
]),
]),
@@ -157,7 +157,7 @@ WalletView.prototype.render = function () {
h(TokenList),
- h('button.wallet-view__add-token-button', {
+ h('button.btn-clear.wallet-view__add-token-button', {
onClick: () => history.push(ADD_TOKEN_ROUTE),
}, 'Add Token'),
])
diff --git a/ui/app/css/itcss/components/add-token.scss b/ui/app/css/itcss/components/add-token.scss
index 5f6d0fcff..13020f62f 100644
--- a/ui/app/css/itcss/components/add-token.scss
+++ b/ui/app/css/itcss/components/add-token.scss
@@ -94,6 +94,7 @@
padding: 12px 0;
font-weight: 600;
cursor: pointer;
+ position: relative;
&:hover {
background-color: rgba(0, 0, 0, .05);
@@ -164,9 +165,18 @@
&__buttons {
display: flex;
- flex-flow: column nowrap;
+ flex-flow: row nowrap;
margin: 30px 0 51px;
flex: 0 0 auto;
+ align-items: center;
+ justify-content: center;
+ }
+
+ &__button {
+ flex: 1 0 141px;
+ margin: 0 12px;
+ padding: 10px 22px;
+ height: 54px;
}
&__token-icons-container {
@@ -324,18 +334,10 @@
}
&__buttons {
- flex-flow: row nowrap;
- width: 100%;
- align-items: center;
- justify-content: center;
padding: 12px 0;
margin: 0;
border-top: 1px solid $gallery;
-
- button {
- flex: 1 0 auto;
- margin: 0 12px;
- }
+ width: 100%;
}
}
}
diff --git a/ui/app/css/itcss/components/buttons.scss b/ui/app/css/itcss/components/buttons.scss
index 8ba084b4a..1450b71cc 100644
--- a/ui/app/css/itcss/components/buttons.scss
+++ b/ui/app/css/itcss/components/buttons.scss
@@ -6,9 +6,43 @@
background-color: #02c9b1; // TODO: reusable color in colors.css
}
-button.btn-clear {
+.btn-clear {
background: $white;
- border: 1px solid;
+ text-align: center;
+ padding: .8rem 1rem;
+ color: $curious-blue;
+ border: 2px solid $spindle;
+ border-radius: 4px;
+ font-size: .85rem;
+ font-weight: 400;
+ transition: border-color .3s ease;
+
+ &:hover {
+ border-color: $curious-blue;
+ }
+
+ &--disabled,
+ &[disabled] {
+ cursor: auto;
+ opacity: .5;
+ pointer-events: none;
+ }
+}
+
+.btn-cancel {
+ background: $white;
+ text-align: center;
+ padding: .9rem 1rem;
+ color: $scorpion;
+ border: 2px solid $dusty-gray;
+ border-radius: 4px;
+ font-size: .85rem;
+ font-weight: 400;
+ transition: border-color .3s ease;
+
+ &:hover {
+ border-color: $scorpion;
+ }
}
// No longer used in flat design, remove when modal buttons done
diff --git a/ui/app/css/itcss/components/confirm.scss b/ui/app/css/itcss/components/confirm.scss
index 4a8232e39..255f66e66 100644
--- a/ui/app/css/itcss/components/confirm.scss
+++ b/ui/app/css/itcss/components/confirm.scss
@@ -2,13 +2,15 @@
position: relative;
align-items: center;
font-family: Roboto;
- flex: 0 0 auto;
+ flex: 1 0 auto;
flex-flow: column nowrap;
box-shadow: 0 2px 4px 0 rgba($black, .08);
border-radius: 8px;
+ display: flex;
@media screen and (max-width: 575px) {
width: 100%;
+ box-shadow: initial;
}
@media screen and (min-width: 576px) {
@@ -102,15 +104,10 @@
.confirm-screen-back-button {
background: transparent;
- border: 1px solid $curious-blue;
left: 24px;
position: absolute;
- text-align: center;
- color: $curious-blue;
- padding: 6px 13px 7px 12px;
- border-radius: 2px;
- height: 30px;
- width: 54px;
+ padding: 6px 12px;
+ font-size: .7rem;
@media screen and (max-width: $break-small) {
margin-right: 12px;
@@ -277,8 +274,8 @@ section .confirm-screen-account-number,
}
.confirm-screen-confirm-button {
- height: 62px;
- border-radius: 2px;
+ height: 50px;
+ border-radius: 4px;
background-color: #02c9b1;
font-size: 16px;
color: $white;
@@ -290,11 +287,11 @@ section .confirm-screen-account-number,
box-shadow: none;
flex: 1 0 auto;
font-weight: 300;
- margin: 0 8px;
+ margin: 0 5px;
}
.btn-light.confirm-screen-cancel-button {
- height: 62px;
+ height: 50px;
background: none;
border: none;
opacity: 1;
@@ -303,12 +300,11 @@ section .confirm-screen-account-number,
padding-top: 15px;
padding-bottom: 15px;
font-size: 16px;
- line-height: 32px;
box-shadow: none;
cursor: pointer;
flex: 1 0 auto;
font-weight: 300;
- margin: 0 8px;
+ margin: 0 5px;
}
#pending-tx-form {
@@ -317,7 +313,7 @@ section .confirm-screen-account-number,
display: flex;
flex-flow: row nowrap;
background-color: $white;
- padding: 12px 18px;
+ padding: 12px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
width: 100%;
diff --git a/ui/app/css/itcss/components/header.scss b/ui/app/css/itcss/components/header.scss
index a6332f819..ac2cecf7e 100644
--- a/ui/app/css/itcss/components/header.scss
+++ b/ui/app/css/itcss/components/header.scss
@@ -17,7 +17,16 @@
@media screen and (min-width: 576px) {
height: 75px;
justify-content: center;
+ }
+
+ .metafox-icon {
+ cursor: pointer;
+ }
+}
+
+.app-header--initialized {
+ @media screen and (min-width: 576px) {
&::after {
content: '';
position: absolute;
@@ -27,10 +36,6 @@
bottom: -32px;
}
}
-
- .metafox-icon {
- cursor: pointer;
- }
}
.app-header-contents {
@@ -53,7 +58,7 @@
}
@media screen and (min-width: 1281px) {
- width: 65vw;
+ width: 62vw;
}
}
@@ -61,8 +66,10 @@
font-family: Roboto;
text-transform: uppercase;
font-weight: 400;
- color: #22232c; // $shark
- line-height: 29px;
+ font-size: 1.1rem;
+ position: relative;
+ padding-left: 15px;
+ color: #5b5d67;
@media screen and (max-width: 575px) {
display: none;
diff --git a/ui/app/css/itcss/components/hero-balance.scss b/ui/app/css/itcss/components/hero-balance.scss
index bdbdd2645..ccc9a0118 100644
--- a/ui/app/css/itcss/components/hero-balance.scss
+++ b/ui/app/css/itcss/components/hero-balance.scss
@@ -16,7 +16,8 @@
flex-direction: row;
justify-content: flex-start;
align-items: center;
- margin: 2.8em 2.37em .8em;
+ margin: 2.3em 2.37em .8em;
+ flex: 0 0 auto;
}
.balance-container {
@@ -37,13 +38,16 @@
}
.balance-display {
+ .token-amount {
+ color: $black;
+ }
@media screen and (max-width: $break-small) {
text-align: center;
.token-amount {
- font-size: 175%;
- margin-top: 12.5%;
+ font-size: 1.75rem;
+ margin-top: 1rem;
}
.fiat-amount {
@@ -54,12 +58,12 @@
}
@media screen and (min-width: $break-large) {
- margin-left: 3%;
+ margin-left: .8em;
justify-content: flex-start;
align-items: flex-start;
.token-amount {
- font-size: 135%;
+ font-size: 1.5rem;
}
.fiat-amount {
@@ -69,13 +73,6 @@
}
}
- .balance-icon {
- border-radius: 25px;
- width: 45px;
- height: 45px;
- border: 1px solid $alto;
- }
-
.hero-balance-buttons {
@media screen and (max-width: $break-small) {
@@ -89,26 +86,9 @@
flex-grow: 2;
justify-content: flex-end;
}
-
- button.btn-clear {
- background: $white;
- border: 1px solid;
- border-radius: 2px;
- font-size: 12px;
-
- @media screen and (max-width: $break-small) {
- border-color: $curious-blue;
- color: $curious-blue;
- height: 36px;
- }
-
- @media screen and (min-width: $break-large) {
- border-color: $curious-blue;
- color: $curious-blue;
- padding: 0;
- width: 85px;
- height: 34px;
- }
- }
}
}
+
+.hero-balance-button {
+ width: 6rem;
+}
diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss
index e1ec42c66..97f7ab785 100644
--- a/ui/app/css/itcss/components/index.scss
+++ b/ui/app/css/itcss/components/index.scss
@@ -53,3 +53,5 @@
@import './editable-label.scss';
@import './pages/index.scss';
+
+@import './new-account.scss';
diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss
index 9b64564d6..5bca4a07d 100644
--- a/ui/app/css/itcss/components/modal.scss
+++ b/ui/app/css/itcss/components/modal.scss
@@ -258,19 +258,10 @@
width: 286px;
}
- .btn-clear {
- min-height: 28px;
- font-size: 14px;
- border-color: $curious-blue;
- color: $curious-blue;
- border-radius: 2px;
- flex-basis: 100%;
- width: 75%;
+ .account-modal__button {
margin-top: 17px;
padding: 10px 22px;
- height: 44px;
width: 235px;
- font-family: Roboto;
}
}
@@ -346,17 +337,17 @@
display: flex;
flex-direction: row;
justify-content: center;
+}
- .btn-clear {
- width: 141px;
- height: 54px;
- }
+.export-private-key__button {
+ margin-top: 17px;
+ padding: 10px 22px;
+ width: 141px;
+ height: 54px;
+}
- .btn-cancel {
- margin-right: 15px;
- border-color: $dusty-gray;
- color: $scorpion;
- }
+.export-private-key__button--cancel {
+ margin-right: 15px;
}
.private-key-password-display-wrapper {
@@ -495,10 +486,9 @@
.hide-token-confirmation {
min-height: 250.72px;
- width: 374.49px;
border-radius: 4px;
- background-color: #FFFFFF;
- box-shadow: 0 1px 7px 0 rgba(0,0,0,0.5);
+ background-color: $white;
+ box-shadow: 0 1px 7px 0 rgba(0, 0, 0, .5);
&__container {
padding: 24px 27px 21px;
@@ -508,7 +498,7 @@
}
&__identicon {
- margin-bottom: 10px
+ margin-bottom: 10px;
}
&__symbol {
@@ -547,21 +537,264 @@
justify-content: center;
margin-top: 15px;
width: 100%;
+ }
+
+ &__button {
+ width: 141px;
+ margin: 0 5px;
+ }
+}
+
+//Notification Modal
+
+.notification-modal-wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+ position: relative;
+ border: 1px solid $alto;
+ box-shadow: 0 0 2px 2px $alto;
+ font-family: Roboto;
+}
+
+.notification-modal-header {
+ background: $wild-sand;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ padding: 30px;
+ font-size: 22px;
+ color: $nile-blue;
+ height: 79px;
+}
+
+.notification-modal-message {
+ padding: 20px;
+}
+
+.notification-modal-message {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ font-size: 17px;
+ color: $nile-blue;
+}
+
+// Deposit Ether Modal
+.deposit-ether-modal {
+ border-radius: 8px;
+ font-family: Roboto;
+ display: flex;
+ flex-flow: column;
+ height: 100%;
+
+ &__header {
+ width: 100%;
+ border-radius: 8px 8px 0 0;
+ background-color: $mid-gray;
+ display: flex;
+ position: relative;
+ padding: 25px;
+ flex-flow: column;
+ align-items: flex-start;
+
+ &__title {
+ color: $white;
+ font-size: 24px;
+ line-height: 32px;
+ }
+
+ &__description {
+ color: $white;
+ font-size: 16px;
+ line-height: 22px;
+ margin-top: 10px;
+ }
+
+ &__close::after {
+ content: '\00D7';
+ font-size: 2em;
+ color: $white;
+ position: absolute;
+ top: 20.8px;
+ right: 28px;
+ cursor: pointer;
+ }
+ }
+
+ &__buy-rows {
+ width: 100%;
+ padding: 33px;
+ padding-top: 0px;
+ display: flex;
+ flex-flow: column nowrap;
+ flex: 1;
+ overflow-y: auto;
- button {
- height: 44px;
- width: 113px;
- border: 1px solid $scorpion;
- border-radius: 2px;
- color: $tundora;
- font-family: Roboto;
- font-size: 14px;
- line-height: 20px;
- text-align: center;
- margin-left: 4px;
- margin-right: 4px;
+ @media screen and (max-width: 575px) {
+ height: 0;
}
}
+
+ &__buy-row {
+ border-bottom: 1px solid $alto;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex: 1;
+ padding-bottom: 25px;
+ padding-top: 25px;
+
+ @media screen and (max-width: 575px) {
+ min-height: 360px;
+ flex-flow: column;
+ justify-content: center;
+ padding-top: 45px;
+ }
+
+ &__back {
+ position: absolute;
+ top: 10px;
+ left: 0px;
+ }
+
+ &__shapeshift-buy {
+ padding-top: 25px;
+ position: relative;
+ @media screen and (max-width: 575px) {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex: 1;
+ padding-bottom: 25px;
+ flex-flow: column;
+ justify-content: center;
+ padding-top: 20px;
+ min-height: 240px;
+ border: none;
+ }
+ }
+
+ &__logo {
+ display: flex;
+ justify-content: center;
+ flex: 0.3 1 auto;
+
+ @media screen and (min-width: 575px) {
+ min-width: 215px;
+ }
+ }
+
+ &__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 {
+ display: flex;
+ }
+
+ &__description {
+ color: $cape-cod;
+ flex: 0.5 1 auto;
+
+ @media screen and (min-width: 575px) {
+ min-width: 315px;
+ }
+
+ &__title {
+ font-size: 20px;
+ line-height: 30px;
+ }
+
+ &__text {
+ font-size: 14px;
+ line-height: 22px;
+ margin-top: 7px;
+ }
+ }
+
+ &__button {
+ display: flex;
+ justify-content: flex-end;
+
+ @media screen and (min-width: 575px) {
+ min-width: 300px;
+ }
+ }
+ }
+
+ &__buy-row:last-of-type {
+ border-bottom: 0px;
+ }
+
+ &__deposit-button, .shapeshift-form__shapeshift-buy-btn {
+ height: 54px;
+ width: 257px;
+ border: 1px solid $curious-blue;
+ border-radius: 4px;
+ display: flex;
+ justify-content: center;
+ font-size: 16px;
+ color: $curious-blue;
+ background-color: $white;
+ }
+
+ .shapeshift-form-wrapper {
+ display: flex;
+ flex-flow: column;
+ justify-content: center;
+ align-items: center;
+ margin-top: 28px;
+ flex: 1 0 auto;
+
+ .shapeshift-form {
+ width: auto;
+
+ &__caret {
+ width: auto;
+ flex: 1;
+ }
+ }
+ }
+
+ .shapeshift-form__shapeshift-buy-btn {
+ margin-top: 10px;
+ }
+
+ .simple-dropdown {
+ color: #5B5D67;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 21px;
+ border: 1px solid #D8D8D8;
+ background-color: #FFFFFF;
+ text-align: center;
+ width: 100%;
+ height: 45px;
+ line-height: 44px;
+ font-family: Montserrat Light;
+ }
+
+ .simple-dropdown__selected {
+ text-align: center;
+ }
}
//Notification Modal
@@ -582,6 +815,7 @@
width: 100%;
display: flex;
justify-content: center;
+ align-items: center;
padding: 30px;
font-size: 22px;
color: $nile-blue;
@@ -598,4 +832,4 @@
justify-content: center;
font-size: 17px;
color: $nile-blue;
-} \ No newline at end of file
+}
diff --git a/ui/app/css/itcss/components/network.scss b/ui/app/css/itcss/components/network.scss
index 98dbdffb2..d9a39b8d5 100644
--- a/ui/app/css/itcss/components/network.scss
+++ b/ui/app/css/itcss/components/network.scss
@@ -8,41 +8,25 @@
}
.network-component.pointer {
- border: 1px solid $shark;
+ border: 2px solid $silver;
border-radius: 82px;
- padding: 6px;
+ padding: 3px;
flex: 0 0 auto;
- &.ethereum-network {
- border-color: rgb(3, 135, 137);
-
- .menu-icon-circle div {
- background-color: rgba(3, 135, 137, .7) !important;
- }
+ &.ethereum-network .menu-icon-circle div {
+ background-color: rgba(3, 135, 137, .7) !important;
}
- &.ropsten-test-network {
- border-color: rgb(233, 21, 80);
-
- .menu-icon-circle div {
- background-color: rgba(233, 21, 80, .7) !important;
- }
+ &.ropsten-test-network .menu-icon-circle div {
+ background-color: rgba(233, 21, 80, .7) !important;
}
- &.kovan-test-network {
- border-color: rgb(105, 4, 150);
-
- .menu-icon-circle div {
- background-color: rgba(105, 4, 150, .7) !important;
- }
+ &.kovan-test-network .menu-icon-circle div {
+ background-color: rgba(105, 4, 150, .7) !important;
}
- &.rinkeby-test-network {
- border-color: rgb(235, 179, 63);
-
- .menu-icon-circle div {
- background-color: rgba(235, 179, 63, .7) !important;
- }
+ &.rinkeby-test-network .menu-icon-circle div {
+ background-color: rgba(235, 179, 63, .7) !important;
}
}
@@ -66,11 +50,12 @@
}
.network-name {
- line-height: 15px;
padding: 0 4px;
font-family: Roboto;
font-size: 12px;
flex: 1 0 auto;
+ color: $tundora;
+ font-weight: 500;
}
.network-droppo {
@@ -167,3 +152,6 @@
line-height: 18px;
}
+.network-caret {
+ margin: 0 8px 2px;
+}
diff --git a/ui/app/css/itcss/components/new-account.scss b/ui/app/css/itcss/components/new-account.scss
new file mode 100644
index 000000000..c5e4ea761
--- /dev/null
+++ b/ui/app/css/itcss/components/new-account.scss
@@ -0,0 +1,192 @@
+.new-account {
+ width: 376px;
+ background-color: #FFFFFF;
+ box-shadow: 0 0 7px 0 rgba(0,0,0,0.08);
+ z-index: 25;
+ padding-bottom: 31px;
+
+ &__header {
+ display: flex;
+ flex-flow: column;
+ border-bottom: 1px solid $geyser;
+ }
+
+ &__title {
+ color: $tundora;
+ font-family: Roboto;
+ font-size: 32px;
+ font-weight: 500;
+ line-height: 43px;
+ margin-top: 22px;
+ margin-left: 29px;
+ }
+
+ &__tabs {
+ margin-left: 22px;
+ display: flex;
+ margin-top: 10px;
+
+ &__tab {
+ height: 54px;
+ width: 75px;
+ padding: 15px 10px;
+ color: $dusty-gray;
+ font-family: Roboto;
+ font-size: 18px;
+ line-height: 24px;
+ text-align: center;
+ }
+
+ &__tab:first-of-type {
+ margin-right: 20px;
+ }
+
+ &__unselected:hover {
+ color: $black;
+ border-bottom: none;
+ }
+
+ &__selected {
+ color: $curious-blue;
+ border-bottom: 3px solid $curious-blue;
+ }
+ }
+
+}
+
+.new-account-import-form {
+ &__select-section {
+ display: flex;
+ justify-content: space-evenly;
+ align-items: center;
+ margin-top: 29px;
+ }
+
+ &__select-label {
+ color: $scorpion;
+ font-family: Roboto;
+ font-size: 16px;
+ line-height: 21px;
+ }
+
+ &__select {
+ height: 54px;
+ width: 210px;
+ border: 1px solid #D2D8DD;
+ border-radius: 4px;
+ background-color: #FFFFFF;
+ display: flex;
+ align-items: center;
+
+ .Select-control,
+ .Select-control:hover {
+ height: 100%;
+ border: none;
+ box-shadow: none;
+
+ .Select-value {
+ display: flex;
+ align-items: center;
+ }
+ }
+ }
+
+ &__instruction {
+ color: $scorpion;
+ font-family: Roboto;
+ font-size: 16px;
+ line-height: 21px;
+ align-self: flex-start;
+ margin-left: 30px;
+ }
+
+ &__private-key {
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+ margin-top: 34px;
+ }
+
+ &__input-password {
+ height: 54px;
+ width: 315px;
+ border: 1px solid $geyser;
+ border-radius: 4px;
+ background-color: $white;
+ margin-top: 16px;
+ color: $scorpion;
+ font-family: Roboto;
+ font-size: 16px;
+ padding: 0px 20px;
+ }
+
+ &__json {
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+ margin-top: 29px;
+ }
+}
+
+.new-account-create-form {
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+
+ &__input-label {
+ color: $scorpion;
+ font-family: Roboto;
+ font-size: 16px;
+ line-height: 21px;
+ margin-top: 29px;
+ align-self: flex-start;
+ margin-left: 30px;
+ }
+
+ &__input {
+ height: 54px;
+ width: 315.84px;
+ border: 1px solid $geyser;
+ border-radius: 4px;
+ background-color: $white;
+ color: $scorpion;
+ font-family: Roboto;
+ font-size: 16px;
+ line-height: 21px;
+ margin-top: 15px;
+ padding: 0px 20px;
+ }
+
+ &__buttons {
+ margin-top: 39px;
+ display: flex;
+ width: 100%;
+ justify-content: space-evenly;
+ }
+
+ &__button-cancel,
+ &__button-create {
+ height: 55px;
+ width: 150px;
+ border-radius: 2px;
+ background-color: #FFFFFF;
+ }
+
+ &__button-cancel {
+ border: 1px solid $dusty-gray;
+ color: $dusty-gray;
+ font-family: Roboto;
+ font-size: 16px;
+ line-height: 21px;
+ text-align: center;
+ }
+
+ &__button-create {
+ border: 1px solid $curious-blue;
+ color: $curious-blue;
+ font-family: Roboto;
+ font-size: 16px;
+ line-height: 21px;
+ text-align: center;
+ }
+} \ No newline at end of file
diff --git a/ui/app/css/itcss/components/newui-sections.scss b/ui/app/css/itcss/components/newui-sections.scss
index 61dfbd176..1c26882b5 100644
--- a/ui/app/css/itcss/components/newui-sections.scss
+++ b/ui/app/css/itcss/components/newui-sections.scss
@@ -4,7 +4,7 @@
// Component Colors
$tx-view-bg: $white;
-$wallet-view-bg: $wild-sand;
+$wallet-view-bg: $alabaster;
// Main container
.main-container {
@@ -40,6 +40,8 @@ $wallet-view-bg: $wild-sand;
.open-in-browser {
cursor: pointer;
+ display: flex;
+ justify-content: center;
}
// wallet view and sidebar
@@ -47,7 +49,7 @@ $wallet-view-bg: $wild-sand;
.wallet-view {
display: flex;
flex-direction: column;
- flex: 33.5 1 33.5%;
+ flex: 32 1 32%;
width: 0;
background: $wallet-view-bg;
z-index: 200;
@@ -69,22 +71,18 @@ $wallet-view-bg: $wild-sand;
}
&__keyring-label {
- height: 40px;
+ height: 50px;
color: $dusty-gray;
font-family: Roboto;
font-size: 10px;
- line-height: 40px;
text-align: right;
- padding: 0 20px;
+ padding: 17px 20px 0;
+ box-sizing: border-box;
}
&__details-button {
- color: $curious-blue;
font-size: 10px;
- line-height: 13px;
- text-align: center;
- border: 1px solid $curious-blue;
- border-radius: 10.5px;
+ border-radius: 17px;
background-color: transparent;
margin: 0 auto;
padding: 4px 12px;
@@ -121,16 +119,14 @@ $wallet-view-bg: $wild-sand;
&__add-token-button {
flex: 0 0 auto;
- color: $dusty-gray;
- font-size: 14px;
- line-height: 19px;
- text-align: center;
margin: 36px auto;
- border: 1px solid $dusty-gray;
- border-radius: 2px;
- font-weight: 300;
background: none;
- padding: 9px 30px;
+ padding: .7rem 2rem;
+ transition: border-color .3s ease;
+
+ &:hover {
+ border-color: $curious-blue;
+ }
}
}
@@ -159,7 +155,7 @@ $wallet-view-bg: $wild-sand;
background: rgb(250, 250, 250);
z-index: $sidebar-z-index;
position: fixed;
- top: 56px;
+ top: 66px;
left: 0;
right: 0;
bottom: 0;
@@ -199,7 +195,7 @@ $wallet-view-bg: $wild-sand;
.main-container {
// margin-top: 6.9vh;
- width: 85%;
+ width: 85vw;
height: 90vh;
box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08);
}
@@ -208,7 +204,7 @@ $wallet-view-bg: $wild-sand;
@media screen and (min-width: 769px) {
.main-container {
// margin-top: 6.9vh;
- width: 80%;
+ width: 80vw;
height: 82vh;
box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08);
}
@@ -217,7 +213,7 @@ $wallet-view-bg: $wild-sand;
@media screen and (min-width: 1281px) {
.main-container {
// margin-top: 6.9vh;
- width: 65%;
+ width: 62vw;
height: 82vh;
box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08);
}
@@ -239,14 +235,6 @@ $wallet-view-bg: $wild-sand;
overflow-y: auto;
background-color: $white;
}
-
- button.btn-clear {
- width: 93px;
- height: 50px;
- font-size: .7em;
- background: $white;
- border: 1px solid;
- }
}
// wallet view
@@ -254,9 +242,9 @@ $wallet-view-bg: $wild-sand;
font-size: 24px;
font-weight: 300;
line-height: 20px;
- color: $scorpion;
+ color: $black;
margin-top: 8px;
- margin-bottom: 24px;
+ margin-bottom: .9rem;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss
index 2bd192788..7a6e2823b 100644
--- a/ui/app/css/itcss/components/send.scss
+++ b/ui/app/css/itcss/components/send.scss
@@ -526,8 +526,9 @@
}
&__form {
- margin: 13px 0;
+ padding: 13px 0;
width: 100%;
+ overflow-y: auto;
@media screen and (max-width: $break-small) {
padding: 13px 0;
@@ -587,7 +588,7 @@
width: 100%;
height: 100%;
}
-
+
&__list {
z-index: 1050;
position: absolute;
@@ -651,11 +652,11 @@
border: 1px solid $curious-blue;
border-radius: 4px;
background-color: $white;
- padding: 5px;
position: absolute;
right: 15px;
top: 14px;
cursor: pointer;
+ font-size: 1em;
}
&__sliders-icon {
@@ -677,40 +678,15 @@
border-top: 1px solid $alto;
background: $white;
padding: 0 12px;
+ flex-shrink: 0;
}
&__next-btn,
- &__cancel-btn,
- &__next-btn__disabled {
+ &__cancel-btn {
width: 163px;
- text-align: center;
- height: 55px;
- border-radius: 2px;
- background-color: $white;
- font-family: Roboto;
- font-size: 16px;
- font-weight: 300;
- line-height: 21px;
- border: 1px solid;
margin: 0 4px;
}
- &__next-btn,
- &__next-btn__disabled {
- color: $curious-blue;
- border-color: $curious-blue;
- }
-
- &__next-btn__disabled {
- opacity: .5;
- cursor: auto;
- }
-
- &__cancel-btn {
- color: $dusty-gray;
- border-color: $dusty-gray;
- }
-
&__customize-gas {
border: 1px solid #D8D8D8;
border-radius: 4px;
diff --git a/ui/app/css/itcss/components/token-list.scss b/ui/app/css/itcss/components/token-list.scss
index d4add71b1..e24bf812b 100644
--- a/ui/app/css/itcss/components/token-list.scss
+++ b/ui/app/css/itcss/components/token-list.scss
@@ -12,7 +12,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
position: relative;
&__token-balance {
- font-size: 130%;
+ font-size: 1.5rem;
@media #{$wallet-balance-breakpoint-range} {
font-size: 105%;
@@ -34,7 +34,8 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
}
&--active {
- background-color: rgba($wallet-balance-bg, 1);
+ background-color: $manatee;
+ color: $white;
}
&__identicon {
@@ -62,11 +63,11 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
height: 55px;
width: 191px;
border-radius: 4px;
- background-color: rgba(0,0,0,0.82);
- box-shadow: 0 2px 4px 0 rgba(0,0,0,0.5);
- position: fixed;
- margin-top: 20px;
- margin-left: 105px;
+ background-color: rgba(0, 0, 0, .82);
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .5);
+ position: absolute;
+ top: 60px;
+ right: 25px;
z-index: 2000;
&__close-area {
diff --git a/ui/app/css/itcss/components/transaction-list.scss b/ui/app/css/itcss/components/transaction-list.scss
index a5d508f11..c3df493df 100644
--- a/ui/app/css/itcss/components/transaction-list.scss
+++ b/ui/app/css/itcss/components/transaction-list.scss
@@ -6,6 +6,10 @@
}
}
+.tx-list-header-wrapper {
+ flex: 0 0 auto;
+}
+
.tx-list-header {
text-transform: capitalize;
}
@@ -32,13 +36,9 @@
}
@media screen and (min-width: $break-large) {
- .tx-list-header-wrapper {
- flex: 0 0 55px;
- }
-
.tx-list-header {
font-size: 16px;
- margin: 1.5em 2.37em;
+ margin: 1.1em 2.37em .8em;
}
.tx-list-container::-webkit-scrollbar {
@@ -73,7 +73,7 @@
}
@media screen and (min-width: $break-large) {
- padding-bottom: 12px;
+ padding-bottom: 8px;
}
}
@@ -91,21 +91,13 @@
}
.tx-list-date-wrapper {
+ margin-top: 6px;
flex: 1 1 auto;
-
- @media screen and (max-width: $break-small) {
- margin-top: 6px;
- }
-
- @media screen and (min-width: $break-large) {
- margin-top: 12px;
- }
}
.tx-list-content-wrapper {
align-items: stretch;
margin-bottom: 4px;
- margin-top: 2px;
flex: 1 0 auto;
width: 100%;
display: flex;
@@ -115,7 +107,7 @@
font-size: 12px;
.tx-list-status {
- font-size: 14px !important;
+ font-size: 12px !important;
}
.tx-list-account {
@@ -129,7 +121,7 @@
.tx-list-fiat-value {
font-size: 12px;
- line-height: 16px;
+ line-height: 22px;
}
}
}
@@ -210,7 +202,7 @@
}
@media screen and (min-width: $break-large) {
- margin: 0 2.37em;
+ padding: 0 2.37em;
}
&:last-of-type {
@@ -259,6 +251,8 @@
}
.tx-list-fiat-value {
+ font-size: 12px;
+ line-height: initial;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
diff --git a/ui/app/css/itcss/components/wallet-balance.scss b/ui/app/css/itcss/components/wallet-balance.scss
index 64b291b89..293771550 100644
--- a/ui/app/css/itcss/components/wallet-balance.scss
+++ b/ui/app/css/itcss/components/wallet-balance.scss
@@ -8,7 +8,8 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
background: rgba($wallet-balance-bg, 0);
&--active {
- background: rgba($wallet-balance-bg, 1);
+ background: $manatee;
+ color: $white;
}
}
@@ -41,7 +42,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
align-items: flex-start;
.token-amount {
- font-size: 135%;
+ font-size: 1.5rem;
}
.fiat-amount {
@@ -61,11 +62,13 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
}
}
}
+}
- .balance-icon {
- border-radius: 25px;
- width: 45px;
- height: 45px;
- border: 1px solid $alto;
- }
+.balance-icon {
+ border-radius: 25px;
+ width: 50px;
+ height: 50px;
+ border: 1px solid $alto;
+ padding: 5px;
+ background: $white;
}
diff --git a/ui/app/css/itcss/settings/typography.scss b/ui/app/css/itcss/settings/typography.scss
index 58e2d444e..ac8c41336 100644
--- a/ui/app/css/itcss/settings/typography.scss
+++ b/ui/app/css/itcss/settings/typography.scss
@@ -51,14 +51,14 @@
@font-face {
font-family: 'DIN NEXT';
- src: url('/fonts/DIN NEXT/DIN NEXT W01 Regular.otf') format('opentype');
+ src: url('/fonts/DIN Next/DIN Next W01 Regular.otf') format('opentype');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'DIN NEXT Light';
- src: url('/fonts/DIN NEXT/DIN NEXT W10 Light.otf') format('opentype');
+ src: url('/fonts/DIN Next/DIN Next W10 Light.otf') format('opentype');
font-weight: 400;
font-style: normal;
}
diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss
index 387d14b5f..4c0972527 100644
--- a/ui/app/css/itcss/settings/variables.scss
+++ b/ui/app/css/itcss/settings/variables.scss
@@ -42,6 +42,10 @@ $malibu-blue: #7ac9fd;
$athens-grey: #e9edf0;
$jaffa: #f28930;
$geyser: #d2d8dd;
+$manatee: #93949d;
+$spindle: #c7ddec;
+$mid-gray: #5b5d67;
+$cape-cod: #38393a;
/*
Z-Indicies
diff --git a/ui/app/info.js b/ui/app/info.js
index 24c211c1f..49ff9f24a 100644
--- a/ui/app/info.js
+++ b/ui/app/info.js
@@ -103,9 +103,9 @@ InfoScreen.prototype.render = function () {
[
h('div.fa.fa-support', [
h('a.info', {
- href: 'https://support.metamask.io',
+ href: 'https://metamask.helpscoutdocs.com/',
target: '_blank',
- }, 'Visit our Support Center'),
+ }, 'Visit our Knowledge Base'),
]),
h('div', [
@@ -138,8 +138,7 @@ InfoScreen.prototype.render = function () {
h('div.fa.fa-envelope', [
h('a.info', {
target: '_blank',
- style: { width: '85vw' },
- href: 'mailto:help@metamask.io?subject=Feedback',
+ href: 'mailto:support@metamask.io?subject=MetaMask Support',
}, 'Email us!'),
]),
]),
diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js
new file mode 100644
index 000000000..24b37a83d
--- /dev/null
+++ b/ui/app/keychains/hd/restore-vault.js
@@ -0,0 +1,156 @@
+const inherits = require('util').inherits
+const PersistentForm = require('../../../lib/persistent-form')
+const connect = require('react-redux').connect
+const h = require('react-hyperscript')
+const actions = require('../../actions')
+
+module.exports = connect(mapStateToProps)(RestoreVaultScreen)
+
+inherits(RestoreVaultScreen, PersistentForm)
+function RestoreVaultScreen () {
+ PersistentForm.call(this)
+}
+
+function mapStateToProps (state) {
+ return {
+ warning: state.appState.warning,
+ forgottenPassword: state.appState.forgottenPassword,
+ }
+}
+
+RestoreVaultScreen.prototype.render = function () {
+ var state = this.props
+ this.persistentFormParentId = 'restore-vault-form'
+
+ return (
+
+ h('.initialize-screen.flex-column.flex-center.flex-grow', [
+
+ h('h3.flex-center.text-transform-uppercase', {
+ style: {
+ background: '#EBEBEB',
+ color: '#AEAEAE',
+ marginBottom: 24,
+ width: '100%',
+ fontSize: '20px',
+ padding: 6,
+ },
+ }, [
+ 'Restore Vault',
+ ]),
+
+ // wallet seed entry
+ h('h3', 'Wallet Seed'),
+ h('textarea.twelve-word-phrase.letter-spacey', {
+ dataset: {
+ persistentFormId: 'wallet-seed',
+ },
+ placeholder: 'Enter your secret twelve word phrase here to restore your vault.',
+ }),
+
+ // password
+ h('input.large-input.letter-spacey', {
+ type: 'password',
+ id: 'password-box',
+ placeholder: 'New Password (min 8 chars)',
+ dataset: {
+ persistentFormId: 'password',
+ },
+ style: {
+ width: 260,
+ marginTop: 12,
+ },
+ }),
+
+ // confirm password
+ h('input.large-input.letter-spacey', {
+ type: 'password',
+ id: 'password-box-confirm',
+ placeholder: 'Confirm Password',
+ onKeyPress: this.createOnEnter.bind(this),
+ dataset: {
+ persistentFormId: 'password-confirmation',
+ },
+ style: {
+ width: 260,
+ marginTop: 16,
+ },
+ }),
+
+ (state.warning) && (
+ h('span.error.in-progress-notification', state.warning)
+ ),
+
+ // submit
+
+ h('.flex-row.flex-space-between', {
+ style: {
+ marginTop: 30,
+ width: '50%',
+ },
+ }, [
+
+ // cancel
+ h('button.primary', {
+ onClick: this.showInitializeMenu.bind(this),
+ }, 'CANCEL'),
+
+ // submit
+ h('button.primary', {
+ onClick: this.createNewVaultAndRestore.bind(this),
+ }, 'OK'),
+
+ ]),
+ ])
+
+ )
+}
+
+RestoreVaultScreen.prototype.showInitializeMenu = function () {
+ if (this.props.forgottenPassword) {
+ this.props.dispatch(actions.backToUnlockView())
+ } else {
+ this.props.dispatch(actions.showInitializeMenu())
+ }
+}
+
+RestoreVaultScreen.prototype.createOnEnter = function (event) {
+ if (event.key === 'Enter') {
+ this.createNewVaultAndRestore()
+ }
+}
+
+RestoreVaultScreen.prototype.createNewVaultAndRestore = function () {
+ // check password
+ var passwordBox = document.getElementById('password-box')
+ var password = passwordBox.value
+ var passwordConfirmBox = document.getElementById('password-box-confirm')
+ var passwordConfirm = passwordConfirmBox.value
+ if (password.length < 8) {
+ this.warning = 'Password not long enough'
+
+ this.props.dispatch(actions.displayWarning(this.warning))
+ return
+ }
+ if (password !== passwordConfirm) {
+ this.warning = 'Passwords don\'t match'
+ this.props.dispatch(actions.displayWarning(this.warning))
+ return
+ }
+ // check seed
+ var seedBox = document.querySelector('textarea.twelve-word-phrase')
+ var seed = seedBox.value.trim()
+ if (seed.split(' ').length !== 12) {
+ this.warning = 'seed phrases are 12 words long'
+ this.props.dispatch(actions.displayWarning(this.warning))
+ return
+ }
+ // submit
+ this.warning = null
+ this.props.dispatch(actions.displayWarning(this.warning))
+ this.props.dispatch(actions.createNewVaultAndRestore(password, seed))
+ .catch((err) => {
+ log.error(err.message)
+ })
+
+}
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index 3a4fb536d..c3ade5cdc 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -58,6 +58,7 @@ function reduceApp (state, action) {
isLoading: false,
// Used to display error text
warning: null,
+ buyView: {},
}, state.appState)
switch (action.type) {
@@ -169,7 +170,6 @@ function reduceApp (state, action) {
})
case actions.SHOW_IMPORT_PAGE:
-
return extend(appState, {
currentView: {
name: 'import-menu',
@@ -178,6 +178,24 @@ function reduceApp (state, action) {
warning: null,
})
+ case actions.SHOW_NEW_ACCOUNT_PAGE:
+ return extend(appState, {
+ currentView: {
+ name: 'new-account-page',
+ context: action.formToSelect,
+ },
+ transForward: true,
+ warning: null,
+ })
+
+ case actions.SET_NEW_ACCOUNT_FORM:
+ return extend(appState, {
+ currentView: {
+ name: appState.currentView.name,
+ context: action.formToSelect,
+ },
+ })
+
case actions.SHOW_INFO_PAGE:
return extend(appState, {
currentView: {
@@ -371,7 +389,7 @@ function reduceApp (state, action) {
return extend(appState, {
currentView: {
name: 'confTx',
- context: action.id ? indexForPending(state, action.id) : indexForLastPending(state),
+ context: action.id ? indexForPending(state, action.id) : 0,
},
transForward: action.transForward,
warning: null,
@@ -391,36 +409,36 @@ function reduceApp (state, action) {
case actions.COMPLETED_TX:
log.debug('reducing COMPLETED_TX for tx ' + action.value)
- // const otherUnconfActions = getUnconfActionList(state)
- // .filter(tx => tx.id !== action.value)
- // const hasOtherUnconfActions = otherUnconfActions.length > 0
-
- // if (hasOtherUnconfActions) {
- // log.debug('reducer detected txs - rendering confTx view')
- // return extend(appState, {
- // transForward: false,
- // currentView: {
- // name: 'confTx',
- // context: 0,
- // },
- // warning: null,
- // })
- // } else {
- log.debug('attempting to close popup')
- return extend(appState, {
- // indicate notification should close
- shouldClose: true,
- transForward: false,
- warning: null,
- currentView: {
- name: 'accountDetail',
- context: state.metamask.selectedAddress,
- },
- accountDetail: {
- subview: 'transactions',
- },
- })
- // }
+ const otherUnconfActions = getUnconfActionList(state)
+ .filter(tx => tx.id !== action.value)
+ const hasOtherUnconfActions = otherUnconfActions.length > 0
+
+ if (hasOtherUnconfActions) {
+ log.debug('reducer detected txs - rendering confTx view')
+ return extend(appState, {
+ transForward: false,
+ currentView: {
+ name: 'confTx',
+ context: 0,
+ },
+ warning: null,
+ })
+ } else {
+ log.debug('attempting to close popup')
+ return extend(appState, {
+ // indicate notification should close
+ shouldClose: true,
+ transForward: false,
+ warning: null,
+ currentView: {
+ name: 'accountDetail',
+ context: state.metamask.selectedAddress,
+ },
+ accountDetail: {
+ subview: 'transactions',
+ },
+ })
+ }
case actions.NEXT_TX:
return extend(appState, {
@@ -591,8 +609,8 @@ function reduceApp (state, action) {
marketinfo: action.value.marketinfo,
coinOptions: action.value.coinOptions,
},
- buyAddress: appState.buyView.buyAddress,
- amount: appState.buyView.amount,
+ buyAddress: action.value.buyAddress || appState.buyView.buyAddress,
+ amount: appState.buyView.amount || 0,
},
})
@@ -661,6 +679,6 @@ function indexForPending (state, txId) {
return index
}
-function indexForLastPending (state) {
- return getUnconfActionList(state).length
-}
+// function indexForLastPending (state) {
+// return getUnconfActionList(state).length
+// }
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index 95b41e5f3..294c29948 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -1,6 +1,7 @@
const extend = require('xtend')
const actions = require('../actions')
const MetamascaraPlatform = require('../../../app/scripts/platforms/window')
+const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums
module.exports = reduceMetamask
@@ -39,6 +40,7 @@ function reduceMetamask (state, action) {
coinOptions: {},
useBlockie: false,
featureFlags: {},
+ networkEndpointType: OLD_UI_NETWORK_TYPE,
}, state.metamask)
switch (action.type) {
@@ -335,6 +337,11 @@ function reduceMetamask (state, action) {
featureFlags: action.value,
})
+ case actions.UPDATE_NETWORK_ENDPOINT_TYPE:
+ return extend(metamaskState, {
+ networkEndpointType: action.value,
+ })
+
default:
return metamaskState
diff --git a/ui/app/select-app.js b/ui/app/select-app.js
index 3ea93ced3..193c98353 100644
--- a/ui/app/select-app.js
+++ b/ui/app/select-app.js
@@ -5,42 +5,64 @@ const h = require('react-hyperscript')
const App = require('./app')
const OldApp = require('../../old-ui/app/app')
const { autoAddToBetaUI } = require('./selectors')
-const { setFeatureFlag } = require('./actions')
+const { setFeatureFlag, setNetworkEndpoints } = require('./actions')
+const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
function mapStateToProps (state) {
- return {
- betaUI: state.metamask.featureFlags.betaUI,
- autoAdd: autoAddToBetaUI(state),
- isUnlocked: state.metamask.isUnlocked,
- }
+ return {
+ betaUI: state.metamask.featureFlags.betaUI,
+ autoAdd: autoAddToBetaUI(state),
+ isUnlocked: state.metamask.isUnlocked,
+ isMascara: state.metamask.isMascara,
+ firstTime: Object.keys(state.metamask.identities).length === 0,
+ }
}
function mapDispatchToProps (dispatch) {
return {
- setFeatureFlagToBeta: () => dispatch(setFeatureFlag('betaUI', true)),
+ setFeatureFlagWithModal: () => {
+ return dispatch(setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL'))
+ .then(() => dispatch(setNetworkEndpoints(BETA_UI_NETWORK_TYPE)))
+ },
+ setFeatureFlagWithoutModal: () => {
+ return dispatch(setFeatureFlag('betaUI', true))
+ .then(() => dispatch(setNetworkEndpoints(BETA_UI_NETWORK_TYPE)))
+ },
}
}
module.exports = connect(mapStateToProps, mapDispatchToProps)(SelectedApp)
inherits(SelectedApp, Component)
function SelectedApp () {
- this.state = {
- autoAdd: false,
- }
- Component.call(this)
+ Component.call(this)
}
SelectedApp.prototype.componentWillReceiveProps = function (nextProps) {
- const { isUnlocked, setFeatureFlagToBeta } = this.props
+ // Code commented out until we begin auto adding users to NewUI
+ const {
+ // isUnlocked,
+ // setFeatureFlagWithModal,
+ setFeatureFlagWithoutModal,
+ isMascara,
+ // firstTime,
+ } = this.props
- if (!isUnlocked && nextProps.isUnlocked && nextProps.autoAdd) {
- this.setState({ autoAdd: nextProps.autoAdd })
- setFeatureFlagToBeta()
- }
+ // if (isMascara || firstTime) {
+ if (isMascara) {
+ setFeatureFlagWithoutModal()
+ }
+ // } else if (!isUnlocked && nextProps.isUnlocked && (nextProps.autoAdd)) {
+ // setFeatureFlagWithModal()
+ // }
}
SelectedApp.prototype.render = function () {
- const { betaUI } = this.props
- const Selected = betaUI ? App : OldApp
+ // Code commented out until we begin auto adding users to NewUI
+ // const { betaUI, isMascara, firstTime } = this.props
+ // const Selected = betaUI || isMascara || firstTime ? App : OldApp
+
+ const { betaUI, isMascara } = this.props
+ const Selected = betaUI || isMascara ? App : OldApp
+
return h(Selected)
}
diff --git a/ui/app/selectors.js b/ui/app/selectors.js
index 22ef439c4..38a96c48b 100644
--- a/ui/app/selectors.js
+++ b/ui/app/selectors.js
@@ -26,6 +26,7 @@ const selectors = {
getSelectedTokenContract,
autoAddToBetaUI,
getSendMaxModeState,
+ getCurrentViewContext,
}
module.exports = selectors
@@ -180,4 +181,9 @@ function autoAddToBetaUI (state) {
const userIsNotInBeta = !state.metamask.featureFlags.betaUI
return userIsNotInBeta && userPassesThreshold
+}
+
+function getCurrentViewContext (state) {
+ const { currentView = {} } = state.appState
+ return currentView.context
} \ No newline at end of file
diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js
index 32bbdfe6e..5eb90143e 100644
--- a/ui/app/send-v2.js
+++ b/ui/app/send-v2.js
@@ -2,6 +2,7 @@ const { inherits } = require('util')
const PersistentForm = require('../lib/persistent-form')
const h = require('react-hyperscript')
+const ethAbi = require('ethereumjs-abi')
const ethUtil = require('ethereumjs-util')
const Identicon = require('./components/identicon')
@@ -12,7 +13,7 @@ const MemoTextArea = require('./components/send/memo-textarea')
const GasFeeDisplay = require('./components/send/gas-fee-display-v2')
const {
- MIN_GAS_TOTAL,
+ TOKEN_TRANSFER_FUNCTION_SIGNATURE,
} = require('./components/send/send-constants')
const {
@@ -84,6 +85,20 @@ SendTransactionScreen.prototype.componentWillMount = function () {
const {
updateTokenExchangeRate,
selectedToken = {},
+ } = this.props
+
+ const { symbol } = selectedToken || {}
+
+ if (symbol) {
+ updateTokenExchangeRate(symbol)
+ }
+
+ this.updateGas()
+}
+
+SendTransactionScreen.prototype.updateGas = function () {
+ const {
+ selectedToken = {},
getGasPrice,
estimateGas,
selectedAddress,
@@ -95,45 +110,41 @@ SendTransactionScreen.prototype.componentWillMount = function () {
gasPrice,
gasLimit,
} = this.props
- const { symbol } = selectedToken || {}
- if (symbol) {
- updateTokenExchangeRate(symbol)
- }
+ const { symbol } = selectedToken || {}
- const estimateGasParams = getParamsForGasEstimate(selectedAddress, symbol, data)
+ const tokenBalancePromise = tokenContract
+ ? tokenContract.balanceOf(from.address)
+ : Promise.resolve()
+ tokenBalancePromise
+ .then(usersToken => this.updateSendTokenBalance(usersToken))
- const tokenBalancePromise = tokenContract && tokenContract.balanceOf(from.address)
- let newGasTotal
if (!editingTransactionId) {
+ const estimateGasParams = getParamsForGasEstimate(selectedAddress, symbol, data)
+
Promise
.all([
getGasPrice(),
estimateGas(estimateGasParams),
- tokenBalancePromise,
])
- .then(([gasPrice, gas, usersToken]) => {
-
- const newGasTotal = multiplyCurrencies(gas, gasPrice, {
- toNumericBase: 'hex',
- multiplicandBase: 16,
- multiplierBase: 16,
- })
+ .then(([gasPrice, gas]) => {
+ const newGasTotal = this.getGasTotal(gas, gasPrice)
updateGasTotal(newGasTotal)
- this.updateSendTokenBalance(usersToken)
})
} else {
- newGasTotal = multiplyCurrencies(gasLimit, gasPrice, {
- toNumericBase: 'hex',
- multiplicandBase: 16,
- multiplierBase: 16,
- })
+ const newGasTotal = this.getGasTotal(gasLimit, gasPrice)
updateGasTotal(newGasTotal)
- tokenBalancePromise && tokenBalancePromise.then(
- usersToken => this.updateSendTokenBalance(usersToken))
}
}
+SendTransactionScreen.prototype.getGasTotal = function (gasLimit, gasPrice) {
+ return multiplyCurrencies(gasLimit, gasPrice, {
+ toNumericBase: 'hex',
+ multiplicandBase: 16,
+ multiplierBase: 16,
+ })
+}
+
SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
const {
from: { balance },
@@ -141,22 +152,31 @@ SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
tokenBalance,
amount,
selectedToken,
+ network,
} = this.props
+
const {
from: { balance: prevBalance },
gasTotal: prevGasTotal,
tokenBalance: prevTokenBalance,
+ network: prevNetwork,
} = prevProps
- const notFirstRender = [prevBalance, prevGasTotal].every(n => n !== null)
+ const uninitialized = [prevBalance, prevGasTotal].every(n => n === null)
const balanceHasChanged = balance !== prevBalance
const gasTotalHasChange = gasTotal !== prevGasTotal
const tokenBalanceHasChanged = selectedToken && tokenBalance !== prevTokenBalance
const amountValidationChange = balanceHasChanged || gasTotalHasChange || tokenBalanceHasChanged
- if (notFirstRender && amountValidationChange) {
- this.validateAmount(amount)
+ if (!uninitialized) {
+ if (amountValidationChange) {
+ this.validateAmount(amount)
+ }
+
+ if (network !== prevNetwork && network !== 'loading') {
+ this.updateGas()
+ }
}
}
@@ -359,14 +379,19 @@ SendTransactionScreen.prototype.validateAmount = function (value) {
const amount = value
let amountError = null
- const sufficientBalance = isBalanceSufficient({
- amount: selectedToken ? '0x0' : amount,
- gasTotal,
- balance,
- primaryCurrency,
- amountConversionRate,
- conversionRate,
- })
+
+ let sufficientBalance = true
+
+ if (gasTotal) {
+ sufficientBalance = isBalanceSufficient({
+ amount: selectedToken ? '0x0' : amount,
+ gasTotal,
+ balance,
+ primaryCurrency,
+ amountConversionRate,
+ conversionRate,
+ })
+ }
let sufficientTokens
if (selectedToken) {
@@ -382,7 +407,7 @@ SendTransactionScreen.prototype.validateAmount = function (value) {
{ value: amount, fromNumericBase: 'hex' },
)
- if (!sufficientBalance) {
+ if (conversionRate && !sufficientBalance) {
amountError = 'Insufficient funds.'
} else if (selectedToken && !sufficientTokens) {
amountError = 'Insufficient tokens.'
@@ -439,7 +464,7 @@ SendTransactionScreen.prototype.renderGasRow = function () {
conversionRate,
convertedCurrency,
showCustomizeGasModal,
- gasTotal = MIN_GAS_TOTAL,
+ gasTotal,
} = this.props
return h('div.send-v2__form-row', [
@@ -455,12 +480,6 @@ SendTransactionScreen.prototype.renderGasRow = function () {
onClick: showCustomizeGasModal,
}),
- h('div.send-v2__sliders-icon-container', {
- onClick: showCustomizeGasModal,
- }, [
- h('i.fa.fa-sliders.send-v2__sliders-icon'),
- ]),
-
]),
])
@@ -510,21 +529,22 @@ SendTransactionScreen.prototype.renderForm = function () {
SendTransactionScreen.prototype.renderFooter = function () {
const {
clearSend,
+ gasTotal,
errors: { amount: amountError, to: toError },
history,
} = this.props
const noErrors = !amountError && toError === null
- const errorClass = noErrors ? '' : '__disabled'
return h('div.send-v2__footer', [
- h('button.send-v2__cancel-btn', {
+ h('button.btn-cancel.send-v2__cancel-btn', {
onClick: () => {
clearSend()
history.goBack()
},
}, 'Cancel'),
- h(`button.send-v2__next-btn${errorClass}`, {
+ h('button.btn-clear.send-v2__next-btn', {
+ disabled: !noErrors || !gasTotal,
onClick: event => this.onSubmit(event),
}, 'Next'),
])
@@ -553,6 +573,48 @@ SendTransactionScreen.prototype.addToAddressBookIfNew = function (newAddress) {
}
}
+SendTransactionScreen.prototype.getEditedTx = function () {
+ const {
+ from: {address: from},
+ to,
+ amount,
+ gasLimit: gas,
+ gasPrice,
+ selectedToken,
+ editingTransactionId,
+ unapprovedTxs,
+ } = this.props
+
+ const editingTx = {
+ ...unapprovedTxs[editingTransactionId],
+ txParams: {
+ from: ethUtil.addHexPrefix(from),
+ gas: ethUtil.addHexPrefix(gas),
+ gasPrice: ethUtil.addHexPrefix(gasPrice),
+ },
+ }
+
+ if (selectedToken) {
+ const data = TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call(
+ ethAbi.rawEncode(['address', 'uint256'], [to, ethUtil.addHexPrefix(amount)]),
+ x => ('00' + x.toString(16)).slice(-2)
+ ).join('')
+
+ Object.assign(editingTx.txParams, {
+ value: ethUtil.addHexPrefix('0'),
+ to: ethUtil.addHexPrefix(selectedToken.address),
+ data,
+ })
+ } else {
+ Object.assign(editingTx.txParams, {
+ value: ethUtil.addHexPrefix(amount),
+ to: ethUtil.addHexPrefix(to),
+ })
+ }
+
+ return editingTx
+}
+
SendTransactionScreen.prototype.onSubmit = function (event) {
event.preventDefault()
const {
@@ -563,10 +625,10 @@ SendTransactionScreen.prototype.onSubmit = function (event) {
gasPrice,
signTokenTx,
signTx,
+ updateTx,
selectedToken,
editingTransactionId,
errors: { amount: amountError, to: toError },
- backToConfirmScreen,
} = this.props
const noErrors = !amountError && toError === null
@@ -578,26 +640,26 @@ SendTransactionScreen.prototype.onSubmit = function (event) {
this.addToAddressBookIfNew(to)
if (editingTransactionId) {
- backToConfirmScreen(editingTransactionId)
- this.props.history.push(CONFIRM_TRANSACTION_ROUTE)
- return
- }
+ const editedTx = this.getEditedTx()
+ updateTx(editedTx)
+ } else {
- const txParams = {
- from,
- value: '0',
- gas,
- gasPrice,
- }
+ const txParams = {
+ from,
+ value: '0',
+ gas,
+ gasPrice,
+ }
- if (!selectedToken) {
- txParams.value = amount
- txParams.to = to
- }
+ if (!selectedToken) {
+ txParams.value = amount
+ txParams.to = to
+ }
- selectedToken
- ? signTokenTx(selectedToken.address, to, amount, txParams)
- : signTx(txParams)
+ selectedToken
+ ? signTokenTx(selectedToken.address, to, amount, txParams)
+ : signTx(txParams)
- this.props.history.push(CONFIRM_TRANSACTION_ROUTE)
+ this.props.history.push(CONFIRM_TRANSACTION_ROUTE)
+ }
}
diff --git a/ui/app/util.js b/ui/app/util.js
index 82a5f9f29..800ccb218 100644
--- a/ui/app/util.js
+++ b/ui/app/util.js
@@ -56,6 +56,7 @@ module.exports = {
exportAsFile: exportAsFile,
isInvalidChecksumAddress,
allNull,
+ getTokenAddressFromTokenObject,
}
function valuesFor (obj) {
@@ -211,6 +212,9 @@ function normalizeEthStringToWei (str) {
while (decimal.length < 18) {
decimal += '0'
}
+ if (decimal.length > 18) {
+ decimal = decimal.slice(0, 18)
+ }
const decimalBN = new ethUtil.BN(decimal, 10)
eth = eth.add(decimalBN)
}
@@ -278,3 +282,7 @@ function exportAsFile (filename, data) {
function allNull (obj) {
return Object.entries(obj).every(([key, value]) => value === null)
}
+
+function getTokenAddressFromTokenObject (token) {
+ return Object.values(token)[0].address.toLowerCase()
+}
diff --git a/ui/index.js b/ui/index.js
index fff677471..bc3676c1f 100644
--- a/ui/index.js
+++ b/ui/index.js
@@ -4,11 +4,12 @@ const Root = require('./app/root')
const actions = require('./app/actions')
const configureStore = require('./app/store')
const txHelper = require('./lib/tx-helper')
+const { OLD_UI_NETWORK_TYPE, BETA_UI_NETWORK_TYPE } = require('../app/scripts/config').enums
+
global.log = require('loglevel')
module.exports = launchMetamaskUi
-
log.setLevel(global.METAMASK_DEBUG ? 'debug' : 'warn')
function launchMetamaskUi (opts, cb) {
@@ -36,6 +37,10 @@ function startApp (metamaskState, accountManager, opts) {
networkVersion: opts.networkVersion,
})
+ const useBetaUi = metamaskState.featureFlags.betaUI
+ const networkEndpointType = useBetaUi ? BETA_UI_NETWORK_TYPE : OLD_UI_NETWORK_TYPE
+ store.dispatch(actions.setNetworkEndpoints(networkEndpointType))
+
// if unconfirmed txs, start on txConf page
const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network)
const numberOfUnapprivedTx = unapprovedTxsAll.length