1st part of refactoring: remove unused styles and components
This commit is contained in:
parent
7fad9fcc00
commit
36b863438f
|
@ -1,6 +1,5 @@
|
||||||
const injectCss = require('inject-css')
|
const injectCss = require('inject-css')
|
||||||
const OldMetaMaskUiCss = require('../../old-ui/css')
|
const OldMetaMaskUiCss = require('../../old-ui/css')
|
||||||
const NewMetaMaskUiCss = require('../../ui/css')
|
|
||||||
const startPopup = require('./popup-core')
|
const startPopup = require('./popup-core')
|
||||||
const PortStream = require('extension-port-stream')
|
const PortStream = require('extension-port-stream')
|
||||||
const { getEnvironmentType } = require('./lib/util')
|
const { getEnvironmentType } = require('./lib/util')
|
||||||
|
@ -45,25 +44,17 @@ async function start () {
|
||||||
// const { isMascara, identities = {}, featureFlags = {} } = store.getState().metamask
|
// const { isMascara, identities = {}, featureFlags = {} } = store.getState().metamask
|
||||||
// const firstTime = Object.keys(identities).length === 0
|
// const firstTime = Object.keys(identities).length === 0
|
||||||
const { isMascara, featureFlags = {} } = store.getState().metamask
|
const { isMascara, featureFlags = {} } = store.getState().metamask
|
||||||
let betaUIState = featureFlags.betaUI
|
|
||||||
|
|
||||||
// Code commented out until we begin auto adding users to NewUI
|
// Code commented out until we begin auto adding users to NewUI
|
||||||
// const useBetaCss = isMascara || firstTime || betaUIState
|
|
||||||
const useBetaCss = isMascara || betaUIState
|
|
||||||
|
|
||||||
let css = useBetaCss ? NewMetaMaskUiCss() : OldMetaMaskUiCss()
|
let css = OldMetaMaskUiCss()
|
||||||
let deleteInjectedCss = injectCss(css)
|
let deleteInjectedCss = injectCss(css)
|
||||||
let newBetaUIState
|
|
||||||
|
|
||||||
store.subscribe(() => {
|
store.subscribe(() => {
|
||||||
const state = store.getState()
|
const state = store.getState()
|
||||||
newBetaUIState = state.metamask.featureFlags.betaUI
|
|
||||||
if (newBetaUIState !== betaUIState) {
|
|
||||||
deleteInjectedCss()
|
deleteInjectedCss()
|
||||||
betaUIState = newBetaUIState
|
css = OldMetaMaskUiCss()
|
||||||
css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss()
|
|
||||||
deleteInjectedCss = injectCss(css)
|
deleteInjectedCss = injectCss(css)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
const Component = require('react').Component
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
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()),
|
|
||||||
setAccountLabel: (address, label) => dispatch(actions.setAccountLabel(address, label)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inherits(AccountDetailsModal, Component)
|
|
||||||
function AccountDetailsModal (props) {
|
|
||||||
Component.call(this)
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
displayedForm: props.displayedForm,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountDetailsModal.contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
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', this.context.t('newAccount')),
|
|
||||||
|
|
||||||
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'),
|
|
||||||
}, this.context.t('createDen')),
|
|
||||||
|
|
||||||
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'),
|
|
||||||
}, this.context.t('import')),
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('div.new-account__form', [
|
|
||||||
|
|
||||||
displayedForm === 'CREATE'
|
|
||||||
? h(NewAccountCreateForm)
|
|
||||||
: h(NewAccountImportForm),
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
])
|
|
||||||
}
|
|
365
ui/app/app.js
365
ui/app/app.js
|
@ -1,365 +0,0 @@
|
||||||
const { Component } = require('react')
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const { Route, Switch, withRouter } = require('react-router-dom')
|
|
||||||
const { compose } = require('recompose')
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const actions = require('./actions')
|
|
||||||
const classnames = require('classnames')
|
|
||||||
const log = require('loglevel')
|
|
||||||
const { getMetaMaskAccounts } = require('./selectors')
|
|
||||||
|
|
||||||
// init
|
|
||||||
const InitializeScreen = require('../../mascara/src/app/first-time').default
|
|
||||||
// accounts
|
|
||||||
const SendTransactionScreen = require('./components/send/send.container')
|
|
||||||
const ConfirmTransaction = require('./components/pages/confirm-transaction')
|
|
||||||
|
|
||||||
// slideout menu
|
|
||||||
const Sidebar = require('./components/sidebars').default
|
|
||||||
|
|
||||||
// other views
|
|
||||||
import Home from './components/pages/home'
|
|
||||||
import Settings from './components/pages/settings'
|
|
||||||
const Authenticated = require('./components/pages/authenticated')
|
|
||||||
const Initialized = require('./components/pages/initialized')
|
|
||||||
const RestoreVaultPage = require('./components/pages/keychains/restore-vault').default
|
|
||||||
const RevealSeedConfirmation = require('./components/pages/keychains/reveal-seed')
|
|
||||||
const AddTokenPage = require('./components/pages/add-token')
|
|
||||||
const ConfirmAddTokenPage = require('./components/pages/confirm-add-token')
|
|
||||||
const ConfirmAddSuggestedTokenPage = require('./components/pages/confirm-add-suggested-token')
|
|
||||||
const CreateAccountPage = require('./components/pages/create-account')
|
|
||||||
const NoticeScreen = require('./components/pages/notice')
|
|
||||||
|
|
||||||
const Loading = require('./components/loading-screen')
|
|
||||||
const NetworkDropdown = require('./components/dropdowns/network-dropdown')
|
|
||||||
const AccountMenu = require('./components/account-menu')
|
|
||||||
|
|
||||||
// Global Modals
|
|
||||||
const Modal = require('./components/modals/index').Modal
|
|
||||||
// Global Alert
|
|
||||||
const Alert = require('./components/alert')
|
|
||||||
|
|
||||||
import AppHeader from './components/app-header'
|
|
||||||
import UnlockPage from './components/pages/unlock-page'
|
|
||||||
|
|
||||||
// Routes
|
|
||||||
const {
|
|
||||||
DEFAULT_ROUTE,
|
|
||||||
UNLOCK_ROUTE,
|
|
||||||
SETTINGS_ROUTE,
|
|
||||||
REVEAL_SEED_ROUTE,
|
|
||||||
RESTORE_VAULT_ROUTE,
|
|
||||||
ADD_TOKEN_ROUTE,
|
|
||||||
CONFIRM_ADD_TOKEN_ROUTE,
|
|
||||||
CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE,
|
|
||||||
NEW_ACCOUNT_ROUTE,
|
|
||||||
SEND_ROUTE,
|
|
||||||
CONFIRM_TRANSACTION_ROUTE,
|
|
||||||
INITIALIZE_ROUTE,
|
|
||||||
NOTICE_ROUTE,
|
|
||||||
} = require('./routes')
|
|
||||||
|
|
||||||
class App extends Component {
|
|
||||||
componentWillMount () {
|
|
||||||
const { currentCurrency, setCurrentCurrencyToUSD } = this.props
|
|
||||||
|
|
||||||
if (!currentCurrency) {
|
|
||||||
setCurrentCurrencyToUSD()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRoutes () {
|
|
||||||
const exact = true
|
|
||||||
|
|
||||||
return (
|
|
||||||
h(Switch, [
|
|
||||||
h(Route, { path: INITIALIZE_ROUTE, component: InitializeScreen }),
|
|
||||||
h(Initialized, { path: UNLOCK_ROUTE, exact, component: UnlockPage }),
|
|
||||||
h(Initialized, { path: RESTORE_VAULT_ROUTE, exact, component: RestoreVaultPage }),
|
|
||||||
h(Authenticated, { path: REVEAL_SEED_ROUTE, exact, component: RevealSeedConfirmation }),
|
|
||||||
h(Authenticated, { path: SETTINGS_ROUTE, component: Settings }),
|
|
||||||
h(Authenticated, { path: NOTICE_ROUTE, exact, component: NoticeScreen }),
|
|
||||||
h(Authenticated, {
|
|
||||||
path: `${CONFIRM_TRANSACTION_ROUTE}/:id?`,
|
|
||||||
component: ConfirmTransaction,
|
|
||||||
}),
|
|
||||||
h(Authenticated, { path: SEND_ROUTE, exact, component: SendTransactionScreen }),
|
|
||||||
h(Authenticated, { path: ADD_TOKEN_ROUTE, exact, component: AddTokenPage }),
|
|
||||||
h(Authenticated, { path: CONFIRM_ADD_TOKEN_ROUTE, exact, component: ConfirmAddTokenPage }),
|
|
||||||
h(Authenticated, { path: CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE, exact, component: ConfirmAddSuggestedTokenPage }),
|
|
||||||
h(Authenticated, { path: NEW_ACCOUNT_ROUTE, component: CreateAccountPage }),
|
|
||||||
h(Authenticated, { path: DEFAULT_ROUTE, exact, component: Home }),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const {
|
|
||||||
isLoading,
|
|
||||||
alertMessage,
|
|
||||||
loadingMessage,
|
|
||||||
network,
|
|
||||||
isMouseUser,
|
|
||||||
provider,
|
|
||||||
frequentRpcList,
|
|
||||||
currentView,
|
|
||||||
setMouseUserState,
|
|
||||||
sidebar,
|
|
||||||
} = this.props
|
|
||||||
const isLoadingNetwork = network === 'loading' && currentView.name !== 'config'
|
|
||||||
const loadMessage = loadingMessage || isLoadingNetwork ?
|
|
||||||
this.getConnectingLabel(loadingMessage) : null
|
|
||||||
log.debug('Main ui render function')
|
|
||||||
|
|
||||||
return (
|
|
||||||
h('.flex-column.full-height', {
|
|
||||||
className: classnames({ 'mouse-user-styles': isMouseUser }),
|
|
||||||
style: {
|
|
||||||
overflowX: 'hidden',
|
|
||||||
position: 'relative',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
tabIndex: '0',
|
|
||||||
onClick: () => setMouseUserState(true),
|
|
||||||
onKeyDown: (e) => {
|
|
||||||
if (e.keyCode === 9) {
|
|
||||||
setMouseUserState(false)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
|
|
||||||
// global modal
|
|
||||||
h(Modal, {}, []),
|
|
||||||
|
|
||||||
// global alert
|
|
||||||
h(Alert, {visible: this.props.alertOpen, msg: alertMessage}),
|
|
||||||
|
|
||||||
h(AppHeader),
|
|
||||||
|
|
||||||
// sidebar
|
|
||||||
h(Sidebar, {
|
|
||||||
sidebarOpen: sidebar.isOpen,
|
|
||||||
hideSidebar: this.props.hideSidebar,
|
|
||||||
transitionName: sidebar.transitionName,
|
|
||||||
type: sidebar.type,
|
|
||||||
}),
|
|
||||||
|
|
||||||
// network dropdown
|
|
||||||
h(NetworkDropdown, {
|
|
||||||
provider,
|
|
||||||
frequentRpcList,
|
|
||||||
}, []),
|
|
||||||
|
|
||||||
h(AccountMenu),
|
|
||||||
|
|
||||||
h('div.main-container-wrapper', [
|
|
||||||
(isLoading || isLoadingNetwork) && h(Loading, {
|
|
||||||
loadingMessage: loadMessage,
|
|
||||||
}),
|
|
||||||
|
|
||||||
// content
|
|
||||||
this.renderRoutes(),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleMetamaskActive () {
|
|
||||||
if (!this.props.isUnlocked) {
|
|
||||||
// currently inactive: redirect to password box
|
|
||||||
var passwordBox = document.querySelector('input[type=password]')
|
|
||||||
if (!passwordBox) return
|
|
||||||
passwordBox.focus()
|
|
||||||
} else {
|
|
||||||
// currently active: deactivate
|
|
||||||
this.props.dispatch(actions.lockMetamask(false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getConnectingLabel = function (loadingMessage) {
|
|
||||||
if (loadingMessage) {
|
|
||||||
return loadingMessage
|
|
||||||
}
|
|
||||||
const { provider } = this.props
|
|
||||||
const providerName = provider.type
|
|
||||||
|
|
||||||
let name
|
|
||||||
|
|
||||||
if (providerName === 'mainnet') {
|
|
||||||
name = this.context.t('connectingToMainnet')
|
|
||||||
} else if (providerName === 'ropsten') {
|
|
||||||
name = this.context.t('connectingToRopsten')
|
|
||||||
} else if (providerName === 'kovan') {
|
|
||||||
name = this.context.t('connectingToKovan')
|
|
||||||
} else if (providerName === 'rinkeby') {
|
|
||||||
name = this.context.t('connectingToRinkeby')
|
|
||||||
} else if (providerName === 'poa') {
|
|
||||||
name = this.context.t('connectingToPOA')
|
|
||||||
} else {
|
|
||||||
name = this.context.t('connectingToUnknown')
|
|
||||||
}
|
|
||||||
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
getNetworkName () {
|
|
||||||
const { provider } = this.props
|
|
||||||
const providerName = provider.type
|
|
||||||
|
|
||||||
let name
|
|
||||||
|
|
||||||
if (providerName === 'mainnet') {
|
|
||||||
name = this.context.t('mainnet')
|
|
||||||
} else if (providerName === 'ropsten') {
|
|
||||||
name = this.context.t('ropsten')
|
|
||||||
} else if (providerName === 'kovan') {
|
|
||||||
name = this.context.t('kovan')
|
|
||||||
} else if (providerName === 'rinkeby') {
|
|
||||||
name = this.context.t('rinkeby')
|
|
||||||
} else if (providerName === 'poa') {
|
|
||||||
name = this.context.t('poa')
|
|
||||||
} else {
|
|
||||||
name = this.context.t('unknownNetwork')
|
|
||||||
}
|
|
||||||
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
App.propTypes = {
|
|
||||||
currentCurrency: PropTypes.string,
|
|
||||||
setCurrentCurrencyToUSD: PropTypes.func,
|
|
||||||
isLoading: PropTypes.bool,
|
|
||||||
loadingMessage: PropTypes.string,
|
|
||||||
alertMessage: PropTypes.string,
|
|
||||||
network: PropTypes.string,
|
|
||||||
provider: PropTypes.object,
|
|
||||||
frequentRpcList: PropTypes.array,
|
|
||||||
currentView: PropTypes.object,
|
|
||||||
sidebar: PropTypes.object,
|
|
||||||
alertOpen: PropTypes.bool,
|
|
||||||
hideSidebar: PropTypes.func,
|
|
||||||
isMascara: PropTypes.bool,
|
|
||||||
isOnboarding: PropTypes.bool,
|
|
||||||
isUnlocked: PropTypes.bool,
|
|
||||||
networkDropdownOpen: PropTypes.bool,
|
|
||||||
showNetworkDropdown: PropTypes.func,
|
|
||||||
hideNetworkDropdown: PropTypes.func,
|
|
||||||
history: PropTypes.object,
|
|
||||||
location: PropTypes.object,
|
|
||||||
dispatch: PropTypes.func,
|
|
||||||
toggleAccountMenu: PropTypes.func,
|
|
||||||
selectedAddress: PropTypes.string,
|
|
||||||
noActiveNotices: PropTypes.bool,
|
|
||||||
lostAccounts: PropTypes.array,
|
|
||||||
isInitialized: PropTypes.bool,
|
|
||||||
forgottenPassword: PropTypes.bool,
|
|
||||||
activeAddress: PropTypes.string,
|
|
||||||
unapprovedTxs: PropTypes.object,
|
|
||||||
seedWords: PropTypes.string,
|
|
||||||
unapprovedMsgCount: PropTypes.number,
|
|
||||||
unapprovedPersonalMsgCount: PropTypes.number,
|
|
||||||
unapprovedTypedMessagesCount: PropTypes.number,
|
|
||||||
welcomeScreenSeen: PropTypes.bool,
|
|
||||||
isPopup: PropTypes.bool,
|
|
||||||
betaUI: PropTypes.bool,
|
|
||||||
isMouseUser: PropTypes.bool,
|
|
||||||
setMouseUserState: PropTypes.func,
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
const { appState, metamask } = state
|
|
||||||
const {
|
|
||||||
networkDropdownOpen,
|
|
||||||
sidebar,
|
|
||||||
alertOpen,
|
|
||||||
alertMessage,
|
|
||||||
isLoading,
|
|
||||||
loadingMessage,
|
|
||||||
} = appState
|
|
||||||
|
|
||||||
const accounts = getMetaMaskAccounts(state)
|
|
||||||
|
|
||||||
const {
|
|
||||||
identities,
|
|
||||||
address,
|
|
||||||
keyrings,
|
|
||||||
isInitialized,
|
|
||||||
noActiveNotices,
|
|
||||||
seedWords,
|
|
||||||
unapprovedTxs,
|
|
||||||
nextUnreadNotice,
|
|
||||||
lostAccounts,
|
|
||||||
unapprovedMsgCount,
|
|
||||||
unapprovedPersonalMsgCount,
|
|
||||||
unapprovedTypedMessagesCount,
|
|
||||||
} = metamask
|
|
||||||
const selected = address || Object.keys(accounts)[0]
|
|
||||||
|
|
||||||
return {
|
|
||||||
// state from plugin
|
|
||||||
networkDropdownOpen,
|
|
||||||
sidebar,
|
|
||||||
alertOpen,
|
|
||||||
alertMessage,
|
|
||||||
isLoading,
|
|
||||||
loadingMessage,
|
|
||||||
noActiveNotices,
|
|
||||||
isInitialized,
|
|
||||||
isUnlocked: state.metamask.isUnlocked,
|
|
||||||
selectedAddress: state.metamask.selectedAddress,
|
|
||||||
currentView: state.appState.currentView,
|
|
||||||
activeAddress: state.appState.activeAddress,
|
|
||||||
transForward: state.appState.transForward,
|
|
||||||
isMascara: state.metamask.isMascara,
|
|
||||||
isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized),
|
|
||||||
isPopup: state.metamask.isPopup,
|
|
||||||
seedWords: state.metamask.seedWords,
|
|
||||||
unapprovedTxs,
|
|
||||||
unapprovedMsgs: state.metamask.unapprovedMsgs,
|
|
||||||
unapprovedMsgCount,
|
|
||||||
unapprovedPersonalMsgCount,
|
|
||||||
unapprovedTypedMessagesCount,
|
|
||||||
menuOpen: state.appState.menuOpen,
|
|
||||||
network: state.metamask.network,
|
|
||||||
provider: state.metamask.provider,
|
|
||||||
forgottenPassword: state.appState.forgottenPassword,
|
|
||||||
nextUnreadNotice,
|
|
||||||
lostAccounts,
|
|
||||||
frequentRpcList: state.metamask.frequentRpcList || [],
|
|
||||||
currentCurrency: state.metamask.currentCurrency,
|
|
||||||
isMouseUser: state.appState.isMouseUser,
|
|
||||||
betaUI: state.metamask.featureFlags.betaUI,
|
|
||||||
isRevealingSeedWords: state.metamask.isRevealingSeedWords,
|
|
||||||
Qr: state.appState.Qr,
|
|
||||||
welcomeScreenSeen: state.metamask.welcomeScreenSeen,
|
|
||||||
|
|
||||||
// state needed to get account dropdown temporarily rendering from app bar
|
|
||||||
identities,
|
|
||||||
selected,
|
|
||||||
keyrings,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch, ownProps) {
|
|
||||||
return {
|
|
||||||
dispatch,
|
|
||||||
hideSidebar: () => dispatch(actions.hideSidebar()),
|
|
||||||
showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()),
|
|
||||||
hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()),
|
|
||||||
setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('usd')),
|
|
||||||
toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()),
|
|
||||||
setMouseUserState: (isMouseUser) => dispatch(actions.setMouseUserState(isMouseUser)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
App.contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = compose(
|
|
||||||
withRouter,
|
|
||||||
connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
)(App)
|
|
|
@ -1,249 +0,0 @@
|
||||||
const inherits = require('util').inherits
|
|
||||||
const Component = require('react').Component
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const { compose } = require('recompose')
|
|
||||||
const { withRouter } = require('react-router-dom')
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const actions = require('../../actions')
|
|
||||||
const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu')
|
|
||||||
const Identicon = require('../identicon')
|
|
||||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums')
|
|
||||||
const { getEnvironmentType } = require('../../../../app/scripts/lib/util')
|
|
||||||
const Tooltip = require('../tooltip')
|
|
||||||
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
|
|
||||||
import { PRIMARY } from '../../constants/common'
|
|
||||||
import { getMetaMaskAccounts } from '../../selectors'
|
|
||||||
|
|
||||||
const {
|
|
||||||
SETTINGS_ROUTE,
|
|
||||||
INFO_ROUTE,
|
|
||||||
NEW_ACCOUNT_ROUTE,
|
|
||||||
IMPORT_ACCOUNT_ROUTE,
|
|
||||||
CONNECT_HARDWARE_ROUTE,
|
|
||||||
DEFAULT_ROUTE,
|
|
||||||
} = require('../../routes')
|
|
||||||
|
|
||||||
module.exports = compose(
|
|
||||||
withRouter,
|
|
||||||
connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
)(AccountMenu)
|
|
||||||
|
|
||||||
AccountMenu.contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
inherits(AccountMenu, Component)
|
|
||||||
function AccountMenu () { Component.call(this) }
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
return {
|
|
||||||
selectedAddress: state.metamask.selectedAddress,
|
|
||||||
isAccountMenuOpen: state.metamask.isAccountMenuOpen,
|
|
||||||
keyrings: state.metamask.keyrings,
|
|
||||||
identities: state.metamask.identities,
|
|
||||||
accounts: getMetaMaskAccounts(state),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
|
||||||
return {
|
|
||||||
toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()),
|
|
||||||
showAccountDetail: address => {
|
|
||||||
dispatch(actions.showAccountDetail(address))
|
|
||||||
dispatch(actions.hideSidebar())
|
|
||||||
dispatch(actions.toggleAccountMenu())
|
|
||||||
},
|
|
||||||
lockMetamask: () => {
|
|
||||||
dispatch(actions.lockMetamask())
|
|
||||||
dispatch(actions.hideWarning())
|
|
||||||
dispatch(actions.hideSidebar())
|
|
||||||
dispatch(actions.toggleAccountMenu())
|
|
||||||
},
|
|
||||||
showConfigPage: () => {
|
|
||||||
dispatch(actions.showConfigPage())
|
|
||||||
dispatch(actions.hideSidebar())
|
|
||||||
dispatch(actions.toggleAccountMenu())
|
|
||||||
},
|
|
||||||
showInfoPage: () => {
|
|
||||||
dispatch(actions.showInfoPage())
|
|
||||||
dispatch(actions.hideSidebar())
|
|
||||||
dispatch(actions.toggleAccountMenu())
|
|
||||||
},
|
|
||||||
showRemoveAccountConfirmationModal: (identity) => {
|
|
||||||
return dispatch(actions.showModal({ name: 'CONFIRM_REMOVE_ACCOUNT', identity }))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountMenu.prototype.render = function () {
|
|
||||||
const {
|
|
||||||
isAccountMenuOpen,
|
|
||||||
toggleAccountMenu,
|
|
||||||
lockMetamask,
|
|
||||||
history,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
return h(Menu, { className: 'account-menu', isShowing: isAccountMenuOpen }, [
|
|
||||||
h(CloseArea, { onClick: toggleAccountMenu }),
|
|
||||||
h(Item, {
|
|
||||||
className: 'account-menu__header',
|
|
||||||
}, [
|
|
||||||
this.context.t('myAccounts'),
|
|
||||||
h('button.account-menu__logout-button', {
|
|
||||||
onClick: () => {
|
|
||||||
lockMetamask()
|
|
||||||
history.push(DEFAULT_ROUTE)
|
|
||||||
},
|
|
||||||
}, this.context.t('logout')),
|
|
||||||
]),
|
|
||||||
h(Divider),
|
|
||||||
h('div.account-menu__accounts', this.renderAccounts()),
|
|
||||||
h(Divider),
|
|
||||||
h(Item, {
|
|
||||||
onClick: () => {
|
|
||||||
toggleAccountMenu()
|
|
||||||
history.push(NEW_ACCOUNT_ROUTE)
|
|
||||||
},
|
|
||||||
icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }),
|
|
||||||
text: this.context.t('createAccount'),
|
|
||||||
}),
|
|
||||||
h(Item, {
|
|
||||||
onClick: () => {
|
|
||||||
toggleAccountMenu()
|
|
||||||
history.push(IMPORT_ACCOUNT_ROUTE)
|
|
||||||
},
|
|
||||||
icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }),
|
|
||||||
text: this.context.t('importAccount'),
|
|
||||||
}),
|
|
||||||
h(Item, {
|
|
||||||
onClick: () => {
|
|
||||||
toggleAccountMenu()
|
|
||||||
if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) {
|
|
||||||
global.platform.openExtensionInBrowser(CONNECT_HARDWARE_ROUTE)
|
|
||||||
} else {
|
|
||||||
history.push(CONNECT_HARDWARE_ROUTE)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon: h('img.account-menu__item-icon', { src: 'images/connect-icon.svg' }),
|
|
||||||
text: this.context.t('connectHardwareWallet'),
|
|
||||||
}),
|
|
||||||
h(Divider),
|
|
||||||
h(Item, {
|
|
||||||
onClick: () => {
|
|
||||||
toggleAccountMenu()
|
|
||||||
history.push(INFO_ROUTE)
|
|
||||||
},
|
|
||||||
icon: h('img', { src: 'images/mm-info-icon.svg' }),
|
|
||||||
text: this.context.t('infoHelp'),
|
|
||||||
}),
|
|
||||||
h(Item, {
|
|
||||||
onClick: () => {
|
|
||||||
toggleAccountMenu()
|
|
||||||
history.push(SETTINGS_ROUTE)
|
|
||||||
},
|
|
||||||
icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }),
|
|
||||||
text: this.context.t('settings'),
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountMenu.prototype.renderAccounts = function () {
|
|
||||||
const {
|
|
||||||
identities,
|
|
||||||
accounts,
|
|
||||||
selectedAddress,
|
|
||||||
keyrings,
|
|
||||||
showAccountDetail,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
const accountOrder = keyrings.reduce((list, keyring) => list.concat(keyring.accounts), [])
|
|
||||||
return accountOrder.filter(address => !!identities[address]).map((address) => {
|
|
||||||
|
|
||||||
const identity = identities[address]
|
|
||||||
const isSelected = identity.address === selectedAddress
|
|
||||||
|
|
||||||
const balanceValue = accounts[address] ? accounts[address].balance : ''
|
|
||||||
const simpleAddress = identity.address.substring(2).toLowerCase()
|
|
||||||
|
|
||||||
const keyring = keyrings.find((kr) => {
|
|
||||||
return kr.accounts.includes(simpleAddress) ||
|
|
||||||
kr.accounts.includes(identity.address)
|
|
||||||
})
|
|
||||||
|
|
||||||
return h(
|
|
||||||
'div.account-menu__account.menu__item--clickable',
|
|
||||||
{ onClick: () => showAccountDetail(identity.address) },
|
|
||||||
[
|
|
||||||
h('div.account-menu__check-mark', [
|
|
||||||
isSelected ? h('div.account-menu__check-mark-icon') : null,
|
|
||||||
]),
|
|
||||||
|
|
||||||
h(
|
|
||||||
Identicon,
|
|
||||||
{
|
|
||||||
address: identity.address,
|
|
||||||
diameter: 24,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
h('div.account-menu__account-info', [
|
|
||||||
h('div.account-menu__name', identity.name || ''),
|
|
||||||
h(UserPreferencedCurrencyDisplay, {
|
|
||||||
className: 'account-menu__balance',
|
|
||||||
value: balanceValue,
|
|
||||||
type: PRIMARY,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
|
|
||||||
this.renderKeyringType(keyring),
|
|
||||||
this.renderRemoveAccount(keyring, identity),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountMenu.prototype.renderRemoveAccount = function (keyring, identity) {
|
|
||||||
// Any account that's not from the HD wallet Keyring can be removed
|
|
||||||
const type = keyring.type
|
|
||||||
const isRemovable = type !== 'HD Key Tree'
|
|
||||||
if (isRemovable) {
|
|
||||||
return h(Tooltip, {
|
|
||||||
title: this.context.t('removeAccount'),
|
|
||||||
position: 'bottom',
|
|
||||||
}, [
|
|
||||||
h('a.remove-account-icon', {
|
|
||||||
onClick: (e) => this.removeAccount(e, identity),
|
|
||||||
}, ''),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountMenu.prototype.removeAccount = function (e, identity) {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
const { showRemoveAccountConfirmationModal } = this.props
|
|
||||||
showRemoveAccountConfirmationModal(identity)
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountMenu.prototype.renderKeyringType = function (keyring) {
|
|
||||||
try { // Sometimes keyrings aren't loaded yet:
|
|
||||||
const type = keyring.type
|
|
||||||
let label
|
|
||||||
switch (type) {
|
|
||||||
case 'Trezor Hardware':
|
|
||||||
case 'Ledger Hardware':
|
|
||||||
label = this.context.t('hardware')
|
|
||||||
break
|
|
||||||
case 'Simple Key Pair':
|
|
||||||
label = this.context.t('imported')
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
label = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
return label !== '' ? h('.keyring-label.allcaps', label) : null
|
|
||||||
|
|
||||||
} catch (e) { return }
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import React, {PureComponent} from 'react'
|
|
||||||
|
|
||||||
export default class AddTokenButton extends PureComponent {
|
|
||||||
static contextTypes = {
|
|
||||||
t: PropTypes.func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
onClick: () => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { t } = this.context
|
|
||||||
const { onClick } = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="add-token-button">
|
|
||||||
<h1 className="add-token-button__help-header">{t('missingYourTokens')}</h1>
|
|
||||||
<p className="add-token-button__help-desc">{t('clickToAdd', [t('addToken')])}</p>
|
|
||||||
<div
|
|
||||||
className="add-token-button__button"
|
|
||||||
onClick={onClick}
|
|
||||||
>
|
|
||||||
{t('addToken')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './add-token-button.component'
|
|
|
@ -1,26 +0,0 @@
|
||||||
.add-token-button {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
color: lighten($scorpion, 25%);
|
|
||||||
width: 185px;
|
|
||||||
margin: 36px auto;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&__help-header {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__help-desc {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__button {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
margin: 1rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: $curious-blue;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
const { Component } = require('react')
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
|
|
||||||
class Alert extends Component {
|
|
||||||
|
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
visble: false,
|
|
||||||
msg: false,
|
|
||||||
className: '',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
|
||||||
if (!this.props.visible && nextProps.visible) {
|
|
||||||
this.animateIn(nextProps)
|
|
||||||
} else if (this.props.visible && !nextProps.visible) {
|
|
||||||
this.animateOut(nextProps)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
animateIn (props) {
|
|
||||||
this.setState({
|
|
||||||
msg: props.msg,
|
|
||||||
visible: true,
|
|
||||||
className: '.visible',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
animateOut (props) {
|
|
||||||
this.setState({
|
|
||||||
msg: null,
|
|
||||||
className: '.hidden',
|
|
||||||
})
|
|
||||||
|
|
||||||
setTimeout(_ => {
|
|
||||||
this.setState({visible: false})
|
|
||||||
}, 500)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
if (this.state.visible) {
|
|
||||||
return (
|
|
||||||
h(`div.global-alert${this.state.className}`, {},
|
|
||||||
h('a.msg', {}, this.state.msg)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Alert.propTypes = {
|
|
||||||
visible: PropTypes.bool.isRequired,
|
|
||||||
msg: PropTypes.string,
|
|
||||||
}
|
|
||||||
module.exports = Alert
|
|
||||||
|
|
|
@ -1,136 +0,0 @@
|
||||||
import React, { PureComponent } from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import classnames from 'classnames'
|
|
||||||
import { matchPath } from 'react-router-dom'
|
|
||||||
|
|
||||||
const {
|
|
||||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
|
||||||
ENVIRONMENT_TYPE_POPUP,
|
|
||||||
} = require('../../../../app/scripts/lib/enums')
|
|
||||||
const { DEFAULT_ROUTE, INITIALIZE_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes')
|
|
||||||
const Identicon = require('../identicon')
|
|
||||||
const NetworkIndicator = require('../network')
|
|
||||||
|
|
||||||
export default class AppHeader extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
history: PropTypes.object,
|
|
||||||
location: PropTypes.object,
|
|
||||||
network: PropTypes.string,
|
|
||||||
provider: PropTypes.object,
|
|
||||||
networkDropdownOpen: PropTypes.bool,
|
|
||||||
showNetworkDropdown: PropTypes.func,
|
|
||||||
hideNetworkDropdown: PropTypes.func,
|
|
||||||
toggleAccountMenu: PropTypes.func,
|
|
||||||
selectedAddress: PropTypes.string,
|
|
||||||
isUnlocked: PropTypes.bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
handleNetworkIndicatorClick (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
event.stopPropagation()
|
|
||||||
|
|
||||||
const { networkDropdownOpen, showNetworkDropdown, hideNetworkDropdown } = this.props
|
|
||||||
|
|
||||||
return networkDropdownOpen === false
|
|
||||||
? showNetworkDropdown()
|
|
||||||
: hideNetworkDropdown()
|
|
||||||
}
|
|
||||||
|
|
||||||
isConfirming () {
|
|
||||||
const { location } = this.props
|
|
||||||
|
|
||||||
return Boolean(matchPath(location.pathname, {
|
|
||||||
path: CONFIRM_TRANSACTION_ROUTE, exact: false,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
renderAccountMenu () {
|
|
||||||
const { isUnlocked, toggleAccountMenu, selectedAddress } = this.props
|
|
||||||
|
|
||||||
return isUnlocked && (
|
|
||||||
<div
|
|
||||||
className={classnames('account-menu__icon', {
|
|
||||||
'account-menu__icon--disabled': this.isConfirming(),
|
|
||||||
})}
|
|
||||||
onClick={() => this.isConfirming() || toggleAccountMenu()}
|
|
||||||
>
|
|
||||||
<Identicon
|
|
||||||
address={selectedAddress}
|
|
||||||
diameter={32}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
hideAppHeader () {
|
|
||||||
const { location } = this.props
|
|
||||||
|
|
||||||
const isInitializing = Boolean(matchPath(location.pathname, {
|
|
||||||
path: INITIALIZE_ROUTE, exact: false,
|
|
||||||
}))
|
|
||||||
|
|
||||||
if (isInitializing) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_POPUP && this.isConfirming()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const {
|
|
||||||
network,
|
|
||||||
provider,
|
|
||||||
history,
|
|
||||||
isUnlocked,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
if (this.hideAppHeader()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classnames('app-header', { 'app-header--back-drop': isUnlocked })}>
|
|
||||||
<div className="app-header__contents">
|
|
||||||
<div
|
|
||||||
className="app-header__logo-container"
|
|
||||||
onClick={() => history.push(DEFAULT_ROUTE)}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
className="app-header__metafox-logo app-header__metafox-logo--horizontal"
|
|
||||||
src="/images/logo/metamask-logo-horizontal-beta.svg"
|
|
||||||
height={30}
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
className="app-header__metafox-logo app-header__metafox-logo--icon"
|
|
||||||
src="/images/logo/metamask-fox.svg"
|
|
||||||
height={42}
|
|
||||||
width={42}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="app-header__account-menu-container">
|
|
||||||
<div className="app-header__network-component-wrapper">
|
|
||||||
<NetworkIndicator
|
|
||||||
network={network}
|
|
||||||
provider={provider}
|
|
||||||
onClick={event => this.handleNetworkIndicatorClick(event)}
|
|
||||||
disabled={this.isConfirming()}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{ this.renderAccountMenu() }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { connect } from 'react-redux'
|
|
||||||
import { withRouter } from 'react-router-dom'
|
|
||||||
import { compose } from 'recompose'
|
|
||||||
|
|
||||||
import AppHeader from './app-header.component'
|
|
||||||
const actions = require('../../actions')
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const { appState, metamask } = state
|
|
||||||
const { networkDropdownOpen } = appState
|
|
||||||
const {
|
|
||||||
network,
|
|
||||||
provider,
|
|
||||||
selectedAddress,
|
|
||||||
isUnlocked,
|
|
||||||
} = metamask
|
|
||||||
|
|
||||||
return {
|
|
||||||
networkDropdownOpen,
|
|
||||||
network,
|
|
||||||
provider,
|
|
||||||
selectedAddress,
|
|
||||||
isUnlocked,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
|
||||||
return {
|
|
||||||
showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()),
|
|
||||||
hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()),
|
|
||||||
toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default compose(
|
|
||||||
withRouter,
|
|
||||||
connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
)(AppHeader)
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './app-header.container'
|
|
|
@ -1,90 +0,0 @@
|
||||||
.app-header {
|
|
||||||
align-items: center;
|
|
||||||
background: $gallery;
|
|
||||||
position: relative;
|
|
||||||
z-index: $header-z-index;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
width: 100%;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
@media screen and (max-width: 575px) {
|
|
||||||
padding: 12px;
|
|
||||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, .08);
|
|
||||||
z-index: $mobile-header-z-index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 576px) {
|
|
||||||
height: 75px;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&--back-drop {
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 32px;
|
|
||||||
background: $gallery;
|
|
||||||
bottom: -32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__metafox-logo {
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&--icon {
|
|
||||||
@media screen and (min-width: $break-large) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--horizontal {
|
|
||||||
@media screen and (max-width: $break-small) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__contents {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-flow: row nowrap;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
@media screen and (max-width: 575px) {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 576px) {
|
|
||||||
width: 85vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 769px) {
|
|
||||||
width: 80vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 1281px) {
|
|
||||||
width: 62vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__logo-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__account-menu-container {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row nowrap;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__network-component-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,120 +0,0 @@
|
||||||
import React, { PureComponent } from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import UnitInput from '../unit-input'
|
|
||||||
import CurrencyDisplay from '../currency-display'
|
|
||||||
import { getValueFromWeiHex, getWeiHexFromDecimalValue } from '../../helpers/conversions.util'
|
|
||||||
import { ETH } from '../../constants/common'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Component that allows user to enter currency values as a number, and props receive a converted
|
|
||||||
* hex value in WEI. props.value, used as a default or forced value, should be a hex value, which
|
|
||||||
* gets converted into a decimal value depending on the currency (ETH or Fiat).
|
|
||||||
*/
|
|
||||||
export default class CurrencyInput extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
conversionRate: PropTypes.number,
|
|
||||||
currentCurrency: PropTypes.string,
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
onBlur: PropTypes.func,
|
|
||||||
suffix: PropTypes.string,
|
|
||||||
useFiat: PropTypes.bool,
|
|
||||||
value: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
const { value: hexValue } = props
|
|
||||||
const decimalValue = hexValue ? this.getDecimalValue(props) : 0
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
decimalValue,
|
|
||||||
hexValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
|
||||||
const { value: prevPropsHexValue } = prevProps
|
|
||||||
const { value: propsHexValue } = this.props
|
|
||||||
const { hexValue: stateHexValue } = this.state
|
|
||||||
|
|
||||||
if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) {
|
|
||||||
const decimalValue = this.getDecimalValue(this.props)
|
|
||||||
this.setState({ hexValue: propsHexValue, decimalValue })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getDecimalValue (props) {
|
|
||||||
const { value: hexValue, useFiat, currentCurrency, conversionRate } = props
|
|
||||||
const decimalValueString = useFiat
|
|
||||||
? getValueFromWeiHex({
|
|
||||||
value: hexValue, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2,
|
|
||||||
})
|
|
||||||
: getValueFromWeiHex({
|
|
||||||
value: hexValue, toCurrency: ETH, numberOfDecimals: 6,
|
|
||||||
})
|
|
||||||
|
|
||||||
return Number(decimalValueString) || 0
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange = decimalValue => {
|
|
||||||
const { useFiat, currentCurrency: fromCurrency, conversionRate, onChange } = this.props
|
|
||||||
|
|
||||||
const hexValue = useFiat
|
|
||||||
? getWeiHexFromDecimalValue({
|
|
||||||
value: decimalValue, fromCurrency, conversionRate, invertConversionRate: true,
|
|
||||||
})
|
|
||||||
: getWeiHexFromDecimalValue({
|
|
||||||
value: decimalValue, fromCurrency: ETH, fromDenomination: ETH, conversionRate,
|
|
||||||
})
|
|
||||||
|
|
||||||
this.setState({ hexValue, decimalValue })
|
|
||||||
onChange(hexValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBlur = () => {
|
|
||||||
this.props.onBlur(this.state.hexValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderConversionComponent () {
|
|
||||||
const { useFiat, currentCurrency } = this.props
|
|
||||||
const { hexValue } = this.state
|
|
||||||
let currency, numberOfDecimals
|
|
||||||
|
|
||||||
if (useFiat) {
|
|
||||||
// Display ETH
|
|
||||||
currency = ETH
|
|
||||||
numberOfDecimals = 6
|
|
||||||
} else {
|
|
||||||
// Display Fiat
|
|
||||||
currency = currentCurrency
|
|
||||||
numberOfDecimals = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CurrencyDisplay
|
|
||||||
className="currency-input__conversion-component"
|
|
||||||
currency={currency}
|
|
||||||
value={hexValue}
|
|
||||||
numberOfDecimals={numberOfDecimals}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { suffix, ...restProps } = this.props
|
|
||||||
const { decimalValue } = this.state
|
|
||||||
|
|
||||||
return (
|
|
||||||
<UnitInput
|
|
||||||
{...restProps}
|
|
||||||
suffix={suffix}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
onBlur={this.handleBlur}
|
|
||||||
value={decimalValue}
|
|
||||||
>
|
|
||||||
{ this.renderConversionComponent() }
|
|
||||||
</UnitInput>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { connect } from 'react-redux'
|
|
||||||
import CurrencyInput from './currency-input.component'
|
|
||||||
import { ETH } from '../../constants/common'
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const { metamask: { currentCurrency, conversionRate } } = state
|
|
||||||
|
|
||||||
return {
|
|
||||||
currentCurrency,
|
|
||||||
conversionRate,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
|
||||||
const { currentCurrency } = stateProps
|
|
||||||
const { useFiat } = ownProps
|
|
||||||
const suffix = useFiat ? currentCurrency.toUpperCase() : ETH
|
|
||||||
|
|
||||||
return {
|
|
||||||
...stateProps,
|
|
||||||
...dispatchProps,
|
|
||||||
...ownProps,
|
|
||||||
suffix,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, null, mergeProps)(CurrencyInput)
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './currency-input.container'
|
|
|
@ -1,7 +0,0 @@
|
||||||
.currency-input {
|
|
||||||
&__conversion-component {
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 12px;
|
|
||||||
padding-left: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,239 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import assert from 'assert'
|
|
||||||
import { shallow, mount } from 'enzyme'
|
|
||||||
import sinon from 'sinon'
|
|
||||||
import { Provider } from 'react-redux'
|
|
||||||
import configureMockStore from 'redux-mock-store'
|
|
||||||
import CurrencyInput from '../currency-input.component'
|
|
||||||
import UnitInput from '../../unit-input'
|
|
||||||
import CurrencyDisplay from '../../currency-display'
|
|
||||||
|
|
||||||
describe('CurrencyInput Component', () => {
|
|
||||||
describe('rendering', () => {
|
|
||||||
it('should render properly without a suffix', () => {
|
|
||||||
const wrapper = shallow(
|
|
||||||
<CurrencyInput />
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.ok(wrapper)
|
|
||||||
assert.equal(wrapper.find(UnitInput).length, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render properly with a suffix', () => {
|
|
||||||
const mockStore = {
|
|
||||||
metamask: {
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
conversionRate: 231.06,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const store = configureMockStore()(mockStore)
|
|
||||||
|
|
||||||
const wrapper = mount(
|
|
||||||
<Provider store={store}>
|
|
||||||
<CurrencyInput
|
|
||||||
suffix="ETH"
|
|
||||||
/>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.ok(wrapper)
|
|
||||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
|
||||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH')
|
|
||||||
assert.equal(wrapper.find(CurrencyDisplay).length, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render properly with an ETH value', () => {
|
|
||||||
const mockStore = {
|
|
||||||
metamask: {
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
conversionRate: 231.06,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const store = configureMockStore()(mockStore)
|
|
||||||
|
|
||||||
const wrapper = mount(
|
|
||||||
<Provider store={store}>
|
|
||||||
<CurrencyInput
|
|
||||||
value="de0b6b3a7640000"
|
|
||||||
suffix="ETH"
|
|
||||||
currentCurrency="usd"
|
|
||||||
conversionRate={231.06}
|
|
||||||
/>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.ok(wrapper)
|
|
||||||
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 1)
|
|
||||||
assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000')
|
|
||||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
|
||||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH')
|
|
||||||
assert.equal(wrapper.find('.unit-input__input').props().value, '1')
|
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '$231.06 USD')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render properly with a fiat value', () => {
|
|
||||||
const mockStore = {
|
|
||||||
metamask: {
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
conversionRate: 231.06,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const store = configureMockStore()(mockStore)
|
|
||||||
|
|
||||||
const wrapper = mount(
|
|
||||||
<Provider store={store}>
|
|
||||||
<CurrencyInput
|
|
||||||
value="f602f2234d0ea"
|
|
||||||
suffix="USD"
|
|
||||||
useFiat
|
|
||||||
currentCurrency="usd"
|
|
||||||
conversionRate={231.06}
|
|
||||||
/>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.ok(wrapper)
|
|
||||||
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 1)
|
|
||||||
assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea')
|
|
||||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
|
||||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'USD')
|
|
||||||
assert.equal(wrapper.find('.unit-input__input').props().value, '1')
|
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '0.004328 ETH')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('handling actions', () => {
|
|
||||||
const handleChangeSpy = sinon.spy()
|
|
||||||
const handleBlurSpy = sinon.spy()
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
handleChangeSpy.resetHistory()
|
|
||||||
handleBlurSpy.resetHistory()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should call onChange and onBlur on input changes with the hex value for ETH', () => {
|
|
||||||
const mockStore = {
|
|
||||||
metamask: {
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
conversionRate: 231.06,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const store = configureMockStore()(mockStore)
|
|
||||||
const wrapper = mount(
|
|
||||||
<Provider store={store}>
|
|
||||||
<CurrencyInput
|
|
||||||
onChange={handleChangeSpy}
|
|
||||||
onBlur={handleBlurSpy}
|
|
||||||
suffix="ETH"
|
|
||||||
currentCurrency="usd"
|
|
||||||
conversionRate={231.06}
|
|
||||||
/>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.ok(wrapper)
|
|
||||||
assert.equal(handleChangeSpy.callCount, 0)
|
|
||||||
assert.equal(handleBlurSpy.callCount, 0)
|
|
||||||
|
|
||||||
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 0)
|
|
||||||
assert.equal(currencyInputInstance.state.hexValue, undefined)
|
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '$0.00 USD')
|
|
||||||
const input = wrapper.find('input')
|
|
||||||
assert.equal(input.props().value, 0)
|
|
||||||
|
|
||||||
input.simulate('change', { target: { value: 1 } })
|
|
||||||
assert.equal(handleChangeSpy.callCount, 1)
|
|
||||||
assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000'))
|
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '$231.06 USD')
|
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 1)
|
|
||||||
assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000')
|
|
||||||
|
|
||||||
assert.equal(handleBlurSpy.callCount, 0)
|
|
||||||
input.simulate('blur')
|
|
||||||
assert.equal(handleBlurSpy.callCount, 1)
|
|
||||||
assert.ok(handleBlurSpy.calledWith('de0b6b3a7640000'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should call onChange and onBlur on input changes with the hex value for fiat', () => {
|
|
||||||
const mockStore = {
|
|
||||||
metamask: {
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
conversionRate: 231.06,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const store = configureMockStore()(mockStore)
|
|
||||||
const wrapper = mount(
|
|
||||||
<Provider store={store}>
|
|
||||||
<CurrencyInput
|
|
||||||
onChange={handleChangeSpy}
|
|
||||||
onBlur={handleBlurSpy}
|
|
||||||
suffix="USD"
|
|
||||||
currentCurrency="usd"
|
|
||||||
conversionRate={231.06}
|
|
||||||
useFiat
|
|
||||||
/>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.ok(wrapper)
|
|
||||||
assert.equal(handleChangeSpy.callCount, 0)
|
|
||||||
assert.equal(handleBlurSpy.callCount, 0)
|
|
||||||
|
|
||||||
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 0)
|
|
||||||
assert.equal(currencyInputInstance.state.hexValue, undefined)
|
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '0 ETH')
|
|
||||||
const input = wrapper.find('input')
|
|
||||||
assert.equal(input.props().value, 0)
|
|
||||||
|
|
||||||
input.simulate('change', { target: { value: 1 } })
|
|
||||||
assert.equal(handleChangeSpy.callCount, 1)
|
|
||||||
assert.ok(handleChangeSpy.calledWith('f602f2234d0ea'))
|
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '0.004328 ETH')
|
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 1)
|
|
||||||
assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea')
|
|
||||||
|
|
||||||
assert.equal(handleBlurSpy.callCount, 0)
|
|
||||||
input.simulate('blur')
|
|
||||||
assert.equal(handleBlurSpy.callCount, 1)
|
|
||||||
assert.ok(handleBlurSpy.calledWith('f602f2234d0ea'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should change the state and pass in a new decimalValue when props.value changes', () => {
|
|
||||||
const mockStore = {
|
|
||||||
metamask: {
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
conversionRate: 231.06,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const store = configureMockStore()(mockStore)
|
|
||||||
const wrapper = shallow(
|
|
||||||
<Provider store={store}>
|
|
||||||
<CurrencyInput
|
|
||||||
onChange={handleChangeSpy}
|
|
||||||
onBlur={handleBlurSpy}
|
|
||||||
suffix="USD"
|
|
||||||
currentCurrency="usd"
|
|
||||||
conversionRate={231.06}
|
|
||||||
useFiat
|
|
||||||
/>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.ok(wrapper)
|
|
||||||
const currencyInputInstance = wrapper.find(CurrencyInput).dive()
|
|
||||||
assert.equal(currencyInputInstance.state('decimalValue'), 0)
|
|
||||||
assert.equal(currencyInputInstance.state('hexValue'), undefined)
|
|
||||||
assert.equal(currencyInputInstance.find(UnitInput).props().value, 0)
|
|
||||||
|
|
||||||
currencyInputInstance.setProps({ value: '1ec05e43e72400' })
|
|
||||||
currencyInputInstance.update()
|
|
||||||
assert.equal(currencyInputInstance.state('decimalValue'), 2)
|
|
||||||
assert.equal(currencyInputInstance.state('hexValue'), '1ec05e43e72400')
|
|
||||||
assert.equal(currencyInputInstance.find(UnitInput).props().value, 2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,55 +0,0 @@
|
||||||
import assert from 'assert'
|
|
||||||
import proxyquire from 'proxyquire'
|
|
||||||
|
|
||||||
let mapStateToProps, mergeProps
|
|
||||||
|
|
||||||
proxyquire('../currency-input.container.js', {
|
|
||||||
'react-redux': {
|
|
||||||
connect: (ms, md, mp) => {
|
|
||||||
mapStateToProps = ms
|
|
||||||
mergeProps = mp
|
|
||||||
return () => ({})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('CurrencyInput container', () => {
|
|
||||||
describe('mapStateToProps()', () => {
|
|
||||||
it('should return the correct props', () => {
|
|
||||||
const mockState = {
|
|
||||||
metamask: {
|
|
||||||
conversionRate: 280.45,
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.deepEqual(mapStateToProps(mockState), {
|
|
||||||
conversionRate: 280.45,
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('mergeProps()', () => {
|
|
||||||
it('should return the correct props', () => {
|
|
||||||
const mockStateProps = {
|
|
||||||
conversionRate: 280.45,
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
}
|
|
||||||
const mockDispatchProps = {}
|
|
||||||
|
|
||||||
assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, { useFiat: true }), {
|
|
||||||
conversionRate: 280.45,
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
useFiat: true,
|
|
||||||
suffix: 'USD',
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, {}), {
|
|
||||||
conversionRate: 280.45,
|
|
||||||
currentCurrency: 'usd',
|
|
||||||
suffix: 'ETH',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,59 +0,0 @@
|
||||||
@import './app-header/index';
|
|
||||||
|
|
||||||
@import './add-token-button/index';
|
|
||||||
|
|
||||||
@import './button-group/index';
|
|
||||||
|
|
||||||
@import './card/index';
|
|
||||||
|
|
||||||
@import './confirm-page-container/index';
|
|
||||||
|
|
||||||
@import './currency-input/index';
|
|
||||||
|
|
||||||
@import './currency-display/index';
|
|
||||||
|
|
||||||
@import './error-message/index';
|
|
||||||
|
|
||||||
@import './export-text-container/index';
|
|
||||||
|
|
||||||
@import './info-box/index';
|
|
||||||
|
|
||||||
@import './menu-bar/index';
|
|
||||||
|
|
||||||
@import './modal/index';
|
|
||||||
|
|
||||||
@import './modals/index';
|
|
||||||
|
|
||||||
@import './network-display/index';
|
|
||||||
|
|
||||||
@import './page-container/index';
|
|
||||||
|
|
||||||
@import './pages/index';
|
|
||||||
|
|
||||||
@import './selected-account/index';
|
|
||||||
|
|
||||||
@import './sender-to-recipient/index';
|
|
||||||
|
|
||||||
@import './tabs/index';
|
|
||||||
|
|
||||||
@import './transaction-activity-log/index';
|
|
||||||
|
|
||||||
@import './transaction-breakdown/index';
|
|
||||||
|
|
||||||
@import './transaction-view/index';
|
|
||||||
|
|
||||||
@import './transaction-view-balance/index';
|
|
||||||
|
|
||||||
@import './transaction-list/index';
|
|
||||||
|
|
||||||
@import './transaction-list-item/index';
|
|
||||||
|
|
||||||
@import './transaction-list-item-details/index';
|
|
||||||
|
|
||||||
@import './transaction-status/index';
|
|
||||||
|
|
||||||
@import './app-header/index';
|
|
||||||
|
|
||||||
@import './sidebars/index';
|
|
||||||
|
|
||||||
@import './unit-input/index';
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './menu-bar.container'
|
|
|
@ -1,23 +0,0 @@
|
||||||
.menu-bar {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid #e5e5e5;
|
|
||||||
|
|
||||||
&__sidebar-button {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__open-in-browser {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
import React, { PureComponent } from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Tooltip from '../tooltip'
|
|
||||||
import SelectedAccount from '../selected-account'
|
|
||||||
import AccountDetailsDropdown from '../dropdowns/account-details-dropdown.js'
|
|
||||||
|
|
||||||
export default class MenuBar extends PureComponent {
|
|
||||||
static contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
hideSidebar: PropTypes.func,
|
|
||||||
isMascara: PropTypes.bool,
|
|
||||||
sidebarOpen: PropTypes.bool,
|
|
||||||
showSidebar: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
state = { accountDetailsMenuOpen: false }
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { t } = this.context
|
|
||||||
const { isMascara, sidebarOpen, hideSidebar, showSidebar } = this.props
|
|
||||||
const { accountDetailsMenuOpen } = this.state
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="menu-bar">
|
|
||||||
<Tooltip
|
|
||||||
title={t('menu')}
|
|
||||||
position="bottom"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="fa fa-bars menu-bar__sidebar-button"
|
|
||||||
onClick={() => sidebarOpen ? hideSidebar() : showSidebar()}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
<SelectedAccount />
|
|
||||||
{
|
|
||||||
!isMascara && (
|
|
||||||
<Tooltip
|
|
||||||
title={t('accountOptions')}
|
|
||||||
position="bottom"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="fa fa-ellipsis-h fa-lg menu-bar__open-in-browser"
|
|
||||||
onClick={() => this.setState({ accountDetailsMenuOpen: true })}
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
accountDetailsMenuOpen && (
|
|
||||||
<AccountDetailsDropdown
|
|
||||||
className="menu-bar__account-details-dropdown"
|
|
||||||
onClose={() => this.setState({ accountDetailsMenuOpen: false })}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import { connect } from 'react-redux'
|
|
||||||
import MenuBar from './menu-bar.component'
|
|
||||||
import { showSidebar, hideSidebar } from '../../actions'
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const { appState: { sidebar: { isOpen }, isMascara } } = state
|
|
||||||
|
|
||||||
return {
|
|
||||||
sidebarOpen: isOpen,
|
|
||||||
isMascara,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
|
||||||
return {
|
|
||||||
showSidebar: () => {
|
|
||||||
dispatch(showSidebar({
|
|
||||||
transitionName: 'sidebar-right',
|
|
||||||
type: 'wallet-view',
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
hideSidebar: () => dispatch(hideSidebar()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(MenuBar)
|
|
|
@ -1,154 +0,0 @@
|
||||||
const Component = require('react').Component
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const classnames = require('classnames')
|
|
||||||
const inherits = require('util').inherits
|
|
||||||
const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon')
|
|
||||||
|
|
||||||
Network.contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = connect()(Network)
|
|
||||||
|
|
||||||
|
|
||||||
inherits(Network, Component)
|
|
||||||
|
|
||||||
function Network () {
|
|
||||||
Component.call(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
Network.prototype.render = function () {
|
|
||||||
const props = this.props
|
|
||||||
const context = this.context
|
|
||||||
const networkNumber = props.network
|
|
||||||
let providerName
|
|
||||||
try {
|
|
||||||
providerName = props.provider.type
|
|
||||||
} catch (e) {
|
|
||||||
providerName = null
|
|
||||||
}
|
|
||||||
let iconName, hoverText
|
|
||||||
|
|
||||||
if (networkNumber === 'loading') {
|
|
||||||
return h('span.pointer.network-indicator', {
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
},
|
|
||||||
onClick: (event) => this.props.onClick(event),
|
|
||||||
}, [
|
|
||||||
h('img', {
|
|
||||||
title: context.t('attemptingConnect'),
|
|
||||||
style: {
|
|
||||||
width: '27px',
|
|
||||||
},
|
|
||||||
src: 'images/loading.svg',
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
} else if (providerName === 'mainnet') {
|
|
||||||
hoverText = context.t('mainnet')
|
|
||||||
iconName = 'ethereum-network'
|
|
||||||
} else if (providerName === 'ropsten') {
|
|
||||||
hoverText = context.t('ropsten')
|
|
||||||
iconName = 'ropsten-test-network'
|
|
||||||
} else if (parseInt(networkNumber) === 3) {
|
|
||||||
hoverText = context.t('ropsten')
|
|
||||||
iconName = 'ropsten-test-network'
|
|
||||||
} else if (providerName === 'kovan') {
|
|
||||||
hoverText = context.t('kovan')
|
|
||||||
iconName = 'kovan-test-network'
|
|
||||||
} else if (providerName === 'rinkeby') {
|
|
||||||
hoverText = context.t('rinkeby')
|
|
||||||
iconName = 'rinkeby-test-network'
|
|
||||||
} else if (providerName === 'poa') {
|
|
||||||
hoverText = context.t('poa')
|
|
||||||
iconName = 'poa-network'
|
|
||||||
} else {
|
|
||||||
hoverText = context.t('unknownNetwork')
|
|
||||||
iconName = 'unknown-private-network'
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
h('div.network-component.pointer', {
|
|
||||||
className: classnames({
|
|
||||||
'network-component--disabled': this.props.disabled,
|
|
||||||
'ethereum-network': providerName === 'mainnet',
|
|
||||||
'ropsten-test-network': providerName === 'ropsten' || parseInt(networkNumber) === 3,
|
|
||||||
'kovan-test-network': providerName === 'kovan',
|
|
||||||
'rinkeby-test-network': providerName === 'rinkeby',
|
|
||||||
'poa-network': providerName === 'poa',
|
|
||||||
}),
|
|
||||||
title: hoverText,
|
|
||||||
onClick: (event) => {
|
|
||||||
if (!this.props.disabled) {
|
|
||||||
this.props.onClick(event)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
(function () {
|
|
||||||
switch (iconName) {
|
|
||||||
case 'ethereum-network':
|
|
||||||
return h('.network-indicator', [
|
|
||||||
h(NetworkDropdownIcon, {
|
|
||||||
backgroundColor: '#038789', // $blue-lagoon
|
|
||||||
nonSelectBackgroundColor: '#15afb2',
|
|
||||||
}),
|
|
||||||
h('.network-name', context.t('mainnet')),
|
|
||||||
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
|
|
||||||
])
|
|
||||||
case 'ropsten-test-network':
|
|
||||||
return h('.network-indicator', [
|
|
||||||
h(NetworkDropdownIcon, {
|
|
||||||
backgroundColor: '#e91550', // $crimson
|
|
||||||
nonSelectBackgroundColor: '#ec2c50',
|
|
||||||
}),
|
|
||||||
h('.network-name', context.t('ropsten')),
|
|
||||||
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
|
|
||||||
])
|
|
||||||
case 'kovan-test-network':
|
|
||||||
return h('.network-indicator', [
|
|
||||||
h(NetworkDropdownIcon, {
|
|
||||||
backgroundColor: '#690496', // $purple
|
|
||||||
nonSelectBackgroundColor: '#b039f3',
|
|
||||||
}),
|
|
||||||
h('.network-name', context.t('kovan')),
|
|
||||||
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
|
|
||||||
])
|
|
||||||
case 'rinkeby-test-network':
|
|
||||||
return h('.network-indicator', [
|
|
||||||
h(NetworkDropdownIcon, {
|
|
||||||
backgroundColor: '#ebb33f', // $tulip-tree
|
|
||||||
nonSelectBackgroundColor: '#ecb23e',
|
|
||||||
}),
|
|
||||||
h('.network-name', context.t('rinkeby')),
|
|
||||||
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
|
|
||||||
])
|
|
||||||
case 'poa-network':
|
|
||||||
return h('.network-indicator', [
|
|
||||||
h(NetworkDropdownIcon, {
|
|
||||||
backgroundColor: '#5c34a2', // $tulip-tree
|
|
||||||
nonSelectBackgroundColor: '#5c34a2',
|
|
||||||
}),
|
|
||||||
h('.network-name', context.t('poa')),
|
|
||||||
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
|
|
||||||
])
|
|
||||||
default:
|
|
||||||
return h('.network-indicator', [
|
|
||||||
h('i.fa.fa-question-circle.fa-lg', {
|
|
||||||
style: {
|
|
||||||
margin: '10px',
|
|
||||||
color: 'rgb(125, 128, 130)',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
h('.network-name', context.t('privateNetwork')),
|
|
||||||
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './settings.component'
|
|
|
@ -1,80 +0,0 @@
|
||||||
@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%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './info-tab.component'
|
|
|
@ -1,56 +0,0 @@
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,136 +0,0 @@
|
||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './settings-tab.container'
|
|
|
@ -1,69 +0,0 @@
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__radio-buttons {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__radio-button {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__radio-label {
|
|
||||||
padding-left: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,413 +0,0 @@
|
||||||
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,
|
|
||||||
useETHAsPrimaryCurrency: PropTypes.bool,
|
|
||||||
setUseETHAsPrimaryCurrencyPreference: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderUseEthAsPrimaryCurrency () {
|
|
||||||
const { t } = this.context
|
|
||||||
const { useETHAsPrimaryCurrency, setUseETHAsPrimaryCurrencyPreference } = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="settings-page__content-row">
|
|
||||||
<div className="settings-page__content-item">
|
|
||||||
<span>{ t('primaryCurrencySetting') }</span>
|
|
||||||
<div className="settings-page__content-description">
|
|
||||||
{ t('primaryCurrencySettingDescription') }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="settings-page__content-item">
|
|
||||||
<div className="settings-page__content-item-col">
|
|
||||||
<div className="settings-tab__radio-buttons">
|
|
||||||
<div className="settings-tab__radio-button">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id="eth-primary-currency"
|
|
||||||
onChange={() => setUseETHAsPrimaryCurrencyPreference(true)}
|
|
||||||
checked={Boolean(useETHAsPrimaryCurrency)}
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
htmlFor="eth-primary-currency"
|
|
||||||
className="settings-tab__radio-label"
|
|
||||||
>
|
|
||||||
{ t('eth') }
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className="settings-tab__radio-button">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id="fiat-primary-currency"
|
|
||||||
onChange={() => setUseETHAsPrimaryCurrencyPreference(false)}
|
|
||||||
checked={!useETHAsPrimaryCurrency}
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
htmlFor="fiat-primary-currency"
|
|
||||||
className="settings-tab__radio-label"
|
|
||||||
>
|
|
||||||
{ t('fiat') }
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</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.renderUseEthAsPrimaryCurrency() }
|
|
||||||
{ this.renderCurrentLocale() }
|
|
||||||
{ this.renderNewRpcUrl() }
|
|
||||||
{ this.renderStateLogs() }
|
|
||||||
{ this.renderSeedWords() }
|
|
||||||
{ !isMascara && this.renderOldUI() }
|
|
||||||
{ this.renderResetAccount() }
|
|
||||||
{ this.renderBlockieOptIn() }
|
|
||||||
{ this.renderHexDataOptIn() }
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
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,
|
|
||||||
setUseETHAsPrimaryCurrencyPreference,
|
|
||||||
} from '../../../../actions'
|
|
||||||
import { preferencesSelector } from '../../../../selectors'
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const { appState: { warning }, metamask } = state
|
|
||||||
const {
|
|
||||||
currentCurrency,
|
|
||||||
conversionDate,
|
|
||||||
useBlockie,
|
|
||||||
featureFlags: { sendHexData } = {},
|
|
||||||
provider = {},
|
|
||||||
isMascara,
|
|
||||||
currentLocale,
|
|
||||||
} = metamask
|
|
||||||
const { useETHAsPrimaryCurrency } = preferencesSelector(state)
|
|
||||||
|
|
||||||
return {
|
|
||||||
warning,
|
|
||||||
isMascara,
|
|
||||||
currentLocale,
|
|
||||||
currentCurrency,
|
|
||||||
conversionDate,
|
|
||||||
useBlockie,
|
|
||||||
sendHexData,
|
|
||||||
provider,
|
|
||||||
useETHAsPrimaryCurrency,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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' })),
|
|
||||||
setUseETHAsPrimaryCurrencyPreference: value => {
|
|
||||||
return dispatch(setUseETHAsPrimaryCurrencyPreference(value))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default compose(
|
|
||||||
withRouter,
|
|
||||||
connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
)(SettingsTab)
|
|
|
@ -1,54 +0,0 @@
|
||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,307 +0,0 @@
|
||||||
const Component = require('react').Component
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const inherits = require('util').inherits
|
|
||||||
const Identicon = require('./identicon')
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const ethUtil = require('ethereumjs-util')
|
|
||||||
const classnames = require('classnames')
|
|
||||||
const { compose } = require('recompose')
|
|
||||||
const { withRouter } = require('react-router-dom')
|
|
||||||
const { ObjectInspector } = require('react-inspector')
|
|
||||||
|
|
||||||
const AccountDropdownMini = require('./dropdowns/account-dropdown-mini')
|
|
||||||
|
|
||||||
const actions = require('../actions')
|
|
||||||
const { conversionUtil } = require('../conversion-util')
|
|
||||||
|
|
||||||
const {
|
|
||||||
getSelectedAccount,
|
|
||||||
getCurrentAccountWithSendEtherInfo,
|
|
||||||
getSelectedAddress,
|
|
||||||
accountsWithSendEtherInfoSelector,
|
|
||||||
conversionRateSelector,
|
|
||||||
} = require('../selectors.js')
|
|
||||||
|
|
||||||
import { clearConfirmTransaction } from '../ducks/confirm-transaction.duck'
|
|
||||||
import Button from './button'
|
|
||||||
|
|
||||||
const { DEFAULT_ROUTE } = require('../routes')
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
return {
|
|
||||||
balance: getSelectedAccount(state).balance,
|
|
||||||
selectedAccount: getCurrentAccountWithSendEtherInfo(state),
|
|
||||||
selectedAddress: getSelectedAddress(state),
|
|
||||||
requester: null,
|
|
||||||
requesterAddress: null,
|
|
||||||
accounts: accountsWithSendEtherInfoSelector(state),
|
|
||||||
conversionRate: conversionRateSelector(state),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
|
||||||
return {
|
|
||||||
goHome: () => dispatch(actions.goHome()),
|
|
||||||
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = compose(
|
|
||||||
withRouter,
|
|
||||||
connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
)(SignatureRequest)
|
|
||||||
|
|
||||||
|
|
||||||
inherits(SignatureRequest, Component)
|
|
||||||
function SignatureRequest (props) {
|
|
||||||
Component.call(this)
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
selectedAccount: props.selectedAccount,
|
|
||||||
accountDropdownOpen: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.renderHeader = function () {
|
|
||||||
return h('div.request-signature__header', [
|
|
||||||
|
|
||||||
h('div.request-signature__header-background'),
|
|
||||||
|
|
||||||
h('div.request-signature__header__text', this.context.t('sigRequest')),
|
|
||||||
|
|
||||||
h('div.request-signature__header__tip-container', [
|
|
||||||
h('div.request-signature__header__tip'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.renderAccountDropdown = function () {
|
|
||||||
const {
|
|
||||||
selectedAccount,
|
|
||||||
accountDropdownOpen,
|
|
||||||
} = this.state
|
|
||||||
|
|
||||||
const {
|
|
||||||
accounts,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
return h('div.request-signature__account', [
|
|
||||||
|
|
||||||
h('div.request-signature__account-text', [this.context.t('account') + ':']),
|
|
||||||
|
|
||||||
h(AccountDropdownMini, {
|
|
||||||
selectedAccount,
|
|
||||||
accounts,
|
|
||||||
onSelect: selectedAccount => this.setState({ selectedAccount }),
|
|
||||||
dropdownOpen: accountDropdownOpen,
|
|
||||||
openDropdown: () => this.setState({ accountDropdownOpen: true }),
|
|
||||||
closeDropdown: () => this.setState({ accountDropdownOpen: false }),
|
|
||||||
}),
|
|
||||||
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.renderBalance = function () {
|
|
||||||
const { balance, conversionRate } = this.props
|
|
||||||
|
|
||||||
const balanceInEther = conversionUtil(balance, {
|
|
||||||
fromNumericBase: 'hex',
|
|
||||||
toNumericBase: 'dec',
|
|
||||||
fromDenomination: 'WEI',
|
|
||||||
numberOfDecimals: 6,
|
|
||||||
conversionRate,
|
|
||||||
})
|
|
||||||
|
|
||||||
return h('div.request-signature__balance', [
|
|
||||||
|
|
||||||
h('div.request-signature__balance-text', `${this.context.t('balance')}:`),
|
|
||||||
|
|
||||||
h('div.request-signature__balance-value', `${balanceInEther} ETH`),
|
|
||||||
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.renderAccountInfo = function () {
|
|
||||||
return h('div.request-signature__account-info', [
|
|
||||||
|
|
||||||
this.renderAccountDropdown(),
|
|
||||||
|
|
||||||
this.renderRequestIcon(),
|
|
||||||
|
|
||||||
this.renderBalance(),
|
|
||||||
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.renderRequestIcon = function () {
|
|
||||||
const { requesterAddress } = this.props
|
|
||||||
|
|
||||||
return h('div.request-signature__request-icon', [
|
|
||||||
h(Identicon, {
|
|
||||||
diameter: 40,
|
|
||||||
address: requesterAddress,
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.renderRequestInfo = function () {
|
|
||||||
return h('div.request-signature__request-info', [
|
|
||||||
|
|
||||||
h('div.request-signature__headline', [
|
|
||||||
this.context.t('yourSigRequested'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.msgHexToText = function (hex) {
|
|
||||||
try {
|
|
||||||
const stripped = ethUtil.stripHexPrefix(hex)
|
|
||||||
const buff = Buffer.from(stripped, 'hex')
|
|
||||||
return buff.toString('utf8')
|
|
||||||
} catch (e) {
|
|
||||||
return hex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
SignatureRequest.prototype.renderTypedDataV3 = function (data) {
|
|
||||||
const { domain, message } = JSON.parse(data)
|
|
||||||
return [
|
|
||||||
h('div.request-signature__typed-container', [
|
|
||||||
domain ? h('div', [
|
|
||||||
h('h1', 'Domain'),
|
|
||||||
h(ObjectInspector, { data: domain, expandLevel: 1, name: 'domain' }),
|
|
||||||
]) : '',
|
|
||||||
message ? h('div', [
|
|
||||||
h('h1', 'Message'),
|
|
||||||
h(ObjectInspector, { data: message, expandLevel: 1, name: 'message' }),
|
|
||||||
]) : '',
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.renderBody = function () {
|
|
||||||
let rows
|
|
||||||
let notice = this.context.t('youSign') + ':'
|
|
||||||
|
|
||||||
const { txData } = this.props
|
|
||||||
const { type, msgParams: { data, version } } = txData
|
|
||||||
|
|
||||||
if (type === 'personal_sign') {
|
|
||||||
rows = [{ name: this.context.t('message'), value: this.msgHexToText(data) }]
|
|
||||||
} else if (type === 'eth_signTypedData') {
|
|
||||||
rows = data
|
|
||||||
} else if (type === 'eth_sign') {
|
|
||||||
rows = [{ name: this.context.t('message'), value: data }]
|
|
||||||
notice = [this.context.t('signNotice'),
|
|
||||||
h('span.request-signature__help-link', {
|
|
||||||
onClick: () => {
|
|
||||||
global.platform.openWindow({
|
|
||||||
url: 'https://metamask.zendesk.com/hc/en-us/articles/360015488751',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}, this.context.t('learnMore'))]
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div.request-signature__body', {}, [
|
|
||||||
|
|
||||||
this.renderAccountInfo(),
|
|
||||||
|
|
||||||
this.renderRequestInfo(),
|
|
||||||
|
|
||||||
h('div.request-signature__notice', {
|
|
||||||
className: classnames({
|
|
||||||
'request-signature__notice': type === 'personal_sign' || type === 'eth_signTypedData',
|
|
||||||
'request-signature__warning': type === 'eth_sign',
|
|
||||||
}),
|
|
||||||
}, [notice]),
|
|
||||||
|
|
||||||
h('div.request-signature__rows', type === 'eth_signTypedData' && version === 'V3' ?
|
|
||||||
this.renderTypedDataV3(data) :
|
|
||||||
rows.map(({ name, value }) => {
|
|
||||||
if (typeof value === 'boolean') {
|
|
||||||
value = value.toString()
|
|
||||||
}
|
|
||||||
return h('div.request-signature__row', [
|
|
||||||
h('div.request-signature__row-title', [`${name}:`]),
|
|
||||||
h('div.request-signature__row-value', value),
|
|
||||||
])
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.renderFooter = function () {
|
|
||||||
const {
|
|
||||||
signPersonalMessage,
|
|
||||||
signTypedMessage,
|
|
||||||
cancelPersonalMessage,
|
|
||||||
cancelTypedMessage,
|
|
||||||
signMessage,
|
|
||||||
cancelMessage,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
const { txData } = this.props
|
|
||||||
const { type } = txData
|
|
||||||
|
|
||||||
let cancel
|
|
||||||
let sign
|
|
||||||
if (type === 'personal_sign') {
|
|
||||||
cancel = cancelPersonalMessage
|
|
||||||
sign = signPersonalMessage
|
|
||||||
} else if (type === 'eth_signTypedData') {
|
|
||||||
cancel = cancelTypedMessage
|
|
||||||
sign = signTypedMessage
|
|
||||||
} else if (type === 'eth_sign') {
|
|
||||||
cancel = cancelMessage
|
|
||||||
sign = signMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div.request-signature__footer', [
|
|
||||||
h(Button, {
|
|
||||||
type: 'default',
|
|
||||||
large: true,
|
|
||||||
className: 'request-signature__footer__cancel-button',
|
|
||||||
onClick: event => {
|
|
||||||
cancel(event).then(() => {
|
|
||||||
this.props.clearConfirmTransaction()
|
|
||||||
this.props.history.push(DEFAULT_ROUTE)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}, this.context.t('cancel')),
|
|
||||||
h(Button, {
|
|
||||||
type: 'primary',
|
|
||||||
large: true,
|
|
||||||
onClick: event => {
|
|
||||||
sign(event).then(() => {
|
|
||||||
this.props.clearConfirmTransaction()
|
|
||||||
this.props.history.push(DEFAULT_ROUTE)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}, this.context.t('sign')),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SignatureRequest.prototype.render = function () {
|
|
||||||
return (
|
|
||||||
|
|
||||||
h('div.request-signature__container', [
|
|
||||||
|
|
||||||
this.renderHeader(),
|
|
||||||
|
|
||||||
this.renderBody(),
|
|
||||||
|
|
||||||
this.renderFooter(),
|
|
||||||
|
|
||||||
])
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,230 +0,0 @@
|
||||||
const Component = require('react').Component
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const { withRouter } = require('react-router-dom')
|
|
||||||
const { compose } = require('recompose')
|
|
||||||
const inherits = require('util').inherits
|
|
||||||
const classnames = require('classnames')
|
|
||||||
const { checksumAddress } = require('../util')
|
|
||||||
const Identicon = require('./identicon')
|
|
||||||
// const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns
|
|
||||||
const Tooltip = require('./tooltip-v2.js').default
|
|
||||||
const copyToClipboard = require('copy-to-clipboard')
|
|
||||||
const actions = require('../actions')
|
|
||||||
const BalanceComponent = require('./balance-component')
|
|
||||||
const TokenList = require('./token-list')
|
|
||||||
const selectors = require('../selectors')
|
|
||||||
const { ADD_TOKEN_ROUTE } = require('../routes')
|
|
||||||
|
|
||||||
import AddTokenButton from './add-token-button'
|
|
||||||
|
|
||||||
module.exports = compose(
|
|
||||||
withRouter,
|
|
||||||
connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
)(WalletView)
|
|
||||||
|
|
||||||
WalletView.contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
WalletView.defaultProps = {
|
|
||||||
responsiveDisplayClassname: '',
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
|
|
||||||
return {
|
|
||||||
network: state.metamask.network,
|
|
||||||
sidebarOpen: state.appState.sidebar.isOpen,
|
|
||||||
identities: state.metamask.identities,
|
|
||||||
accounts: selectors.getMetaMaskAccounts(state),
|
|
||||||
tokens: state.metamask.tokens,
|
|
||||||
keyrings: state.metamask.keyrings,
|
|
||||||
selectedAddress: selectors.getSelectedAddress(state),
|
|
||||||
selectedAccount: selectors.getSelectedAccount(state),
|
|
||||||
selectedTokenAddress: state.metamask.selectedTokenAddress,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
|
||||||
return {
|
|
||||||
showSendPage: () => dispatch(actions.showSendPage()),
|
|
||||||
hideSidebar: () => dispatch(actions.hideSidebar()),
|
|
||||||
unsetSelectedToken: () => dispatch(actions.setSelectedToken()),
|
|
||||||
showAccountDetailModal: () => {
|
|
||||||
dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' }))
|
|
||||||
},
|
|
||||||
showAddTokenPage: () => dispatch(actions.showAddTokenPage()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inherits(WalletView, Component)
|
|
||||||
function WalletView () {
|
|
||||||
Component.call(this)
|
|
||||||
this.state = {
|
|
||||||
hasCopied: false,
|
|
||||||
copyToClipboardPressed: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WalletView.prototype.renderWalletBalance = function () {
|
|
||||||
const {
|
|
||||||
selectedTokenAddress,
|
|
||||||
selectedAccount,
|
|
||||||
unsetSelectedToken,
|
|
||||||
hideSidebar,
|
|
||||||
sidebarOpen,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
const selectedClass = selectedTokenAddress
|
|
||||||
? ''
|
|
||||||
: 'wallet-balance-wrapper--active'
|
|
||||||
const className = `flex-column wallet-balance-wrapper ${selectedClass}`
|
|
||||||
|
|
||||||
return h('div', { className }, [
|
|
||||||
h('div.wallet-balance',
|
|
||||||
{
|
|
||||||
onClick: () => {
|
|
||||||
unsetSelectedToken()
|
|
||||||
selectedTokenAddress && sidebarOpen && hideSidebar()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[
|
|
||||||
h(BalanceComponent, {
|
|
||||||
balanceValue: selectedAccount ? selectedAccount.balance : '',
|
|
||||||
style: {},
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
WalletView.prototype.renderAddToken = function () {
|
|
||||||
const {
|
|
||||||
sidebarOpen,
|
|
||||||
hideSidebar,
|
|
||||||
history,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
return h(AddTokenButton, {
|
|
||||||
onClick () {
|
|
||||||
history.push(ADD_TOKEN_ROUTE)
|
|
||||||
if (sidebarOpen) {
|
|
||||||
hideSidebar()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
WalletView.prototype.render = function () {
|
|
||||||
const {
|
|
||||||
responsiveDisplayClassname,
|
|
||||||
selectedAddress,
|
|
||||||
keyrings,
|
|
||||||
showAccountDetailModal,
|
|
||||||
hideSidebar,
|
|
||||||
identities,
|
|
||||||
} = this.props
|
|
||||||
// temporary logs + fake extra wallets
|
|
||||||
|
|
||||||
const checksummedAddress = checksumAddress(selectedAddress)
|
|
||||||
|
|
||||||
if (!selectedAddress) {
|
|
||||||
throw new Error('selectedAddress should not be ' + String(selectedAddress))
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyring = keyrings.find((kr) => {
|
|
||||||
return kr.accounts.includes(selectedAddress)
|
|
||||||
})
|
|
||||||
|
|
||||||
let label = ''
|
|
||||||
let type
|
|
||||||
if (keyring) {
|
|
||||||
type = keyring.type
|
|
||||||
if (type !== 'HD Key Tree') {
|
|
||||||
if (type.toLowerCase().search('hardware') !== -1) {
|
|
||||||
label = this.context.t('hardware')
|
|
||||||
} else {
|
|
||||||
label = this.context.t('imported')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div.wallet-view.flex-column', {
|
|
||||||
style: {},
|
|
||||||
className: responsiveDisplayClassname,
|
|
||||||
}, [
|
|
||||||
|
|
||||||
// TODO: Separate component: wallet account details
|
|
||||||
h('div.flex-column.wallet-view-account-details', {
|
|
||||||
style: {},
|
|
||||||
}, [
|
|
||||||
h('div.wallet-view__sidebar-close', {
|
|
||||||
onClick: hideSidebar,
|
|
||||||
}),
|
|
||||||
|
|
||||||
h('div.wallet-view__keyring-label.allcaps', label),
|
|
||||||
|
|
||||||
h('div.flex-column.flex-center.wallet-view__name-container', {
|
|
||||||
style: { margin: '0 auto' },
|
|
||||||
onClick: showAccountDetailModal,
|
|
||||||
}, [
|
|
||||||
h(Identicon, {
|
|
||||||
diameter: 54,
|
|
||||||
address: checksummedAddress,
|
|
||||||
}),
|
|
||||||
|
|
||||||
h('span.account-name', {
|
|
||||||
style: {},
|
|
||||||
}, [
|
|
||||||
identities[selectedAddress].name,
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('button.btn-clear.wallet-view__details-button.allcaps', this.context.t('details')),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
|
|
||||||
h(Tooltip, {
|
|
||||||
position: 'bottom',
|
|
||||||
title: this.state.hasCopied ? this.context.t('copiedExclamation') : this.context.t('copyToClipboard'),
|
|
||||||
wrapperClassName: 'wallet-view__tooltip',
|
|
||||||
}, [
|
|
||||||
h('button.wallet-view__address', {
|
|
||||||
className: classnames({
|
|
||||||
'wallet-view__address__pressed': this.state.copyToClipboardPressed,
|
|
||||||
}),
|
|
||||||
onClick: () => {
|
|
||||||
copyToClipboard(checksummedAddress)
|
|
||||||
this.setState({ hasCopied: true })
|
|
||||||
setTimeout(() => this.setState({ hasCopied: false }), 3000)
|
|
||||||
},
|
|
||||||
onMouseDown: () => {
|
|
||||||
this.setState({ copyToClipboardPressed: true })
|
|
||||||
},
|
|
||||||
onMouseUp: () => {
|
|
||||||
this.setState({ copyToClipboardPressed: false })
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
`${checksummedAddress.slice(0, 6)}...${checksummedAddress.slice(-4)}`,
|
|
||||||
h('i.fa.fa-clipboard', { style: { marginLeft: '8px' } }),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
|
|
||||||
this.renderWalletBalance(),
|
|
||||||
|
|
||||||
h(TokenList),
|
|
||||||
|
|
||||||
this.renderAddToken(),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Extra wallets, for dev testing. Remove when PRing to master.
|
|
||||||
// const extraWallet = h('div.flex-column.wallet-balance-wrapper', {}, [
|
|
||||||
// h('div.wallet-balance', {}, [
|
|
||||||
// h(BalanceComponent, {
|
|
||||||
// balanceValue: selectedAccount.balance,
|
|
||||||
// style: {},
|
|
||||||
// }),
|
|
||||||
// ]),
|
|
||||||
// ])
|
|
|
@ -1,207 +0,0 @@
|
||||||
const { EventEmitter } = require('events')
|
|
||||||
const { Component } = require('react')
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const actions = require('../actions')
|
|
||||||
const Tooltip = require('../components/tooltip')
|
|
||||||
const { RESTORE_VAULT_ROUTE, DEFAULT_ROUTE } = require('../routes')
|
|
||||||
const { getEnvironmentType } = require('../../../app/scripts/lib/util')
|
|
||||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../../app/scripts/lib/enums')
|
|
||||||
|
|
||||||
class InitializeMenuScreen extends Component {
|
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
this.animationEventEmitter = new EventEmitter()
|
|
||||||
this.state = {
|
|
||||||
warning: null,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount () {
|
|
||||||
const { isInitialized, isUnlocked, history } = this.props
|
|
||||||
if (isInitialized || isUnlocked) {
|
|
||||||
history.push(DEFAULT_ROUTE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
document.getElementById('password-box').focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { warning } = this.state
|
|
||||||
|
|
||||||
return (
|
|
||||||
h('.initialize-screen.flex-column.flex-center', [
|
|
||||||
|
|
||||||
h('h1', {
|
|
||||||
style: {
|
|
||||||
fontSize: '1.3em',
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
color: '#7F8082',
|
|
||||||
marginBottom: 10,
|
|
||||||
},
|
|
||||||
}, this.context.t('appName')),
|
|
||||||
|
|
||||||
h('div', [
|
|
||||||
h('h3', {
|
|
||||||
style: {
|
|
||||||
fontSize: '0.8em',
|
|
||||||
color: '#7F8082',
|
|
||||||
display: 'inline',
|
|
||||||
},
|
|
||||||
}, this.context.t('encryptNewDen')),
|
|
||||||
|
|
||||||
h(Tooltip, {
|
|
||||||
title: this.context.t('denExplainer'),
|
|
||||||
}, [
|
|
||||||
h('i.fa.fa-question-circle.pointer', {
|
|
||||||
style: {
|
|
||||||
fontSize: '18px',
|
|
||||||
position: 'relative',
|
|
||||||
color: 'rgb(247, 134, 28)',
|
|
||||||
top: '2px',
|
|
||||||
marginLeft: '4px',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('span.error.in-progress-notification', warning),
|
|
||||||
|
|
||||||
// password
|
|
||||||
h('input.large-input.letter-spacey', {
|
|
||||||
type: 'password',
|
|
||||||
id: 'password-box',
|
|
||||||
placeholder: this.context.t('newPassword'),
|
|
||||||
onInput: this.inputChanged.bind(this),
|
|
||||||
style: {
|
|
||||||
width: 260,
|
|
||||||
marginTop: 12,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
// confirm password
|
|
||||||
h('input.large-input.letter-spacey', {
|
|
||||||
type: 'password',
|
|
||||||
id: 'password-box-confirm',
|
|
||||||
placeholder: this.context.t('confirmPassword'),
|
|
||||||
onKeyPress: this.createVaultOnEnter.bind(this),
|
|
||||||
onInput: this.inputChanged.bind(this),
|
|
||||||
style: {
|
|
||||||
width: 260,
|
|
||||||
marginTop: 16,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
|
|
||||||
h('button.primary', {
|
|
||||||
onClick: this.createNewVaultAndKeychain.bind(this),
|
|
||||||
style: {
|
|
||||||
margin: 12,
|
|
||||||
},
|
|
||||||
}, this.context.t('createDen')),
|
|
||||||
|
|
||||||
h('.flex-row.flex-center.flex-grow', [
|
|
||||||
h('p.pointer', {
|
|
||||||
onClick: () => this.showRestoreVault(),
|
|
||||||
style: {
|
|
||||||
fontSize: '0.8em',
|
|
||||||
color: 'rgb(247, 134, 28)',
|
|
||||||
textDecoration: 'underline',
|
|
||||||
},
|
|
||||||
}, this.context.t('importDen')),
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('.flex-row.flex-center.flex-grow', [
|
|
||||||
h('p.pointer', {
|
|
||||||
onClick: this.showOldUI.bind(this),
|
|
||||||
style: {
|
|
||||||
fontSize: '0.8em',
|
|
||||||
color: '#aeaeae',
|
|
||||||
textDecoration: 'underline',
|
|
||||||
marginTop: '32px',
|
|
||||||
},
|
|
||||||
}, this.context.t('classicInterface')),
|
|
||||||
]),
|
|
||||||
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
createVaultOnEnter (event) {
|
|
||||||
if (event.key === 'Enter') {
|
|
||||||
event.preventDefault()
|
|
||||||
this.createNewVaultAndKeychain()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createNewVaultAndKeychain () {
|
|
||||||
const { history } = this.props
|
|
||||||
var passwordBox = document.getElementById('password-box')
|
|
||||||
var password = passwordBox.value
|
|
||||||
var passwordConfirmBox = document.getElementById('password-box-confirm')
|
|
||||||
var passwordConfirm = passwordConfirmBox.value
|
|
||||||
|
|
||||||
this.setState({ warning: null })
|
|
||||||
|
|
||||||
if (password.length < 8) {
|
|
||||||
this.setState({ warning: this.context.t('passwordShort') })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (password !== passwordConfirm) {
|
|
||||||
this.setState({ warning: this.context.t('passwordMismatch') })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.createNewVaultAndKeychain(password)
|
|
||||||
.then(() => history.push(DEFAULT_ROUTE))
|
|
||||||
}
|
|
||||||
|
|
||||||
showRestoreVault () {
|
|
||||||
this.props.markPasswordForgotten()
|
|
||||||
if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) {
|
|
||||||
global.platform.openExtensionInBrowser()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.history.push(RESTORE_VAULT_ROUTE)
|
|
||||||
}
|
|
||||||
|
|
||||||
showOldUI () {
|
|
||||||
this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMenuScreen.propTypes = {
|
|
||||||
history: PropTypes.object,
|
|
||||||
isInitialized: PropTypes.bool,
|
|
||||||
isUnlocked: PropTypes.bool,
|
|
||||||
createNewVaultAndKeychain: PropTypes.func,
|
|
||||||
markPasswordForgotten: PropTypes.func,
|
|
||||||
dispatch: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMenuScreen.contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const { metamask: { isInitialized, isUnlocked } } = state
|
|
||||||
|
|
||||||
return {
|
|
||||||
isInitialized,
|
|
||||||
isUnlocked,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
|
||||||
return {
|
|
||||||
createNewVaultAndKeychain: password => dispatch(actions.createNewVaultAndKeychain(password)),
|
|
||||||
markPasswordForgotten: () => dispatch(actions.markPasswordForgotten()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(InitializeMenuScreen)
|
|
|
@ -3,7 +3,6 @@ const Component = require('react').Component
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const { HashRouter } = require('react-router-dom')
|
const { HashRouter } = require('react-router-dom')
|
||||||
const App = require('./app')
|
|
||||||
const OldApp = require('../../old-ui/app/app')
|
const OldApp = require('../../old-ui/app/app')
|
||||||
const { autoAddToBetaUI } = require('./selectors')
|
const { autoAddToBetaUI } = require('./selectors')
|
||||||
const { setFeatureFlag } = require('./actions')
|
const { setFeatureFlag } = require('./actions')
|
||||||
|
@ -11,7 +10,6 @@ const I18nProvider = require('./i18n-provider')
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
return {
|
return {
|
||||||
betaUI: state.metamask.featureFlags.betaUI,
|
|
||||||
autoAdd: autoAddToBetaUI(state),
|
autoAdd: autoAddToBetaUI(state),
|
||||||
isUnlocked: state.metamask.isUnlocked,
|
isUnlocked: state.metamask.isUnlocked,
|
||||||
isMascara: state.metamask.isMascara,
|
isMascara: state.metamask.isMascara,
|
||||||
|
@ -60,15 +58,7 @@ SelectedApp.prototype.render = function () {
|
||||||
// const { betaUI, isMascara, firstTime } = this.props
|
// const { betaUI, isMascara, firstTime } = this.props
|
||||||
// const Selected = betaUI || isMascara || firstTime ? App : OldApp
|
// const Selected = betaUI || isMascara || firstTime ? App : OldApp
|
||||||
|
|
||||||
const { betaUI, isMascara } = this.props
|
return h(HashRouter, {
|
||||||
|
|
||||||
return betaUI || isMascara
|
|
||||||
? h(HashRouter, {
|
|
||||||
hashType: 'noslash',
|
|
||||||
}, [
|
|
||||||
h(I18nProvider, [ h(App) ]),
|
|
||||||
])
|
|
||||||
: h(HashRouter, {
|
|
||||||
hashType: 'noslash',
|
hashType: 'noslash',
|
||||||
}, [
|
}, [
|
||||||
h(I18nProvider, [ h(OldApp) ]),
|
h(I18nProvider, [ h(OldApp) ]),
|
||||||
|
|
123
ui/example.js
123
ui/example.js
|
@ -1,123 +0,0 @@
|
||||||
const injectCss = require('inject-css')
|
|
||||||
const MetaMaskUi = require('./index.js')
|
|
||||||
const MetaMaskUiCss = require('./css.js')
|
|
||||||
const EventEmitter = require('events').EventEmitter
|
|
||||||
|
|
||||||
// account management
|
|
||||||
|
|
||||||
var identities = {
|
|
||||||
'0x1113462427bcc9133bb46e88bcbe39cd7ef0e111': {
|
|
||||||
name: 'Walrus',
|
|
||||||
img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
|
|
||||||
address: '0x1113462427bcc9133bb46e88bcbe39cd7ef0e111',
|
|
||||||
balance: 220,
|
|
||||||
txCount: 4,
|
|
||||||
},
|
|
||||||
'0x222462427bcc9133bb46e88bcbe39cd7ef0e7222': {
|
|
||||||
name: 'Tardus',
|
|
||||||
img: 'QmQYaRdrf2EhRhJWaHnts8Meu1mZiXrNib5W1P6cYmXWRL',
|
|
||||||
address: '0x222462427bcc9133bb46e88bcbe39cd7ef0e7222',
|
|
||||||
balance: 10.005,
|
|
||||||
txCount: 16,
|
|
||||||
},
|
|
||||||
'0x333462427bcc9133bb46e88bcbe39cd7ef0e7333': {
|
|
||||||
name: 'Gambler',
|
|
||||||
img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
|
|
||||||
address: '0x333462427bcc9133bb46e88bcbe39cd7ef0e7333',
|
|
||||||
balance: 0.000001,
|
|
||||||
txCount: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var unapprovedTxs = {}
|
|
||||||
addUnconfTx({
|
|
||||||
from: '0x222462427bcc9133bb46e88bcbe39cd7ef0e7222',
|
|
||||||
to: '0x1113462427bcc9133bb46e88bcbe39cd7ef0e111',
|
|
||||||
value: '0x123',
|
|
||||||
})
|
|
||||||
addUnconfTx({
|
|
||||||
from: '0x1113462427bcc9133bb46e88bcbe39cd7ef0e111',
|
|
||||||
to: '0x333462427bcc9133bb46e88bcbe39cd7ef0e7333',
|
|
||||||
value: '0x0000',
|
|
||||||
data: '0x000462427bcc9133bb46e88bcbe39cd7ef0e7000',
|
|
||||||
})
|
|
||||||
|
|
||||||
function addUnconfTx (txParams) {
|
|
||||||
var time = (new Date()).getTime()
|
|
||||||
var id = createRandomId()
|
|
||||||
unapprovedTxs[id] = {
|
|
||||||
id: id,
|
|
||||||
txParams: txParams,
|
|
||||||
time: time,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isUnlocked = false
|
|
||||||
var selectedAccount = null
|
|
||||||
|
|
||||||
function getState () {
|
|
||||||
return {
|
|
||||||
isUnlocked: isUnlocked,
|
|
||||||
identities: isUnlocked ? identities : {},
|
|
||||||
unapprovedTxs: isUnlocked ? unapprovedTxs : {},
|
|
||||||
selectedAccount: selectedAccount,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var accountManager = new EventEmitter()
|
|
||||||
|
|
||||||
accountManager.getState = function (cb) {
|
|
||||||
cb(null, getState())
|
|
||||||
}
|
|
||||||
|
|
||||||
accountManager.setLocked = function () {
|
|
||||||
isUnlocked = false
|
|
||||||
this._didUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
accountManager.submitPassword = function (password, cb) {
|
|
||||||
if (password === 'test') {
|
|
||||||
isUnlocked = true
|
|
||||||
cb(null, getState())
|
|
||||||
this._didUpdate()
|
|
||||||
} else {
|
|
||||||
cb(new Error('Bad password -- try "test"'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accountManager.setSelectedAccount = function (address, cb) {
|
|
||||||
selectedAccount = address
|
|
||||||
cb(null, getState())
|
|
||||||
this._didUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
accountManager.signTransaction = function (txParams, cb) {
|
|
||||||
alert('signing tx....')
|
|
||||||
}
|
|
||||||
|
|
||||||
accountManager._didUpdate = function () {
|
|
||||||
this.emit('update', getState())
|
|
||||||
}
|
|
||||||
|
|
||||||
// start app
|
|
||||||
|
|
||||||
var container = document.getElementById('app-content')
|
|
||||||
|
|
||||||
var css = MetaMaskUiCss()
|
|
||||||
injectCss(css)
|
|
||||||
|
|
||||||
MetaMaskUi({
|
|
||||||
container: container,
|
|
||||||
accountManager: accountManager,
|
|
||||||
})
|
|
||||||
|
|
||||||
// util
|
|
||||||
|
|
||||||
function createRandomId () {
|
|
||||||
// 13 time digits
|
|
||||||
var datePart = new Date().getTime() * Math.pow(10, 3)
|
|
||||||
// 3 random digits
|
|
||||||
var extraPart = Math.floor(Math.random() * Math.pow(10, 3))
|
|
||||||
// 16 digits
|
|
||||||
return datePart + extraPart
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Nifty Wallet</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- app content -->
|
|
||||||
<div id="app-content"></div>
|
|
||||||
<script src="./bundle.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
<!-- design reference -->
|
|
||||||
<link rel="stylesheet" type="text/css" href="./app/css/debug.css">
|
|
||||||
<div id="design-container">
|
|
||||||
<img id="design-img" src="./design/metamask_wfs_jan_13.png">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in New Issue