aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components/pages
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app/components/pages')
-rw-r--r--ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js2
-rw-r--r--ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js54
-rw-r--r--ui/app/components/pages/confirm-add-token/confirm-add-token.component.js46
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js30
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js26
-rw-r--r--ui/app/components/pages/create-account/connect-hardware/account-list.js31
-rw-r--r--ui/app/components/pages/create-account/connect-hardware/connect-screen.js15
-rw-r--r--ui/app/components/pages/create-account/import-account/index.js2
-rw-r--r--ui/app/components/pages/create-account/import-account/json.js21
-rw-r--r--ui/app/components/pages/create-account/import-account/private-key.js19
-rw-r--r--ui/app/components/pages/create-account/new-account.js19
-rw-r--r--ui/app/components/pages/index.scss2
-rw-r--r--ui/app/components/pages/keychains/reveal-seed.js29
-rw-r--r--ui/app/components/pages/settings/index.js65
-rw-r--r--ui/app/components/pages/settings/index.scss80
-rw-r--r--ui/app/components/pages/settings/info-tab/index.js1
-rw-r--r--ui/app/components/pages/settings/info-tab/index.scss56
-rw-r--r--ui/app/components/pages/settings/info-tab/info-tab.component.js136
-rw-r--r--ui/app/components/pages/settings/info.js120
-rw-r--r--ui/app/components/pages/settings/settings-tab/index.js1
-rw-r--r--ui/app/components/pages/settings/settings-tab/index.scss51
-rw-r--r--ui/app/components/pages/settings/settings-tab/settings-tab.component.js360
-rw-r--r--ui/app/components/pages/settings/settings-tab/settings-tab.container.js59
-rw-r--r--ui/app/components/pages/settings/settings.component.js54
-rw-r--r--ui/app/components/pages/settings/settings.js394
-rw-r--r--ui/app/components/pages/unlock-page/index.scss1
26 files changed, 980 insertions, 694 deletions
diff --git a/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js b/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js
index 1611f817b..20f550927 100644
--- a/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js
+++ b/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js
@@ -15,7 +15,7 @@ export default class TokenListPlaceholder extends Component {
</div>
<a
className="token-list-placeholder__link"
- href="https://consensys.zendesk.com/hc/en-us/articles/360004135092"
+ href="https://metamask.zendesk.com/hc/en-us/articles/360015489031"
target="_blank"
rel="noopener noreferrer"
>
diff --git a/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js b/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js
index c24e1e0ea..ee5d6fa64 100644
--- a/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js
+++ b/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js
@@ -90,35 +90,31 @@ export default class ConfirmAddSuggestedToken extends Component {
</div>
</div>
<div className="page-container__footer">
- <Button
- type="default"
- large
- className="page-container__footer-button"
- onClick={() => {
- removeSuggestedTokens()
- .then(() => {
- history.push(DEFAULT_ROUTE)
- })
- }}
- >
- { this.context.t('cancel') }
- </Button>
- <Button
- type="primary"
- large
- className="page-container__footer-button"
- onClick={() => {
- addToken(pendingToken)
- .then(() => {
- removeSuggestedTokens()
- .then(() => {
- history.push(DEFAULT_ROUTE)
- })
- })
- }}
- >
- { this.context.t('addToken') }
- </Button>
+ <header>
+ <Button
+ type="default"
+ large
+ className="page-container__footer-button"
+ onClick={() => {
+ removeSuggestedTokens()
+ .then(() => history.push(DEFAULT_ROUTE))
+ }}
+ >
+ { this.context.t('cancel') }
+ </Button>
+ <Button
+ type="primary"
+ large
+ className="page-container__footer-button"
+ onClick={() => {
+ addToken(pendingToken)
+ .then(() => removeSuggestedTokens())
+ .then(() => history.push(DEFAULT_ROUTE))
+ }}
+ >
+ { this.context.t('addToken') }
+ </Button>
+ </header>
</div>
</div>
)
diff --git a/ui/app/components/pages/confirm-add-token/confirm-add-token.component.js b/ui/app/components/pages/confirm-add-token/confirm-add-token.component.js
index 3dcc8cda9..d3fec79d7 100644
--- a/ui/app/components/pages/confirm-add-token/confirm-add-token.component.js
+++ b/ui/app/components/pages/confirm-add-token/confirm-add-token.component.js
@@ -86,28 +86,30 @@ export default class ConfirmAddToken extends Component {
</div>
</div>
<div className="page-container__footer">
- <Button
- type="default"
- large
- className="page-container__footer-button"
- onClick={() => history.push(ADD_TOKEN_ROUTE)}
- >
- { this.context.t('back') }
- </Button>
- <Button
- type="primary"
- large
- className="page-container__footer-button"
- onClick={() => {
- addTokens(pendingTokens)
- .then(() => {
- clearPendingTokens()
- history.push(DEFAULT_ROUTE)
- })
- }}
- >
- { this.context.t('addTokens') }
- </Button>
+ <header>
+ <Button
+ type="default"
+ large
+ className="page-container__footer-button"
+ onClick={() => history.push(ADD_TOKEN_ROUTE)}
+ >
+ { this.context.t('back') }
+ </Button>
+ <Button
+ type="primary"
+ large
+ className="page-container__footer-button"
+ onClick={() => {
+ addTokens(pendingTokens)
+ .then(() => {
+ clearPendingTokens()
+ history.push(DEFAULT_ROUTE)
+ })
+ }}
+ >
+ { this.context.t('addTokens') }
+ </Button>
+ </header>
</div>
</div>
)
diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
index 56cfbccc8..707dad62d 100644
--- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
+++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
@@ -8,6 +8,7 @@ import {
INSUFFICIENT_FUNDS_ERROR_KEY,
TRANSACTION_ERROR_KEY,
} from '../../../constants/error-keys'
+import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../../constants/transactions'
export default class ConfirmTransactionBase extends Component {
static contextTypes = {
@@ -21,6 +22,7 @@ export default class ConfirmTransactionBase extends Component {
// Redux props
balance: PropTypes.string,
cancelTransaction: PropTypes.func,
+ cancelAllTransactions: PropTypes.func,
clearConfirmTransaction: PropTypes.func,
clearSend: PropTypes.func,
conversionRate: PropTypes.number,
@@ -42,12 +44,14 @@ export default class ConfirmTransactionBase extends Component {
sendTransaction: PropTypes.func,
showCustomizeGasModal: PropTypes.func,
showTransactionConfirmedModal: PropTypes.func,
+ showRejectTransactionsConfirmationModal: PropTypes.func,
toAddress: PropTypes.string,
tokenData: PropTypes.object,
tokenProps: PropTypes.object,
toName: PropTypes.string,
transactionStatus: PropTypes.string,
txData: PropTypes.object,
+ unapprovedTxCount: PropTypes.number,
// Component props
action: PropTypes.string,
contentComponent: PropTypes.node,
@@ -85,9 +89,9 @@ export default class ConfirmTransactionBase extends Component {
clearConfirmTransaction,
} = this.props
- if (transactionStatus === 'dropped') {
+ if (transactionStatus === DROPPED_STATUS || transactionStatus === CONFIRMED_STATUS) {
showTransactionConfirmedModal({
- onHide: () => {
+ onSubmit: () => {
clearConfirmTransaction()
history.push(DEFAULT_ROUTE)
},
@@ -248,6 +252,25 @@ export default class ConfirmTransactionBase extends Component {
onEdit({ txData, tokenData, tokenProps })
}
+ handleCancelAll () {
+ const {
+ cancelAllTransactions,
+ clearConfirmTransaction,
+ history,
+ showRejectTransactionsConfirmationModal,
+ unapprovedTxCount,
+ } = this.props
+
+ showRejectTransactionsConfirmationModal({
+ unapprovedTxCount,
+ async onSubmit () {
+ await cancelAllTransactions()
+ clearConfirmTransaction()
+ history.push(DEFAULT_ROUTE)
+ },
+ })
+ }
+
handleCancel () {
const { onCancel, txData, cancelTransaction, history, clearConfirmTransaction } = this.props
@@ -313,6 +336,7 @@ export default class ConfirmTransactionBase extends Component {
nonce,
assetImage,
warning,
+ unapprovedTxCount,
} = this.props
const { submitting, submitError } = this.state
@@ -336,6 +360,7 @@ export default class ConfirmTransactionBase extends Component {
dataComponent={this.renderData()}
contentComponent={contentComponent}
nonce={nonce}
+ unapprovedTxCount={unapprovedTxCount}
assetImage={assetImage}
identiconAddress={identiconAddress}
errorMessage={errorMessage || submitError}
@@ -343,6 +368,7 @@ export default class ConfirmTransactionBase extends Component {
warning={warning}
disabled={!propsValid || !valid || submitting}
onEdit={() => this.handleEdit()}
+ onCancelAll={() => this.handleCancelAll()}
onCancel={() => this.handleCancel()}
onSubmit={() => this.handleSubmit()}
/>
diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
index 8f54c8040..b34067686 100644
--- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
+++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
@@ -8,7 +8,7 @@ import {
clearConfirmTransaction,
updateGasAndCalculate,
} from '../../../ducks/confirm-transaction.duck'
-import { clearSend, cancelTx, updateAndApproveTx, showModal } from '../../../actions'
+import { clearSend, cancelTx, cancelTxs, updateAndApproveTx, showModal } from '../../../actions'
import {
INSUFFICIENT_FUNDS_ERROR_KEY,
GAS_LIMIT_TOO_LOW_ERROR_KEY,
@@ -17,7 +17,7 @@ import { getHexGasTotal } from '../../../helpers/confirm-transaction/util'
import { isBalanceSufficient } from '../../send/send.utils'
import { conversionGreaterThan } from '../../../conversion-util'
import { MIN_GAS_LIMIT_DEC } from '../../send/send.constants'
-import { addressSlicer } from '../../../util'
+import { addressSlicer, valuesFor } from '../../../util'
const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
return {
@@ -53,6 +53,8 @@ const mapStateToProps = (state, props) => {
selectedAddress,
selectedAddressTxList,
assetImages,
+ network,
+ unapprovedTxs,
} = metamask
const assetImage = assetImages[txParamsToAddress]
const { balance } = accounts[selectedAddress]
@@ -67,6 +69,12 @@ const mapStateToProps = (state, props) => {
const transaction = R.find(({ id }) => id === transactionId)(selectedAddressTxList)
const transactionStatus = transaction ? transaction.status : ''
+ const currentNetworkUnapprovedTxs = R.filter(
+ ({ metamaskNetworkId }) => metamaskNetworkId === network,
+ valuesFor(unapprovedTxs),
+ )
+ const unapprovedTxCount = currentNetworkUnapprovedTxs.length
+
return {
balance,
fromAddress,
@@ -90,6 +98,8 @@ const mapStateToProps = (state, props) => {
transactionStatus,
nonce,
assetImage,
+ unapprovedTxs,
+ unapprovedTxCount,
}
}
@@ -97,8 +107,8 @@ const mapDispatchToProps = dispatch => {
return {
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
clearSend: () => dispatch(clearSend()),
- showTransactionConfirmedModal: ({ onHide }) => {
- return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onHide }))
+ showTransactionConfirmedModal: ({ onSubmit }) => {
+ return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onSubmit }))
},
showCustomizeGasModal: ({ txData, onSubmit, validate }) => {
return dispatch(showModal({ name: 'CONFIRM_CUSTOMIZE_GAS', txData, onSubmit, validate }))
@@ -106,7 +116,11 @@ const mapDispatchToProps = dispatch => {
updateGasAndCalculate: ({ gasLimit, gasPrice }) => {
return dispatch(updateGasAndCalculate({ gasLimit, gasPrice }))
},
+ showRejectTransactionsConfirmationModal: ({ onSubmit, unapprovedTxCount }) => {
+ return dispatch(showModal({ name: 'REJECT_TRANSACTIONS', onSubmit, unapprovedTxCount }))
+ },
cancelTransaction: ({ id }) => dispatch(cancelTx({ id })),
+ cancelAllTransactions: (txList) => dispatch(cancelTxs(txList)),
sendTransaction: txData => dispatch(updateAndApproveTx(txData)),
}
}
@@ -156,8 +170,9 @@ const getValidateEditGas = ({ balance, conversionRate, txData }) => {
}
const mergeProps = (stateProps, dispatchProps, ownProps) => {
- const { balance, conversionRate, txData } = stateProps
+ const { balance, conversionRate, txData, unapprovedTxs } = stateProps
const {
+ cancelAllTransactions: dispatchCancelAllTransactions,
showCustomizeGasModal: dispatchShowCustomizeGasModal,
updateGasAndCalculate: dispatchUpdateGasAndCalculate,
...otherDispatchProps
@@ -174,6 +189,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
onSubmit: txData => dispatchUpdateGasAndCalculate(txData),
validate: validateEditGas,
}),
+ cancelAllTransactions: () => dispatchCancelAllTransactions(valuesFor(unapprovedTxs)),
}
}
diff --git a/ui/app/components/pages/create-account/connect-hardware/account-list.js b/ui/app/components/pages/create-account/connect-hardware/account-list.js
index 488a189ea..2767b2e1f 100644
--- a/ui/app/components/pages/create-account/connect-hardware/account-list.js
+++ b/ui/app/components/pages/create-account/connect-hardware/account-list.js
@@ -3,6 +3,7 @@ const PropTypes = require('prop-types')
const h = require('react-hyperscript')
const genAccountLink = require('../../../../../lib/account-link.js')
const Select = require('react-select').default
+import Button from '../../../button'
class AccountList extends Component {
constructor (props, context) {
@@ -143,22 +144,20 @@ class AccountList extends Component {
}
return h('div.new-account-connect-form__buttons', {}, [
- h(
- 'button.btn-default.btn--large.new-account-connect-form__button',
- {
- onClick: this.props.onCancel.bind(this),
- },
- [this.context.t('cancel')]
- ),
-
- h(
- `button.btn-primary.btn--large.new-account-connect-form__button.unlock ${disabled ? '.btn-primary--disabled' : ''}`,
- {
- onClick: this.props.onUnlockAccount.bind(this, this.props.device),
- ...buttonProps,
- },
- [this.context.t('unlock')]
- ),
+ h(Button, {
+ type: 'default',
+ large: true,
+ className: 'new-account-connect-form__button',
+ onClick: this.props.onCancel.bind(this),
+ }, [this.context.t('cancel')]),
+
+ h(Button, {
+ type: 'primary',
+ large: true,
+ className: 'new-account-connect-form__button unlock',
+ disabled,
+ onClick: this.props.onUnlockAccount.bind(this, this.props.device),
+ }, [this.context.t('unlock')]),
])
}
diff --git a/ui/app/components/pages/create-account/connect-hardware/connect-screen.js b/ui/app/components/pages/create-account/connect-hardware/connect-screen.js
index b3dfa4ee2..d3abf3119 100644
--- a/ui/app/components/pages/create-account/connect-hardware/connect-screen.js
+++ b/ui/app/components/pages/create-account/connect-hardware/connect-screen.js
@@ -1,6 +1,7 @@
const { Component } = require('react')
const PropTypes = require('prop-types')
const h = require('react-hyperscript')
+import Button from '../../../button'
class ConnectScreen extends Component {
constructor (props, context) {
@@ -60,13 +61,13 @@ class ConnectScreen extends Component {
h('h3.hw-connect__title', {}, this.context.t('browserNotSupported')),
h('p.hw-connect__msg', {}, this.context.t('chromeRequiredForHardwareWallets')),
]),
- h(
- 'button.btn-primary.btn--large',
- {
- onClick: () => global.platform.openWindow({
- url: 'https://google.com/chrome',
- }),
- },
+ h(Button, {
+ type: 'primary',
+ large: true,
+ onClick: () => global.platform.openWindow({
+ url: 'https://google.com/chrome',
+ }),
+ },
this.context.t('downloadGoogleChrome')
),
])
diff --git a/ui/app/components/pages/create-account/import-account/index.js b/ui/app/components/pages/create-account/import-account/index.js
index e2e973af9..48d8f8838 100644
--- a/ui/app/components/pages/create-account/import-account/index.js
+++ b/ui/app/components/pages/create-account/import-account/index.js
@@ -46,7 +46,7 @@ AccountImportSubview.prototype.render = function () {
},
onClick: () => {
global.platform.openWindow({
- url: 'https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI',
+ url: 'https://metamask.zendesk.com/hc/en-us/articles/360015289932',
})
},
}, this.context.t('here')),
diff --git a/ui/app/components/pages/create-account/import-account/json.js b/ui/app/components/pages/create-account/import-account/json.js
index dd57256a3..90279bbbd 100644
--- a/ui/app/components/pages/create-account/import-account/json.js
+++ b/ui/app/components/pages/create-account/import-account/json.js
@@ -8,6 +8,7 @@ const actions = require('../../../../actions')
const FileInput = require('react-simple-file-input').default
const { DEFAULT_ROUTE } = require('../../../../routes')
const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts'
+import Button from '../../../button'
class JsonImportSubview extends Component {
constructor (props) {
@@ -51,17 +52,19 @@ class JsonImportSubview extends Component {
h('div.new-account-create-form__buttons', {}, [
- h('button.btn-default.new-account-create-form__button', {
+ h(Button, {
+ type: 'default',
+ large: true,
+ className: 'new-account-create-form__button',
onClick: () => this.props.history.push(DEFAULT_ROUTE),
- }, [
- this.context.t('cancel'),
- ]),
+ }, [this.context.t('cancel')]),
- h('button.btn-primary.new-account-create-form__button', {
+ h(Button, {
+ type: 'primary',
+ large: true,
+ className: 'new-account-create-form__button',
onClick: () => this.createNewKeychain(),
- }, [
- this.context.t('import'),
- ]),
+ }, [this.context.t('import')]),
]),
@@ -82,7 +85,7 @@ class JsonImportSubview extends Component {
}
createNewKeychain () {
- const { firstAddress, displayWarning, importNewJsonAccount, setSelectedAddress } = this.props
+ const { firstAddress, displayWarning, importNewJsonAccount, setSelectedAddress, history } = this.props
const state = this.state
if (!state) {
diff --git a/ui/app/components/pages/create-account/import-account/private-key.js b/ui/app/components/pages/create-account/import-account/private-key.js
index 1db999f2f..8db1bfbdd 100644
--- a/ui/app/components/pages/create-account/import-account/private-key.js
+++ b/ui/app/components/pages/create-account/import-account/private-key.js
@@ -7,6 +7,7 @@ const PropTypes = require('prop-types')
const connect = require('react-redux').connect
const actions = require('../../../../actions')
const { DEFAULT_ROUTE } = require('../../../../routes')
+import Button from '../../../button'
PrivateKeyImportView.contextTypes = {
t: PropTypes.func,
@@ -61,20 +62,22 @@ PrivateKeyImportView.prototype.render = function () {
h('div.new-account-import-form__buttons', {}, [
- h('button.btn-default.btn--large.new-account-create-form__button', {
+ h(Button, {
+ type: 'default',
+ large: true,
+ className: 'new-account-create-form__button',
onClick: () => {
displayWarning(null)
this.props.history.push(DEFAULT_ROUTE)
},
- }, [
- this.context.t('cancel'),
- ]),
+ }, [this.context.t('cancel')]),
- h('button.btn-primary.btn--large.new-account-create-form__button', {
+ h(Button, {
+ type: 'primary',
+ large: true,
+ className: 'new-account-create-form__button',
onClick: () => this.createNewKeychain(),
- }, [
- this.context.t('import'),
- ]),
+ }, [this.context.t('import')]),
]),
diff --git a/ui/app/components/pages/create-account/new-account.js b/ui/app/components/pages/create-account/new-account.js
index 402b8f03b..94a5fa487 100644
--- a/ui/app/components/pages/create-account/new-account.js
+++ b/ui/app/components/pages/create-account/new-account.js
@@ -4,6 +4,7 @@ const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('../../../actions')
const { DEFAULT_ROUTE } = require('../../../routes')
+import Button from '../../button'
class NewAccountCreateForm extends Component {
constructor (props, context) {
@@ -38,20 +39,22 @@ class NewAccountCreateForm extends Component {
h('div.new-account-create-form__buttons', {}, [
- h('button.btn-default.btn--large.new-account-create-form__button', {
+ h(Button, {
+ type: 'default',
+ large: true,
+ className: 'new-account-create-form__button',
onClick: () => history.push(DEFAULT_ROUTE),
- }, [
- this.context.t('cancel'),
- ]),
+ }, [this.context.t('cancel')]),
- h('button.btn-primary.btn--large.new-account-create-form__button', {
+ h(Button, {
+ type: 'primary',
+ large: true,
+ className: 'new-account-create-form__button',
onClick: () => {
createAccount(newAccountName || defaultAccountName)
.then(() => history.push(DEFAULT_ROUTE))
},
- }, [
- this.context.t('create'),
- ]),
+ }, [this.context.t('create')]),
]),
diff --git a/ui/app/components/pages/index.scss b/ui/app/components/pages/index.scss
index b15c59863..6551278f5 100644
--- a/ui/app/components/pages/index.scss
+++ b/ui/app/components/pages/index.scss
@@ -3,3 +3,5 @@
@import './add-token/index';
@import './confirm-add-token/index';
+
+@import './settings/index';
diff --git a/ui/app/components/pages/keychains/reveal-seed.js b/ui/app/components/pages/keychains/reveal-seed.js
index 7d7d3f462..32557066f 100644
--- a/ui/app/components/pages/keychains/reveal-seed.js
+++ b/ui/app/components/pages/keychains/reveal-seed.js
@@ -8,6 +8,8 @@ const { requestRevealSeedWords } = require('../../../actions')
const { DEFAULT_ROUTE } = require('../../../routes')
const ExportTextContainer = require('../../export-text-container')
+import Button from '../../button'
+
const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN'
const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN'
@@ -106,13 +108,21 @@ class RevealSeedPage extends Component {
renderPasswordPromptFooter () {
return (
h('.page-container__footer', [
- h('button.btn-default.btn--large.page-container__footer-button', {
- onClick: () => this.props.history.push(DEFAULT_ROUTE),
- }, this.context.t('cancel')),
- h('button.btn-primary.btn--large.page-container__footer-button', {
- onClick: event => this.handleSubmit(event),
- disabled: this.state.password === '',
- }, this.context.t('next')),
+ h('header', [
+ h(Button, {
+ type: 'default',
+ large: true,
+ className: 'page-container__footer-button',
+ onClick: () => this.props.history.push(DEFAULT_ROUTE),
+ }, this.context.t('cancel')),
+ h(Button, {
+ type: 'primary',
+ large: true,
+ className: 'page-container__footer-button',
+ onClick: event => this.handleSubmit(event),
+ disabled: this.state.password === '',
+ }, this.context.t('next')),
+ ]),
])
)
}
@@ -120,7 +130,10 @@ class RevealSeedPage extends Component {
renderRevealSeedFooter () {
return (
h('.page-container__footer', [
- h('button.btn-default.btn--large.page-container__footer-button', {
+ h(Button, {
+ type: 'default',
+ large: true,
+ className: 'page-container__footer-button',
onClick: () => this.props.history.push(DEFAULT_ROUTE),
}, this.context.t('close')),
])
diff --git a/ui/app/components/pages/settings/index.js b/ui/app/components/pages/settings/index.js
index aee17e0e8..44a9ffa63 100644
--- a/ui/app/components/pages/settings/index.js
+++ b/ui/app/components/pages/settings/index.js
@@ -1,64 +1 @@
-const { Component } = require('react')
-const { Switch, Route, matchPath } = require('react-router-dom')
-const PropTypes = require('prop-types')
-const h = require('react-hyperscript')
-const TabBar = require('../../tab-bar')
-const Settings = require('./settings')
-const Info = require('./info')
-const { DEFAULT_ROUTE, SETTINGS_ROUTE, INFO_ROUTE } = require('../../../routes')
-
-class Config extends Component {
- renderTabs () {
- const { history, location } = this.props
-
- return h('div.settings__tabs', [
- h(TabBar, {
- tabs: [
- { content: this.context.t('settings'), key: SETTINGS_ROUTE },
- { content: this.context.t('info'), key: INFO_ROUTE },
- ],
- isActive: key => matchPath(location.pathname, { path: key, exact: true }),
- onSelect: key => history.push(key),
- }),
- ])
- }
-
- render () {
- const { history } = this.props
-
- return (
- h('.main-container.settings', {}, [
- h('.settings__header', [
- h('div.settings__close-button', {
- onClick: () => history.push(DEFAULT_ROUTE),
- }),
- this.renderTabs(),
- ]),
- h(Switch, [
- h(Route, {
- exact: true,
- path: INFO_ROUTE,
- component: Info,
- }),
- h(Route, {
- exact: true,
- path: SETTINGS_ROUTE,
- component: Settings,
- }),
- ]),
- ])
- )
- }
-}
-
-Config.propTypes = {
- location: PropTypes.object,
- history: PropTypes.object,
- t: PropTypes.func,
-}
-
-Config.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = Config
+export { default } from './settings.component'
diff --git a/ui/app/components/pages/settings/index.scss b/ui/app/components/pages/settings/index.scss
new file mode 100644
index 000000000..138ebcfc5
--- /dev/null
+++ b/ui/app/components/pages/settings/index.scss
@@ -0,0 +1,80 @@
+@import './info-tab/index';
+
+@import './settings-tab/index';
+
+.settings-page {
+ position: relative;
+ background: $white;
+ display: flex;
+ flex-flow: column nowrap;
+
+ &__header {
+ padding: 25px 25px 0;
+ }
+
+ &__close-button::after {
+ content: '\00D7';
+ font-size: 40px;
+ color: $dusty-gray;
+ position: absolute;
+ top: 25px;
+ right: 30px;
+ cursor: pointer;
+ }
+
+ &__content {
+ padding: 25px;
+ height: auto;
+ overflow: auto;
+ }
+
+ &__content-row {
+ display: flex;
+ flex-direction: row;
+ padding: 10px 0 20px;
+
+ @media screen and (max-width: 575px) {
+ flex-direction: column;
+ padding: 10px 0;
+ }
+ }
+
+ &__content-item {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ padding: 0 5px;
+ min-height: 71px;
+
+ @media screen and (max-width: 575px) {
+ height: initial;
+ padding: 5px 0;
+ }
+
+ &--without-height {
+ height: initial;
+ }
+ }
+
+ &__content-label {
+ text-transform: capitalize;
+ }
+
+ &__content-description {
+ font-size: 14px;
+ color: $dusty-gray;
+ padding-top: 5px;
+ }
+
+ &__content-item-col {
+ max-width: 300px;
+ display: flex;
+ flex-direction: column;
+
+ @media screen and (max-width: 575px) {
+ max-width: 100%;
+ width: 100%;
+ }
+ }
+}
diff --git a/ui/app/components/pages/settings/info-tab/index.js b/ui/app/components/pages/settings/info-tab/index.js
new file mode 100644
index 000000000..7556a258d
--- /dev/null
+++ b/ui/app/components/pages/settings/info-tab/index.js
@@ -0,0 +1 @@
+export { default } from './info-tab.component'
diff --git a/ui/app/components/pages/settings/info-tab/index.scss b/ui/app/components/pages/settings/info-tab/index.scss
new file mode 100644
index 000000000..43ad6f652
--- /dev/null
+++ b/ui/app/components/pages/settings/info-tab/index.scss
@@ -0,0 +1,56 @@
+.info-tab {
+ &__logo-wrapper {
+ height: 80px;
+ margin-bottom: 20px;
+ }
+
+ &__logo {
+ max-height: 100%;
+ max-width: 100%;
+ }
+
+ &__item {
+ padding: 10px 0;
+ }
+
+ &__link-header {
+ padding-bottom: 15px;
+
+ @media screen and (max-width: 575px) {
+ padding-bottom: 5px;
+ }
+ }
+
+ &__link-item {
+ padding: 15px 0;
+
+ @media screen and (max-width: 575px) {
+ padding: 5px 0;
+ }
+ }
+
+ &__link-text {
+ color: $curious-blue;
+ }
+
+ &__version-number {
+ padding-top: 5px;
+ font-size: 13px;
+ color: $dusty-gray;
+ }
+
+ &__separator {
+ margin: 15px 0;
+ width: 80px;
+ border-color: $alto;
+ border: none;
+ height: 1px;
+ background-color: $alto;
+ color: $alto;
+ }
+
+ &__about {
+ color: $dusty-gray;
+ margin-bottom: 15px;
+ }
+}
diff --git a/ui/app/components/pages/settings/info-tab/info-tab.component.js b/ui/app/components/pages/settings/info-tab/info-tab.component.js
new file mode 100644
index 000000000..72f7d835e
--- /dev/null
+++ b/ui/app/components/pages/settings/info-tab/info-tab.component.js
@@ -0,0 +1,136 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+
+export default class InfoTab extends PureComponent {
+ state = {
+ version: global.platform.getVersion(),
+ }
+
+ static propTypes = {
+ tab: PropTypes.string,
+ metamask: PropTypes.object,
+ setCurrentCurrency: PropTypes.func,
+ setRpcTarget: PropTypes.func,
+ displayWarning: PropTypes.func,
+ revealSeedConfirmation: PropTypes.func,
+ warning: PropTypes.string,
+ location: PropTypes.object,
+ history: PropTypes.object,
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ renderInfoLinks () {
+ const { t } = this.context
+
+ return (
+ <div className="settings-page__content-item settings-page__content-item--without-height">
+ <div className="info-tab__link-header">
+ { t('links') }
+ </div>
+ <div className="info-tab__link-item">
+ <a
+ href="https://metamask.io/privacy.html"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ <span className="info-tab__link-text">
+ { t('privacyMsg') }
+ </span>
+ </a>
+ </div>
+ <div className="info-tab__link-item">
+ <a
+ href="https://metamask.io/terms.html"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ <span className="info-tab__link-text">
+ { t('terms') }
+ </span>
+ </a>
+ </div>
+ <div className="info-tab__link-item">
+ <a
+ href="https://metamask.io/attributions.html"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ <span className="info-tab__link-text">
+ { t('attributions') }
+ </span>
+ </a>
+ </div>
+ <hr className="info-tab__separator" />
+ <div className="info-tab__link-item">
+ <a
+ href="https://support.metamask.io"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ <span className="info-tab__link-text">
+ { t('supportCenter') }
+ </span>
+ </a>
+ </div>
+ <div className="info-tab__link-item">
+ <a
+ href="https://metamask.io/"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ <span className="info-tab__link-text">
+ { t('visitWebSite') }
+ </span>
+ </a>
+ </div>
+ <div className="info-tab__link-item">
+ <a
+ href="mailto:help@metamask.io?subject=Feedback"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ <span className="info-tab__link-text">
+ { t('emailUs') }
+ </span>
+ </a>
+ </div>
+ </div>
+ )
+ }
+
+ render () {
+ const { t } = this.context
+
+ return (
+ <div className="settings-page__content">
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item settings-page__content-item--without-height">
+ <div className="info-tab__logo-wrapper">
+ <img
+ src="images/info-logo.png"
+ className="info-tab__logo"
+ />
+ </div>
+ <div className="info-tab__item">
+ <div className="info-tab__version-header">
+ { t('metamaskVersion') }
+ </div>
+ <div className="info-tab__version-number">
+ { this.state.version }
+ </div>
+ </div>
+ <div className="info-tab__item">
+ <div className="info-tab__about">
+ { t('builtInCalifornia') }
+ </div>
+ </div>
+ </div>
+ { this.renderInfoLinks() }
+ </div>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/pages/settings/info.js b/ui/app/components/pages/settings/info.js
deleted file mode 100644
index bd9040499..000000000
--- a/ui/app/components/pages/settings/info.js
+++ /dev/null
@@ -1,120 +0,0 @@
-const { Component } = require('react')
-const PropTypes = require('prop-types')
-const h = require('react-hyperscript')
-
-class Info extends Component {
- constructor (props) {
- super(props)
-
- this.state = {
- version: global.platform.getVersion(),
- }
- }
-
- renderLogo () {
- return (
- h('div.settings__info-logo-wrapper', [
- h('img.settings__info-logo', { src: 'images/info-logo.png' }),
- ])
- )
- }
-
- renderInfoLinks () {
- return (
- h('div.settings__content-item.settings__content-item--without-height', [
- h('div.settings__info-link-header', this.context.t('links')),
- h('div.settings__info-link-item', [
- h('a', {
- href: 'https://metamask.io/privacy.html',
- target: '_blank',
- }, [
- h('span.settings__info-link', this.context.t('privacyMsg')),
- ]),
- ]),
- h('div.settings__info-link-item', [
- h('a', {
- href: 'https://metamask.io/terms.html',
- target: '_blank',
- }, [
- h('span.settings__info-link', this.context.t('terms')),
- ]),
- ]),
- h('div.settings__info-link-item', [
- h('a', {
- href: 'https://metamask.io/attributions.html',
- target: '_blank',
- }, [
- h('span.settings__info-link', this.context.t('attributions')),
- ]),
- ]),
- h('hr.settings__info-separator'),
- h('div.settings__info-link-item', [
- h('a', {
- href: 'https://support.metamask.io',
- target: '_blank',
- }, [
- h('span.settings__info-link', this.context.t('supportCenter')),
- ]),
- ]),
- h('div.settings__info-link-item', [
- h('a', {
- href: 'https://metamask.io/',
- target: '_blank',
- }, [
- h('span.settings__info-link', this.context.t('visitWebSite')),
- ]),
- ]),
- h('div.settings__info-link-item', [
- h('a', {
- target: '_blank',
- href: 'mailto:help@metamask.io?subject=Feedback',
- }, [
- h('span.settings__info-link', this.context.t('emailUs')),
- ]),
- ]),
- ])
- )
- }
-
- render () {
- return (
- h('div.settings__content', [
- h('div.settings__content-row', [
- h('div.settings__content-item.settings__content-item--without-height', [
- this.renderLogo(),
- h('div.settings__info-item', [
- h('div.settings__info-version-header', 'MetaMask Version'),
- h('div.settings__info-version-number', this.state.version),
- ]),
- h('div.settings__info-item', [
- h(
- 'div.settings__info-about',
- this.context.t('builtInCalifornia')
- ),
- ]),
- ]),
- this.renderInfoLinks(),
- ]),
- ])
- )
- }
-}
-
-Info.propTypes = {
- tab: PropTypes.string,
- metamask: PropTypes.object,
- setCurrentCurrency: PropTypes.func,
- setRpcTarget: PropTypes.func,
- displayWarning: PropTypes.func,
- revealSeedConfirmation: PropTypes.func,
- warning: PropTypes.string,
- location: PropTypes.object,
- history: PropTypes.object,
- t: PropTypes.func,
-}
-
-Info.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = Info
diff --git a/ui/app/components/pages/settings/settings-tab/index.js b/ui/app/components/pages/settings/settings-tab/index.js
new file mode 100644
index 000000000..9fdaafd3f
--- /dev/null
+++ b/ui/app/components/pages/settings/settings-tab/index.js
@@ -0,0 +1 @@
+export { default } from './settings-tab.container'
diff --git a/ui/app/components/pages/settings/settings-tab/index.scss b/ui/app/components/pages/settings/settings-tab/index.scss
new file mode 100644
index 000000000..76a0cec6f
--- /dev/null
+++ b/ui/app/components/pages/settings/settings-tab/index.scss
@@ -0,0 +1,51 @@
+.settings-tab {
+ &__error {
+ padding-bottom: 20px;
+ text-align: center;
+ color: $crimson;
+ }
+
+ &__rpc-save-button {
+ align-self: flex-end;
+ padding: 5px;
+ text-transform: uppercase;
+ color: $dusty-gray;
+ cursor: pointer;
+ }
+
+ &__rpc-save-button {
+ align-self: flex-end;
+ padding: 5px;
+ text-transform: uppercase;
+ color: $dusty-gray;
+ cursor: pointer;
+ }
+
+ &__button--red {
+ border-color: lighten($monzo, 10%);
+ color: $monzo;
+
+ &:active {
+ background: lighten($monzo, 55%);
+ border-color: $monzo;
+ }
+
+ &:hover {
+ border-color: $monzo;
+ }
+ }
+
+ &__button--orange {
+ border-color: lighten($ecstasy, 20%);
+ color: $ecstasy;
+
+ &:active {
+ background: lighten($ecstasy, 40%);
+ border-color: $ecstasy;
+ }
+
+ &:hover {
+ border-color: $ecstasy;
+ }
+ }
+}
diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js
new file mode 100644
index 000000000..9da624f56
--- /dev/null
+++ b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js
@@ -0,0 +1,360 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import infuraCurrencies from '../../../../infura-conversion.json'
+import validUrl from 'valid-url'
+import { exportAsFile } from '../../../../util'
+import SimpleDropdown from '../../../dropdowns/simple-dropdown'
+import ToggleButton from 'react-toggle-button'
+import { REVEAL_SEED_ROUTE } from '../../../../routes'
+import locales from '../../../../../../app/_locales/index.json'
+import TextField from '../../../text-field'
+import Button from '../../../button'
+
+const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => {
+ return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase())
+})
+
+const infuraCurrencyOptions = sortedCurrencies.map(({ quote: { code, name } }) => {
+ return {
+ displayValue: `${code.toUpperCase()} - ${name}`,
+ key: code,
+ value: code,
+ }
+})
+
+const localeOptions = locales.map(locale => {
+ return {
+ displayValue: `${locale.name}`,
+ key: locale.code,
+ value: locale.code,
+ }
+})
+
+export default class SettingsTab extends PureComponent {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ metamask: PropTypes.object,
+ setUseBlockie: PropTypes.func,
+ setHexDataFeatureFlag: PropTypes.func,
+ setCurrentCurrency: PropTypes.func,
+ setRpcTarget: PropTypes.func,
+ delRpcTarget: PropTypes.func,
+ displayWarning: PropTypes.func,
+ revealSeedConfirmation: PropTypes.func,
+ setFeatureFlagToBeta: PropTypes.func,
+ showResetAccountConfirmationModal: PropTypes.func,
+ warning: PropTypes.string,
+ history: PropTypes.object,
+ isMascara: PropTypes.bool,
+ updateCurrentLocale: PropTypes.func,
+ currentLocale: PropTypes.string,
+ useBlockie: PropTypes.bool,
+ sendHexData: PropTypes.bool,
+ currentCurrency: PropTypes.string,
+ conversionDate: PropTypes.number,
+ }
+
+ state = {
+ newRpc: '',
+ }
+
+ renderCurrentConversion () {
+ const { t } = this.context
+ const { currentCurrency, conversionDate, setCurrentCurrency } = this.props
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ t('currentConversion') }</span>
+ <span className="settings-page__content-description">
+ { t('updatedWithDate', [Date(conversionDate)]) }
+ </span>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <SimpleDropdown
+ placeholder={t('selectCurrency')}
+ options={infuraCurrencyOptions}
+ selectedOption={currentCurrency}
+ onSelect={newCurrency => setCurrentCurrency(newCurrency)}
+ />
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ renderCurrentLocale () {
+ const { t } = this.context
+ const { updateCurrentLocale, currentLocale } = this.props
+ const currentLocaleMeta = locales.find(locale => locale.code === currentLocale)
+ const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : ''
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span className="settings-page__content-label">
+ { t('currentLanguage') }
+ </span>
+ <span className="settings-page__content-description">
+ { currentLocaleName }
+ </span>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <SimpleDropdown
+ placeholder={t('selectLocale')}
+ options={localeOptions}
+ selectedOption={currentLocale}
+ onSelect={async newLocale => updateCurrentLocale(newLocale)}
+ />
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ renderNewRpcUrl () {
+ const { t } = this.context
+ const { newRpc } = this.state
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ t('newRPC') }</span>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <TextField
+ type="text"
+ id="new-rpc"
+ placeholder={t('newRPC')}
+ value={newRpc}
+ onChange={e => this.setState({ newRpc: e.target.value })}
+ onKeyPress={e => {
+ if (e.key === 'Enter') {
+ this.validateRpc(newRpc)
+ }
+ }}
+ fullWidth
+ margin="none"
+ />
+ <div
+ className="settings-tab__rpc-save-button"
+ onClick={e => {
+ e.preventDefault()
+ this.validateRpc(newRpc)
+ }}
+ >
+ { t('save') }
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ validateRpc (newRpc) {
+ const { setRpcTarget, displayWarning } = this.props
+
+ if (validUrl.isWebUri(newRpc)) {
+ setRpcTarget(newRpc)
+ } else {
+ const appendedRpc = `http://${newRpc}`
+
+ if (validUrl.isWebUri(appendedRpc)) {
+ displayWarning(this.context.t('uriErrorMsg'))
+ } else {
+ displayWarning(this.context.t('invalidRPC'))
+ }
+ }
+ }
+
+ renderStateLogs () {
+ const { t } = this.context
+ const { displayWarning } = this.props
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ t('stateLogs') }</span>
+ <span className="settings-page__content-description">
+ { t('stateLogsDescription') }
+ </span>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <Button
+ type="primary"
+ large
+ onClick={() => {
+ window.logStateString((err, result) => {
+ if (err) {
+ displayWarning(t('stateLogError'))
+ } else {
+ exportAsFile('MetaMask State Logs.json', result)
+ }
+ })
+ }}
+ >
+ { t('downloadStateLogs') }
+ </Button>
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ renderSeedWords () {
+ const { t } = this.context
+ const { history } = this.props
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ t('revealSeedWords') }</span>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <Button
+ type="secondary"
+ large
+ onClick={event => {
+ event.preventDefault()
+ history.push(REVEAL_SEED_ROUTE)
+ }}
+ >
+ { t('revealSeedWords') }
+ </Button>
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ renderOldUI () {
+ const { t } = this.context
+ const { setFeatureFlagToBeta } = this.props
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ t('useOldUI') }</span>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <Button
+ type="secondary"
+ large
+ className="settings-tab__button--orange"
+ onClick={event => {
+ event.preventDefault()
+ setFeatureFlagToBeta()
+ }}
+ >
+ { t('useOldUI') }
+ </Button>
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ renderResetAccount () {
+ const { t } = this.context
+ const { showResetAccountConfirmationModal } = this.props
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ t('resetAccount') }</span>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <Button
+ type="secondary"
+ large
+ className="settings-tab__button--orange"
+ onClick={event => {
+ event.preventDefault()
+ showResetAccountConfirmationModal()
+ }}
+ >
+ { t('resetAccount') }
+ </Button>
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ renderBlockieOptIn () {
+ const { useBlockie, setUseBlockie } = this.props
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ this.context.t('blockiesIdenticon') }</span>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <ToggleButton
+ value={useBlockie}
+ onToggle={value => setUseBlockie(!value)}
+ activeLabel=""
+ inactiveLabel=""
+ />
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ renderHexDataOptIn () {
+ const { t } = this.context
+ const { sendHexData, setHexDataFeatureFlag } = this.props
+
+ return (
+ <div className="settings-page__content-row">
+ <div className="settings-page__content-item">
+ <span>{ t('showHexData') }</span>
+ <div className="settings-page__content-description">
+ { t('showHexDataDescription') }
+ </div>
+ </div>
+ <div className="settings-page__content-item">
+ <div className="settings-page__content-item-col">
+ <ToggleButton
+ value={sendHexData}
+ onToggle={value => setHexDataFeatureFlag(!value)}
+ activeLabel=""
+ inactiveLabel=""
+ />
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ render () {
+ const { warning, isMascara } = this.props
+
+ return (
+ <div className="settings-page__content">
+ { warning && <div className="settings-tab__error">{ warning }</div> }
+ { this.renderCurrentConversion() }
+ { this.renderCurrentLocale() }
+ { this.renderNewRpcUrl() }
+ { this.renderStateLogs() }
+ { this.renderSeedWords() }
+ { !isMascara && this.renderOldUI() }
+ { this.renderResetAccount() }
+ { this.renderBlockieOptIn() }
+ { this.renderHexDataOptIn() }
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js
new file mode 100644
index 000000000..665b56f5c
--- /dev/null
+++ b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js
@@ -0,0 +1,59 @@
+import SettingsTab from './settings-tab.component'
+import { compose } from 'recompose'
+import { connect } from 'react-redux'
+import { withRouter } from 'react-router-dom'
+import {
+ setCurrentCurrency,
+ setRpcTarget,
+ displayWarning,
+ revealSeedConfirmation,
+ setUseBlockie,
+ updateCurrentLocale,
+ setFeatureFlag,
+ showModal,
+} from '../../../../actions'
+
+const mapStateToProps = state => {
+ const { appState: { warning }, metamask } = state
+ const {
+ currentCurrency,
+ conversionDate,
+ useBlockie,
+ featureFlags: { sendHexData } = {},
+ provider = {},
+ isMascara,
+ currentLocale,
+ } = metamask
+
+ return {
+ warning,
+ isMascara,
+ currentLocale,
+ currentCurrency,
+ conversionDate,
+ useBlockie,
+ sendHexData,
+ provider,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ setCurrentCurrency: currency => dispatch(setCurrentCurrency(currency)),
+ setRpcTarget: newRpc => dispatch(setRpcTarget(newRpc)),
+ displayWarning: warning => dispatch(displayWarning(warning)),
+ revealSeedConfirmation: () => dispatch(revealSeedConfirmation()),
+ setUseBlockie: value => dispatch(setUseBlockie(value)),
+ updateCurrentLocale: key => dispatch(updateCurrentLocale(key)),
+ setFeatureFlagToBeta: () => {
+ return dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
+ },
+ setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)),
+ showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })),
+ }
+}
+
+export default compose(
+ withRouter,
+ connect(mapStateToProps, mapDispatchToProps)
+)(SettingsTab)
diff --git a/ui/app/components/pages/settings/settings.component.js b/ui/app/components/pages/settings/settings.component.js
new file mode 100644
index 000000000..94a97bba1
--- /dev/null
+++ b/ui/app/components/pages/settings/settings.component.js
@@ -0,0 +1,54 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import { Switch, Route, matchPath } from 'react-router-dom'
+import TabBar from '../../tab-bar'
+import SettingsTab from './settings-tab'
+import InfoTab from './info-tab'
+import { DEFAULT_ROUTE, SETTINGS_ROUTE, INFO_ROUTE } from '../../../routes'
+
+export default class SettingsPage extends PureComponent {
+ static propTypes = {
+ location: PropTypes.object,
+ history: PropTypes.object,
+ t: PropTypes.func,
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ render () {
+ const { history, location } = this.props
+
+ return (
+ <div className="main-container settings-page">
+ <div className="settings-page__header">
+ <div
+ className="settings-page__close-button"
+ onClick={() => history.push(DEFAULT_ROUTE)}
+ />
+ <TabBar
+ tabs={[
+ { content: this.context.t('settings'), key: SETTINGS_ROUTE },
+ { content: this.context.t('info'), key: INFO_ROUTE },
+ ]}
+ isActive={key => matchPath(location.pathname, { path: key, exact: true })}
+ onSelect={key => history.push(key)}
+ />
+ </div>
+ <Switch>
+ <Route
+ exact
+ path={INFO_ROUTE}
+ component={InfoTab}
+ />
+ <Route
+ exact
+ path={SETTINGS_ROUTE}
+ component={SettingsTab}
+ />
+ </Switch>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/pages/settings/settings.js b/ui/app/components/pages/settings/settings.js
deleted file mode 100644
index a5ea1b89c..000000000
--- a/ui/app/components/pages/settings/settings.js
+++ /dev/null
@@ -1,394 +0,0 @@
-const { Component } = require('react')
-const { withRouter } = require('react-router-dom')
-const { compose } = require('recompose')
-const PropTypes = require('prop-types')
-const h = require('react-hyperscript')
-const connect = require('react-redux').connect
-const actions = require('../../../actions')
-const infuraCurrencies = require('../../../infura-conversion.json')
-const validUrl = require('valid-url')
-const { exportAsFile } = require('../../../util')
-const SimpleDropdown = require('../../dropdowns/simple-dropdown')
-const ToggleButton = require('react-toggle-button')
-const { REVEAL_SEED_ROUTE } = require('../../../routes')
-const locales = require('../../../../../app/_locales/index.json')
-
-const getInfuraCurrencyOptions = () => {
- const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => {
- return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase())
- })
-
- return sortedCurrencies.map(({ quote: { code, name } }) => {
- return {
- displayValue: `${code.toUpperCase()} - ${name}`,
- key: code,
- value: code,
- }
- })
-}
-
-const getLocaleOptions = () => {
- return locales.map((locale) => {
- return {
- displayValue: `${locale.name}`,
- key: locale.code,
- value: locale.code,
- }
- })
-}
-
-class Settings extends Component {
- constructor (props) {
- super(props)
-
- this.state = {
- newRpc: '',
- }
- }
-
- renderBlockieOptIn () {
- const { metamask: { useBlockie }, setUseBlockie } = this.props
-
- return h('div.settings__content-row', [
- h('div.settings__content-item', [
- h('span', this.context.t('blockiesIdenticon')),
- ]),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h(ToggleButton, {
- value: useBlockie,
- onToggle: (value) => setUseBlockie(!value),
- activeLabel: '',
- inactiveLabel: '',
- }),
- ]),
- ]),
- ])
- }
-
- renderHexDataOptIn () {
- const { metamask: { featureFlags: { sendHexData } }, setHexDataFeatureFlag } = this.props
-
- return h('div.settings__content-row', [
- h('div.settings__content-item', [
- h('span', this.context.t('showHexData')),
- h(
- 'div.settings__content-description',
- this.context.t('showHexDataDescription')
- ),
- ]),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h(ToggleButton, {
- value: sendHexData,
- onToggle: (value) => setHexDataFeatureFlag(!value),
- activeLabel: '',
- inactiveLabel: '',
- }),
- ]),
- ]),
- ])
- }
-
- renderCurrentConversion () {
- const { metamask: { currentCurrency, conversionDate }, setCurrentCurrency } = this.props
-
- return h('div.settings__content-row', [
- h('div.settings__content-item', [
- h('span', this.context.t('currentConversion')),
- h('span.settings__content-description', `Updated ${Date(conversionDate)}`),
- ]),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h(SimpleDropdown, {
- placeholder: this.context.t('selectCurrency'),
- options: getInfuraCurrencyOptions(),
- selectedOption: currentCurrency,
- onSelect: newCurrency => setCurrentCurrency(newCurrency),
- }),
- ]),
- ]),
- ])
- }
-
- renderCurrentLocale () {
- const { updateCurrentLocale, currentLocale } = this.props
- const currentLocaleMeta = locales.find(locale => locale.code === currentLocale)
- const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : ''
-
- return h('div.settings__content-row', [
- h('div.settings__content-item', [
- h('span', 'Current Language'),
- h('span.settings__content-description', `${currentLocaleName}`),
- ]),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h(SimpleDropdown, {
- placeholder: 'Select Locale',
- options: getLocaleOptions(),
- selectedOption: currentLocale,
- onSelect: async (newLocale) => {
- updateCurrentLocale(newLocale)
- },
- }),
- ]),
- ]),
- ])
- }
-
- renderCurrentProvider () {
- const { metamask: { provider = {} } } = this.props
- let title, value, color
-
- switch (provider.type) {
-
- case 'mainnet':
- title = this.context.t('currentNetwork')
- value = this.context.t('mainnet')
- color = '#038789'
- break
-
- case 'ropsten':
- title = this.context.t('currentNetwork')
- value = this.context.t('ropsten')
- color = '#e91550'
- break
-
- case 'kovan':
- title = this.context.t('currentNetwork')
- value = this.context.t('kovan')
- color = '#690496'
- break
-
- case 'rinkeby':
- title = this.context.t('currentNetwork')
- value = this.context.t('rinkeby')
- color = '#ebb33f'
- break
-
- default:
- title = this.context.t('currentRpc')
- value = provider.rpcTarget
- }
-
- return h('div.settings__content-row', [
- h('div.settings__content-item', title),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h('div.settings__provider-wrapper', [
- h('div.settings__provider-icon', { style: { background: color } }),
- h('div', value),
- ]),
- ]),
- ]),
- ])
- }
-
- renderNewRpcUrl () {
- return (
- h('div.settings__content-row', [
- h('div.settings__content-item', [
- h('span', this.context.t('newRPC')),
- ]),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h('input.settings__input', {
- placeholder: this.context.t('newRPC'),
- onChange: event => this.setState({ newRpc: event.target.value }),
- onKeyPress: event => {
- if (event.key === 'Enter') {
- this.validateRpc(this.state.newRpc)
- }
- },
- }),
- h('div.settings__rpc-save-button', {
- onClick: event => {
- event.preventDefault()
- this.validateRpc(this.state.newRpc)
- },
- }, this.context.t('save')),
- ]),
- ]),
- ])
- )
- }
-
- validateRpc (newRpc) {
- const { setRpcTarget, displayWarning } = this.props
-
- if (validUrl.isWebUri(newRpc)) {
- setRpcTarget(newRpc)
- } else {
- const appendedRpc = `http://${newRpc}`
-
- if (validUrl.isWebUri(appendedRpc)) {
- displayWarning(this.context.t('uriErrorMsg'))
- } else {
- displayWarning(this.context.t('invalidRPC'))
- }
- }
- }
-
- renderStateLogs () {
- return (
- h('div.settings__content-row', [
- h('div.settings__content-item', [
- h('div', this.context.t('stateLogs')),
- h(
- 'div.settings__content-description',
- this.context.t('stateLogsDescription')
- ),
- ]),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h('button.btn-primary.btn--large.settings__button', {
- onClick (event) {
- window.logStateString((err, result) => {
- if (err) {
- this.state.dispatch(actions.displayWarning(this.context.t('stateLogError')))
- } else {
- exportAsFile('MetaMask State Logs.json', result)
- }
- })
- },
- }, this.context.t('downloadStateLogs')),
- ]),
- ]),
- ])
- )
- }
-
- renderSeedWords () {
- const { history } = this.props
-
- return (
- h('div.settings__content-row', [
- h('div.settings__content-item', this.context.t('revealSeedWords')),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h('button.btn-primary.btn--large.settings__button--red', {
- onClick: event => {
- event.preventDefault()
- history.push(REVEAL_SEED_ROUTE)
- },
- }, this.context.t('revealSeedWords')),
- ]),
- ]),
- ])
- )
- }
-
- renderOldUI () {
- const { setFeatureFlagToBeta } = this.props
-
- return (
- h('div.settings__content-row', [
- h('div.settings__content-item', this.context.t('useOldUI')),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h('button.btn-primary.btn--large.settings__button--orange', {
- onClick (event) {
- event.preventDefault()
- setFeatureFlagToBeta()
- },
- }, this.context.t('useOldUI')),
- ]),
- ]),
- ])
- )
- }
-
- renderResetAccount () {
- const { showResetAccountConfirmationModal } = this.props
-
- return h('div.settings__content-row', [
- h('div.settings__content-item', this.context.t('resetAccount')),
- h('div.settings__content-item', [
- h('div.settings__content-item-col', [
- h('button.btn-primary.btn--large.settings__button--orange', {
- onClick (event) {
- event.preventDefault()
- showResetAccountConfirmationModal()
- },
- }, this.context.t('resetAccount')),
- ]),
- ]),
- ])
- }
-
- render () {
- const { warning, isMascara } = this.props
-
- return (
- h('div.settings__content', [
- warning && h('div.settings__error', warning),
- this.renderCurrentConversion(),
- this.renderCurrentLocale(),
- // this.renderCurrentProvider(),
- this.renderNewRpcUrl(),
- this.renderStateLogs(),
- this.renderSeedWords(),
- !isMascara && this.renderOldUI(),
- this.renderResetAccount(),
- this.renderBlockieOptIn(),
- this.renderHexDataOptIn(),
- ])
- )
- }
-}
-
-Settings.propTypes = {
- metamask: PropTypes.object,
- setUseBlockie: PropTypes.func,
- setHexDataFeatureFlag: PropTypes.func,
- setCurrentCurrency: PropTypes.func,
- setRpcTarget: PropTypes.func,
- displayWarning: PropTypes.func,
- revealSeedConfirmation: PropTypes.func,
- setFeatureFlagToBeta: PropTypes.func,
- showResetAccountConfirmationModal: PropTypes.func,
- warning: PropTypes.string,
- history: PropTypes.object,
- isMascara: PropTypes.bool,
- updateCurrentLocale: PropTypes.func,
- currentLocale: PropTypes.string,
- t: PropTypes.func,
-}
-
-const mapStateToProps = state => {
- return {
- metamask: state.metamask,
- warning: state.appState.warning,
- isMascara: state.metamask.isMascara,
- currentLocale: state.metamask.currentLocale,
- }
-}
-
-const mapDispatchToProps = dispatch => {
- return {
- setCurrentCurrency: currency => dispatch(actions.setCurrentCurrency(currency)),
- setRpcTarget: newRpc => dispatch(actions.setRpcTarget(newRpc)),
- displayWarning: warning => dispatch(actions.displayWarning(warning)),
- revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()),
- setUseBlockie: value => dispatch(actions.setUseBlockie(value)),
- updateCurrentLocale: key => dispatch(actions.updateCurrentLocale(key)),
- setFeatureFlagToBeta: () => {
- return dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
- },
- setHexDataFeatureFlag: (featureFlagShowState) => {
- return dispatch(actions.setFeatureFlag('sendHexData', featureFlagShowState))
- },
- showResetAccountConfirmationModal: () => {
- return dispatch(actions.showModal({ name: 'CONFIRM_RESET_ACCOUNT' }))
- },
- }
-}
-
-Settings.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = compose(
- withRouter,
- connect(mapStateToProps, mapDispatchToProps)
-)(Settings)
diff --git a/ui/app/components/pages/unlock-page/index.scss b/ui/app/components/pages/unlock-page/index.scss
index 3d44bd037..6bd52282d 100644
--- a/ui/app/components/pages/unlock-page/index.scss
+++ b/ui/app/components/pages/unlock-page/index.scss
@@ -14,6 +14,7 @@
align-self: stretch;
justify-content: center;
flex: 1 0 auto;
+ height: 100vh;
}
&__mascot-container {