mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-26 12:29:06 +01:00
Merge branch 'develop' into e2e-tests
This commit is contained in:
commit
517be35ab6
@ -393,6 +393,9 @@
|
||||
"message": "Imported",
|
||||
"description": "status showing that an account has been fully loaded into the keyring"
|
||||
},
|
||||
"importUsingSeed": {
|
||||
"message": "Import using account seed phrase"
|
||||
},
|
||||
"infoHelp": {
|
||||
"message": "Info & Help"
|
||||
},
|
||||
@ -632,7 +635,7 @@
|
||||
"message": "Reset Account"
|
||||
},
|
||||
"restoreFromSeed": {
|
||||
"message": "Restore from seed phrase"
|
||||
"message": "Restore account?"
|
||||
},
|
||||
"restoreVault": {
|
||||
"message": "Restore Vault"
|
||||
@ -721,7 +724,7 @@
|
||||
"message": "New Password (min 8 chars)"
|
||||
},
|
||||
"seedPhraseReq": {
|
||||
"message": "seed phrases are 12 words long"
|
||||
"message": "Seed phrases are 12 words long"
|
||||
},
|
||||
"select": {
|
||||
"message": "Select"
|
||||
@ -896,6 +899,9 @@
|
||||
"unknownNetworkId": {
|
||||
"message": "Unknown network ID"
|
||||
},
|
||||
"unlockMessage": {
|
||||
"message": "The decentralized web awaits"
|
||||
},
|
||||
"uriErrorMsg": {
|
||||
"message": "URIs require the appropriate HTTP/HTTPS prefix."
|
||||
},
|
||||
@ -924,6 +930,9 @@
|
||||
"warning": {
|
||||
"message": "Warning"
|
||||
},
|
||||
"welcomeBack": {
|
||||
"message": "Welcome Back!"
|
||||
},
|
||||
"welcomeBeta": {
|
||||
"message": "Welcome to MetaMask Beta"
|
||||
},
|
||||
|
@ -13,8 +13,13 @@ import {
|
||||
INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE,
|
||||
INITIALIZE_NOTICE_ROUTE,
|
||||
} from '../../../../ui/app/routes'
|
||||
import TextField from '../../../../ui/app/components/text-field'
|
||||
|
||||
class CreatePasswordScreen extends Component {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
createAccount: PropTypes.func.isRequired,
|
||||
@ -27,6 +32,8 @@ class CreatePasswordScreen extends Component {
|
||||
state = {
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
passwordError: null,
|
||||
confirmPasswordError: null,
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
@ -69,82 +76,37 @@ class CreatePasswordScreen extends Component {
|
||||
.then(() => history.push(INITIALIZE_UNIQUE_IMAGE_ROUTE))
|
||||
}
|
||||
|
||||
renderFields () {
|
||||
const { isMascara, history } = this.props
|
||||
handlePasswordChange (password) {
|
||||
const { confirmPassword } = this.state
|
||||
let confirmPasswordError = null
|
||||
let passwordError = null
|
||||
|
||||
return (
|
||||
<div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
|
||||
<div className={classnames({
|
||||
'first-view-main': !isMascara,
|
||||
'first-view-main__mascara': isMascara,
|
||||
})}>
|
||||
{isMascara && <div className="mascara-info first-view-phone-invisible">
|
||||
<Mascot
|
||||
animationEventEmitter={this.animationEventEmitter}
|
||||
width="225"
|
||||
height="225"
|
||||
/>
|
||||
<div className="info">
|
||||
MetaMask is a secure identity vault for Ethereum.
|
||||
</div>
|
||||
<div className="info">
|
||||
It allows you to hold ether & tokens, and interact with decentralized applications.
|
||||
</div>
|
||||
</div>}
|
||||
<div className="create-password">
|
||||
<div className="create-password__title">
|
||||
Create Password
|
||||
</div>
|
||||
<input
|
||||
className="first-time-flow__input"
|
||||
type="password"
|
||||
placeholder="New Password (min 8 characters)"
|
||||
onChange={e => this.setState({password: e.target.value})}
|
||||
/>
|
||||
<input
|
||||
className="first-time-flow__input create-password__confirm-input"
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
onChange={e => this.setState({confirmPassword: e.target.value})}
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
disabled={!this.isValid()}
|
||||
onClick={this.createAccount}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
<a
|
||||
href=""
|
||||
className="first-time-flow__link create-password__import-link"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE)
|
||||
}}
|
||||
>
|
||||
Import with seed phrase
|
||||
</a>
|
||||
{ /* }
|
||||
<a
|
||||
href=""
|
||||
className="first-time-flow__link create-password__import-link"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
history.push(INITIALIZE_IMPORT_ACCOUNT_ROUTE)
|
||||
}}
|
||||
>
|
||||
Import an account
|
||||
</a>
|
||||
{ */ }
|
||||
<Breadcrumbs total={3} currentIndex={0} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
if (password && password.length < 8) {
|
||||
passwordError = this.context.t('passwordNotLongEnough')
|
||||
}
|
||||
|
||||
if (confirmPassword && password !== confirmPassword) {
|
||||
confirmPasswordError = this.context.t('passwordsDontMatch')
|
||||
}
|
||||
|
||||
this.setState({ password, passwordError, confirmPasswordError })
|
||||
}
|
||||
|
||||
handleConfirmPasswordChange (confirmPassword) {
|
||||
const { password } = this.state
|
||||
let confirmPasswordError = null
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
confirmPasswordError = this.context.t('passwordsDontMatch')
|
||||
}
|
||||
|
||||
this.setState({ confirmPassword, confirmPasswordError })
|
||||
}
|
||||
|
||||
render () {
|
||||
const { history, isMascara } = this.props
|
||||
const { passwordError, confirmPasswordError } = this.state
|
||||
const { t } = this.context
|
||||
|
||||
return (
|
||||
<div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
|
||||
@ -169,17 +131,30 @@ class CreatePasswordScreen extends Component {
|
||||
<div className="create-password__title">
|
||||
Create Password
|
||||
</div>
|
||||
<input
|
||||
<TextField
|
||||
id="create-password"
|
||||
label={t('newPassword')}
|
||||
type="password"
|
||||
className="first-time-flow__input"
|
||||
type="password"
|
||||
placeholder="New Password (min 8 characters)"
|
||||
onChange={e => this.setState({password: e.target.value})}
|
||||
value={this.state.password}
|
||||
onChange={event => this.handlePasswordChange(event.target.value)}
|
||||
error={passwordError}
|
||||
autoFocus
|
||||
autoComplete="new-password"
|
||||
margin="normal"
|
||||
fullWidth
|
||||
/>
|
||||
<input
|
||||
className="first-time-flow__input create-password__confirm-input"
|
||||
<TextField
|
||||
id="confirm-password"
|
||||
label={t('confirmPassword')}
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
onChange={e => this.setState({confirmPassword: e.target.value})}
|
||||
className="first-time-flow__input"
|
||||
value={this.state.confirmPassword}
|
||||
onChange={event => this.handleConfirmPasswordChange(event.target.value)}
|
||||
error={confirmPasswordError}
|
||||
autoComplete="confirm-password"
|
||||
margin="normal"
|
||||
fullWidth
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
|
@ -1,29 +1,33 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
import classnames from 'classnames'
|
||||
import {
|
||||
createNewVaultAndRestore,
|
||||
hideWarning,
|
||||
displayWarning,
|
||||
unMarkPasswordForgotten,
|
||||
} from '../../../../ui/app/actions'
|
||||
import { DEFAULT_ROUTE, INITIALIZE_NOTICE_ROUTE } from '../../../../ui/app/routes'
|
||||
import { INITIALIZE_NOTICE_ROUTE } from '../../../../ui/app/routes'
|
||||
import TextField from '../../../../ui/app/components/text-field'
|
||||
|
||||
class ImportSeedPhraseScreen extends Component {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
warning: PropTypes.string,
|
||||
createNewVaultAndRestore: PropTypes.func.isRequired,
|
||||
hideWarning: PropTypes.func.isRequired,
|
||||
displayWarning: PropTypes.func,
|
||||
leaveImportSeedScreenState: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
isLoading: PropTypes.bool,
|
||||
};
|
||||
|
||||
state = {
|
||||
seedPhrase: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
seedPhraseError: null,
|
||||
passwordError: null,
|
||||
confirmPasswordError: null,
|
||||
}
|
||||
|
||||
parseSeedPhrase = (seedPhrase) => {
|
||||
@ -32,39 +36,47 @@ class ImportSeedPhraseScreen extends Component {
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
onChange = ({ seedPhrase, password, confirmPassword }) => {
|
||||
const {
|
||||
password: prevPassword,
|
||||
confirmPassword: prevConfirmPassword,
|
||||
} = this.state
|
||||
const { displayWarning, hideWarning } = this.props
|
||||
|
||||
let warning = null
|
||||
handleSeedPhraseChange (seedPhrase) {
|
||||
let seedPhraseError = null
|
||||
|
||||
if (seedPhrase && this.parseSeedPhrase(seedPhrase).split(' ').length !== 12) {
|
||||
warning = 'Seed Phrases are 12 words long'
|
||||
} else if (password && password.length < 8) {
|
||||
warning = 'Passwords require a mimimum length of 8'
|
||||
} else if ((password || prevPassword) !== (confirmPassword || prevConfirmPassword)) {
|
||||
warning = 'Confirmed password does not match'
|
||||
seedPhraseError = this.context.t('seedPhraseReq')
|
||||
}
|
||||
|
||||
if (warning) {
|
||||
displayWarning(warning)
|
||||
} else {
|
||||
hideWarning()
|
||||
this.setState({ seedPhrase, seedPhraseError })
|
||||
}
|
||||
|
||||
handlePasswordChange (password) {
|
||||
const { confirmPassword } = this.state
|
||||
let confirmPasswordError = null
|
||||
let passwordError = null
|
||||
|
||||
if (password && password.length < 8) {
|
||||
passwordError = this.context.t('passwordNotLongEnough')
|
||||
}
|
||||
|
||||
seedPhrase && this.setState({ seedPhrase })
|
||||
password && this.setState({ password })
|
||||
confirmPassword && this.setState({ confirmPassword })
|
||||
if (confirmPassword && password !== confirmPassword) {
|
||||
confirmPasswordError = this.context.t('passwordsDontMatch')
|
||||
}
|
||||
|
||||
this.setState({ password, passwordError, confirmPasswordError })
|
||||
}
|
||||
|
||||
handleConfirmPasswordChange (confirmPassword) {
|
||||
const { password } = this.state
|
||||
let confirmPasswordError = null
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
confirmPasswordError = this.context.t('passwordsDontMatch')
|
||||
}
|
||||
|
||||
this.setState({ confirmPassword, confirmPasswordError })
|
||||
}
|
||||
|
||||
onClick = () => {
|
||||
const { password, seedPhrase } = this.state
|
||||
const {
|
||||
createNewVaultAndRestore,
|
||||
displayWarning,
|
||||
leaveImportSeedScreenState,
|
||||
history,
|
||||
} = this.props
|
||||
@ -74,10 +86,23 @@ class ImportSeedPhraseScreen extends Component {
|
||||
.then(() => history.push(INITIALIZE_NOTICE_ROUTE))
|
||||
}
|
||||
|
||||
hasError () {
|
||||
const { passwordError, confirmPasswordError, seedPhraseError } = this.state
|
||||
return passwordError || confirmPasswordError || seedPhraseError
|
||||
}
|
||||
|
||||
render () {
|
||||
const { seedPhrase, password, confirmPassword } = this.state
|
||||
const { warning, isLoading } = this.props
|
||||
const importDisabled = warning || !seedPhrase || !password || !confirmPassword || isLoading
|
||||
const {
|
||||
seedPhrase,
|
||||
password,
|
||||
confirmPassword,
|
||||
seedPhraseError,
|
||||
passwordError,
|
||||
confirmPasswordError,
|
||||
} = this.state
|
||||
const { t } = this.context
|
||||
const { isLoading } = this.props
|
||||
const disabled = !seedPhrase || !password || !confirmPassword || isLoading || this.hasError()
|
||||
|
||||
return (
|
||||
<div className="first-view-main-wrapper">
|
||||
@ -103,45 +128,40 @@ class ImportSeedPhraseScreen extends Component {
|
||||
<label className="import-account__input-label">Wallet Seed</label>
|
||||
<textarea
|
||||
className="import-account__secret-phrase"
|
||||
onChange={e => this.onChange({seedPhrase: e.target.value})}
|
||||
onChange={e => this.handleSeedPhraseChange(e.target.value)}
|
||||
value={this.state.seedPhrase}
|
||||
placeholder="Separate each word with a single space"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="error"
|
||||
>
|
||||
{this.props.warning}
|
||||
<span className="error">
|
||||
{ seedPhraseError }
|
||||
</span>
|
||||
<div className="import-account__input-wrapper">
|
||||
<label className="import-account__input-label">New Password</label>
|
||||
<input
|
||||
className="first-time-flow__input"
|
||||
type="password"
|
||||
placeholder="New Password (min 8 characters)"
|
||||
onChange={e => this.onChange({password: e.target.value})}
|
||||
/>
|
||||
</div>
|
||||
<div className="import-account__input-wrapper">
|
||||
<label
|
||||
className={classnames('import-account__input-label', {
|
||||
'import-account__input-label__disabled': password.length < 8,
|
||||
})}
|
||||
>Confirm Password</label>
|
||||
<input
|
||||
className={classnames('first-time-flow__input', {
|
||||
'first-time-flow__input__disabled': password.length < 8,
|
||||
})}
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
onChange={e => this.onChange({confirmPassword: e.target.value})}
|
||||
disabled={password.length < 8}
|
||||
/>
|
||||
</div>
|
||||
<TextField
|
||||
id="password"
|
||||
label={t('newPassword')}
|
||||
type="password"
|
||||
className="first-time-flow__input"
|
||||
value={this.state.password}
|
||||
onChange={event => this.handlePasswordChange(event.target.value)}
|
||||
error={passwordError}
|
||||
autoComplete="new-password"
|
||||
margin="normal"
|
||||
/>
|
||||
<TextField
|
||||
id="confirm-password"
|
||||
label={t('confirmPassword')}
|
||||
type="password"
|
||||
className="first-time-flow__input"
|
||||
value={this.state.confirmPassword}
|
||||
onChange={event => this.handleConfirmPasswordChange(event.target.value)}
|
||||
error={confirmPasswordError}
|
||||
autoComplete="confirm-password"
|
||||
margin="normal"
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
onClick={() => !importDisabled && this.onClick()}
|
||||
disabled={importDisabled}
|
||||
onClick={() => !disabled && this.onClick()}
|
||||
disabled={disabled}
|
||||
>
|
||||
Import
|
||||
</button>
|
||||
@ -159,7 +179,5 @@ export default connect(
|
||||
dispatch(unMarkPasswordForgotten())
|
||||
},
|
||||
createNewVaultAndRestore: (pw, seed) => dispatch(createNewVaultAndRestore(pw, seed)),
|
||||
displayWarning: (warning) => dispatch(displayWarning(warning)),
|
||||
hideWarning: () => dispatch(hideWarning()),
|
||||
})
|
||||
)(ImportSeedPhraseScreen)
|
||||
|
@ -21,6 +21,7 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background: #f7861c;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.alpha-warning,
|
||||
@ -173,10 +174,7 @@
|
||||
}
|
||||
|
||||
.first-time-flow__input {
|
||||
width: initial !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 18px !important;
|
||||
padding: 12px !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tou__body {
|
||||
@ -247,7 +245,7 @@
|
||||
}
|
||||
|
||||
.create-password__confirm-input {
|
||||
margin-top: 15px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.create-password__import-link {
|
||||
@ -519,10 +517,6 @@ button.backup-phrase__confirm-seed-option:hover {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.first-time-flow__input--error {
|
||||
border: 1px solid #FF001F !important;
|
||||
}
|
||||
|
||||
.import-account__input-error-message {
|
||||
margin-top: 10px;
|
||||
width: 422px;
|
||||
@ -543,7 +537,13 @@ button.backup-phrase__confirm-seed-option:hover {
|
||||
}
|
||||
|
||||
.import-account__input {
|
||||
width: 325px !important;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 575px) {
|
||||
.import-account__input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.import-account__file-input {
|
||||
@ -680,20 +680,6 @@ button.backup-phrase__confirm-seed-option:hover {
|
||||
|
||||
.first-time-flow__input {
|
||||
width: 350px;
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
padding: 15px;
|
||||
border: 1px solid #CDCDCD;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.first-time-flow__input__disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.first-time-flow__input::placeholder {
|
||||
color: #9B9B9B;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.first-time-flow__button {
|
||||
|
@ -3,6 +3,8 @@ import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
import { withRouter, Switch, Route } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import CreatePasswordScreen from './create-password-screen'
|
||||
import UniqueImageScreen from './unique-image-screen'
|
||||
import NoticeScreen from './notice-screen'
|
||||
@ -33,6 +35,7 @@ class FirstTimeFlow extends Component {
|
||||
isUnlocked: PropTypes.bool,
|
||||
history: PropTypes.object,
|
||||
welcomeScreenSeen: PropTypes.bool,
|
||||
isPopup: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@ -41,23 +44,44 @@ class FirstTimeFlow extends Component {
|
||||
noActiveNotices: false,
|
||||
};
|
||||
|
||||
render () {
|
||||
renderAppBar () {
|
||||
const { welcomeScreenSeen } = this.props
|
||||
|
||||
return (
|
||||
<div className="first-time-flow">
|
||||
<Switch>
|
||||
<Route exact path={INITIALIZE_IMPORT_ACCOUNT_ROUTE} component={ImportAccountScreen} />
|
||||
<Route
|
||||
exact
|
||||
path={INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE}
|
||||
component={ImportSeedPhraseScreen}
|
||||
/>
|
||||
<Route exact path={INITIALIZE_UNIQUE_IMAGE_ROUTE} component={UniqueImageScreen} />
|
||||
<Route exact path={INITIALIZE_NOTICE_ROUTE} component={NoticeScreen} />
|
||||
<Route exact path={INITIALIZE_BACKUP_PHRASE_ROUTE} component={BackupPhraseScreen} />
|
||||
<Route exact path={INITIALIZE_CONFIRM_SEED_ROUTE} component={ConfirmSeed} />
|
||||
<Route exact path={INITIALIZE_CREATE_PASSWORD_ROUTE} component={CreatePasswordScreen} />
|
||||
<Route exact path={INITIALIZE_ROUTE} component={WelcomeScreen} />
|
||||
</Switch>
|
||||
<div className="alpha-warning__container">
|
||||
<h2 className={classnames({
|
||||
'alpha-warning': welcomeScreenSeen,
|
||||
'alpha-warning-welcome-screen': !welcomeScreenSeen,
|
||||
})}
|
||||
>
|
||||
Please be aware that this version is still under development
|
||||
</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { isPopup } = this.props
|
||||
|
||||
return (
|
||||
<div className="flex-column flex-grow">
|
||||
{ !isPopup && this.renderAppBar() }
|
||||
<div className="first-time-flow">
|
||||
<Switch>
|
||||
<Route exact path={INITIALIZE_IMPORT_ACCOUNT_ROUTE} component={ImportAccountScreen} />
|
||||
<Route
|
||||
exact
|
||||
path={INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE}
|
||||
component={ImportSeedPhraseScreen}
|
||||
/>
|
||||
<Route exact path={INITIALIZE_UNIQUE_IMAGE_ROUTE} component={UniqueImageScreen} />
|
||||
<Route exact path={INITIALIZE_NOTICE_ROUTE} component={NoticeScreen} />
|
||||
<Route exact path={INITIALIZE_BACKUP_PHRASE_ROUTE} component={BackupPhraseScreen} />
|
||||
<Route exact path={INITIALIZE_CONFIRM_SEED_ROUTE} component={ConfirmSeed} />
|
||||
<Route exact path={INITIALIZE_CREATE_PASSWORD_ROUTE} component={CreatePasswordScreen} />
|
||||
<Route exact path={INITIALIZE_ROUTE} component={WelcomeScreen} />
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -73,6 +97,7 @@ const mapStateToProps = ({ metamask }) => {
|
||||
isMascara,
|
||||
isUnlocked,
|
||||
welcomeScreenSeen,
|
||||
isPopup,
|
||||
} = metamask
|
||||
|
||||
return {
|
||||
@ -84,6 +109,7 @@ const mapStateToProps = ({ metamask }) => {
|
||||
forgottenPassword,
|
||||
isUnlocked,
|
||||
welcomeScreenSeen,
|
||||
isPopup,
|
||||
}
|
||||
}
|
||||
|
||||
|
319
package-lock.json
generated
319
package-lock.json
generated
@ -1365,12 +1365,37 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/jss": {
|
||||
"version": "9.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/jss/-/jss-9.5.2.tgz",
|
||||
"integrity": "sha512-EX87yNYcisXO5BU9tT7stB7OGuDJyV3JwtMwhfUprrmHwYKWh9a3vchAy6DYzUSbmTA7bD46h8qata5jP1V7Zw==",
|
||||
"requires": {
|
||||
"csstype": "2.4.2",
|
||||
"indefinite-observable": "1.0.1"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "8.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.5.tgz",
|
||||
"integrity": "sha512-JRnfoh0Ll4ElmIXKxbUfcOodkGvcNHljct6mO1X9hE/mlrMzAx0hYCLAD7sgT53YAY1HdlpzUcV0CkmDqUqTuA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "16.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.3.14.tgz",
|
||||
"integrity": "sha512-wNUGm49fPl7eE2fnYdF0v5vSOrUMdKMQD/4NwtQRnb6mnPwtkhabmuFz37eq90+hhyfz0pWd38jkZHOcaZ6LGw==",
|
||||
"requires": {
|
||||
"csstype": "2.4.2"
|
||||
}
|
||||
},
|
||||
"@types/react-transition-group": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.0.9.tgz",
|
||||
"integrity": "sha512-Id2MtQcmOgLymqqLqg1VjzNpN7O5vGoF47h3s7jxhzqWdMCtk2GwxFUqcKbGrRmHzzQGyRatfG8yahonIys74Q==",
|
||||
"requires": {
|
||||
"@types/react": "16.3.14"
|
||||
}
|
||||
},
|
||||
"JSONStream": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz",
|
||||
@ -3862,8 +3887,7 @@
|
||||
"brcast": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brcast/-/brcast-3.0.1.tgz",
|
||||
"integrity": "sha512-eI3yqf9YEqyGl9PCNTR46MGvDylGtaHjalcz6Q3fAPnP/PhpKkkve52vFdfGpwp4VUvK6LUr4TQN+2stCrEwTg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-eI3yqf9YEqyGl9PCNTR46MGvDylGtaHjalcz6Q3fAPnP/PhpKkkve52vFdfGpwp4VUvK6LUr4TQN+2stCrEwTg=="
|
||||
},
|
||||
"brfs": {
|
||||
"version": "1.4.3",
|
||||
@ -5907,6 +5931,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-vendor": {
|
||||
"version": "0.3.8",
|
||||
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz",
|
||||
"integrity": "sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo=",
|
||||
"requires": {
|
||||
"is-in-browser": "1.1.3"
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
|
||||
@ -6053,8 +6085,7 @@
|
||||
"csstype": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.4.2.tgz",
|
||||
"integrity": "sha512-1TnkyZwDy0oUl//6685j2bTMNe61SzntWntijNdmmEzvpYbGmVMZkj204gv4glcQp6z/ypg+YRziT91XVFmOyg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-1TnkyZwDy0oUl//6685j2bTMNe61SzntWntijNdmmEzvpYbGmVMZkj204gv4glcQp6z/ypg+YRziT91XVFmOyg=="
|
||||
},
|
||||
"currency-formatter": {
|
||||
"version": "1.4.2",
|
||||
@ -13161,8 +13192,7 @@
|
||||
"hyphenate-style-name": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz",
|
||||
"integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=",
|
||||
"dev": true
|
||||
"integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es="
|
||||
},
|
||||
"i": {
|
||||
"version": "0.3.6",
|
||||
@ -13301,6 +13331,21 @@
|
||||
"resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz",
|
||||
"integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E="
|
||||
},
|
||||
"indefinite-observable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-1.0.1.tgz",
|
||||
"integrity": "sha1-CZFUI8yNb36xy3iCrRNGM8mm7cM=",
|
||||
"requires": {
|
||||
"symbol-observable": "1.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"symbol-observable": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz",
|
||||
"integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"indent-string": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
|
||||
@ -13792,6 +13837,11 @@
|
||||
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz",
|
||||
"integrity": "sha1-bghLvJIGH7sJcexYts5tQE4k2mk="
|
||||
},
|
||||
"is-in-browser": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
|
||||
"integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU="
|
||||
},
|
||||
"is-my-ip-valid": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz",
|
||||
@ -14755,6 +14805,101 @@
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"jss": {
|
||||
"version": "9.8.1",
|
||||
"resolved": "https://registry.npmjs.org/jss/-/jss-9.8.1.tgz",
|
||||
"integrity": "sha512-a9dXInEPTRmdSmzw3LNhbAwdQVZgCRmFU7dFzrpLTMAcdolHXNamhxQ6J+PNIqUtWa9yRbZIzWX6aUlI55LZ/A==",
|
||||
"requires": {
|
||||
"is-in-browser": "1.1.3",
|
||||
"symbol-observable": "1.1.0",
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
"jss-camel-case": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-camel-case/-/jss-camel-case-6.1.0.tgz",
|
||||
"integrity": "sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ==",
|
||||
"requires": {
|
||||
"hyphenate-style-name": "1.0.2"
|
||||
}
|
||||
},
|
||||
"jss-compose": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-compose/-/jss-compose-5.0.0.tgz",
|
||||
"integrity": "sha512-YofRYuiA0+VbeOw0VjgkyO380sA4+TWDrW52nSluD9n+1FWOlDzNbgpZ/Sb3Y46+DcAbOS21W5jo6SAqUEiuwA==",
|
||||
"requires": {
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
"jss-default-unit": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz",
|
||||
"integrity": "sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg=="
|
||||
},
|
||||
"jss-expand": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-expand/-/jss-expand-5.3.0.tgz",
|
||||
"integrity": "sha512-NiM4TbDVE0ykXSAw6dfFmB1LIqXP/jdd0ZMnlvlGgEMkMt+weJIl8Ynq1DsuBY9WwkNyzWktdqcEW2VN0RAtQg=="
|
||||
},
|
||||
"jss-extend": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-extend/-/jss-extend-6.2.0.tgz",
|
||||
"integrity": "sha512-YszrmcB6o9HOsKPszK7NeDBNNjVyiW864jfoiHoMlgMIg2qlxKw70axZHqgczXHDcoyi/0/ikP1XaHDPRvYtEA==",
|
||||
"requires": {
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
"jss-global": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-global/-/jss-global-3.0.0.tgz",
|
||||
"integrity": "sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q=="
|
||||
},
|
||||
"jss-nested": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jss-nested/-/jss-nested-6.0.1.tgz",
|
||||
"integrity": "sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA==",
|
||||
"requires": {
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
"jss-preset-default": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-4.5.0.tgz",
|
||||
"integrity": "sha512-qZbpRVtHT7hBPpZEBPFfafZKWmq3tA/An5RNqywDsZQGrlinIF/mGD9lmj6jGqu8GrED2SMHZ3pPKLmjCZoiaQ==",
|
||||
"requires": {
|
||||
"jss-camel-case": "6.1.0",
|
||||
"jss-compose": "5.0.0",
|
||||
"jss-default-unit": "8.0.2",
|
||||
"jss-expand": "5.3.0",
|
||||
"jss-extend": "6.2.0",
|
||||
"jss-global": "3.0.0",
|
||||
"jss-nested": "6.0.1",
|
||||
"jss-props-sort": "6.0.0",
|
||||
"jss-template": "1.0.1",
|
||||
"jss-vendor-prefixer": "7.0.0"
|
||||
}
|
||||
},
|
||||
"jss-props-sort": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz",
|
||||
"integrity": "sha512-E89UDcrphmI0LzmvYk25Hp4aE5ZBsXqMWlkFXS0EtPkunJkRr+WXdCNYbXbksIPnKlBenGB9OxzQY+mVc70S+g=="
|
||||
},
|
||||
"jss-template": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jss-template/-/jss-template-1.0.1.tgz",
|
||||
"integrity": "sha512-m5BqEWha17fmIVXm1z8xbJhY6GFJxNB9H68GVnCWPyGYfxiAgY9WTQyvDAVj+pYRgrXSOfN5V1T4+SzN1sJTeg==",
|
||||
"requires": {
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
"jss-vendor-prefixer": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz",
|
||||
"integrity": "sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA==",
|
||||
"requires": {
|
||||
"css-vendor": "0.3.8"
|
||||
}
|
||||
},
|
||||
"jstransform": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jstransform/-/jstransform-10.1.0.tgz",
|
||||
@ -15134,8 +15279,7 @@
|
||||
"keycode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
|
||||
"integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ="
|
||||
},
|
||||
"keyv": {
|
||||
"version": "3.0.0",
|
||||
@ -16642,6 +16786,78 @@
|
||||
"integrity": "sha1-UpJZPmdUyxvMK5gDDk4Najr8nqE=",
|
||||
"dev": true
|
||||
},
|
||||
"material-ui": {
|
||||
"version": "1.0.0-beta.44",
|
||||
"resolved": "https://registry.npmjs.org/material-ui/-/material-ui-1.0.0-beta.44.tgz",
|
||||
"integrity": "sha512-m5SJxvDz77bVKcjyZG/AyG6RBR+UUwkPgvHHLJa2jyAHBNtJMCQ5GVouTXOxaUKlvD5cbO/mcH0YtzugyQTAVg==",
|
||||
"requires": {
|
||||
"@types/jss": "9.5.2",
|
||||
"@types/react-transition-group": "2.0.9",
|
||||
"babel-runtime": "6.26.0",
|
||||
"brcast": "3.0.1",
|
||||
"classnames": "2.2.5",
|
||||
"deepmerge": "2.1.0",
|
||||
"dom-helpers": "3.3.1",
|
||||
"hoist-non-react-statics": "2.5.0",
|
||||
"jss": "9.8.1",
|
||||
"jss-camel-case": "6.1.0",
|
||||
"jss-default-unit": "8.0.2",
|
||||
"jss-global": "3.0.0",
|
||||
"jss-nested": "6.0.1",
|
||||
"jss-props-sort": "6.0.0",
|
||||
"jss-vendor-prefixer": "7.0.0",
|
||||
"keycode": "2.2.0",
|
||||
"lodash": "4.17.4",
|
||||
"normalize-scroll-left": "0.1.2",
|
||||
"prop-types": "15.6.1",
|
||||
"react-event-listener": "0.5.3",
|
||||
"react-jss": "8.4.0",
|
||||
"react-lifecycles-compat": "2.0.2",
|
||||
"react-popper": "0.10.4",
|
||||
"react-scrollbar-size": "2.1.0",
|
||||
"react-transition-group": "2.2.1",
|
||||
"recompose": "0.27.0",
|
||||
"scroll": "2.0.3",
|
||||
"warning": "3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"deepmerge": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.0.tgz",
|
||||
"integrity": "sha512-Q89Z26KAfA3lpPGhbF6XMfYAm3jIV3avViy6KOJ2JLzFbeWHOvPQUu5aSJIWXap3gDZC2y1eF5HXEPI2wGqgvw=="
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz",
|
||||
"integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w=="
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-2.0.2.tgz",
|
||||
"integrity": "sha512-BPksUj7VMAAFhcCw79sZA0Ow/LTAEjs3Sio1AQcuwLeOP+ua0f/08Su2wyiW+JjDDH6fRqNy3h5CLXh21u1mVg=="
|
||||
},
|
||||
"recompose": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/recompose/-/recompose-0.27.0.tgz",
|
||||
"integrity": "sha512-hivr1EopLhzjchhv2Y7VcLA2H5NGztwV/qfYqmIAhTkNowNQ9PyXdfq9Q8QCa0TMrPM1NtStlUyi5I/p8XfUNQ==",
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0",
|
||||
"change-emitter": "0.1.6",
|
||||
"fbjs": "0.8.16",
|
||||
"hoist-non-react-statics": "2.5.0",
|
||||
"react-lifecycles-compat": "3.0.3",
|
||||
"symbol-observable": "1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-lifecycles-compat": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.3.tgz",
|
||||
"integrity": "sha512-bOr65SSYgxDgDNqLnDqt+gropXGPNB1Wbyys4tOYiNuP/qYWC4qFM9XH1ruzq+tT6EjE29pJsCr19rclKtpUEg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"math-expression-evaluator": {
|
||||
"version": "1.2.17",
|
||||
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
|
||||
@ -18140,6 +18356,11 @@
|
||||
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
||||
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
|
||||
},
|
||||
"normalize-scroll-left": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/normalize-scroll-left/-/normalize-scroll-left-0.1.2.tgz",
|
||||
"integrity": "sha512-F9YMRls0zCF6BFIE2YnXDRpHPpfd91nOIaNdDgrx5YMoPLo8Wqj+6jNXHQsYBavJeXP4ww8HCt0xQAKc5qk2Fg=="
|
||||
},
|
||||
"normalize-selector": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
|
||||
@ -23395,6 +23616,14 @@
|
||||
"performance-now": "2.1.0"
|
||||
}
|
||||
},
|
||||
"rafl": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/rafl/-/rafl-1.2.2.tgz",
|
||||
"integrity": "sha1-/pMPdYIRAg1H44gV9Rlqi+QVB0A=",
|
||||
"requires": {
|
||||
"global": "4.3.2"
|
||||
}
|
||||
},
|
||||
"railroad-diagrams": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
|
||||
@ -23688,6 +23917,17 @@
|
||||
"integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw==",
|
||||
"dev": true
|
||||
},
|
||||
"react-event-listener": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.5.3.tgz",
|
||||
"integrity": "sha512-fTGYvhe7eTsqq0m664Km0rxKQcqLIGZWZINmy1LU0fu312tay8Mt3Twq2P5Xj1dfDVvvzT1Ql3/FDkiMPJ1MOg==",
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0",
|
||||
"fbjs": "0.8.16",
|
||||
"prop-types": "15.6.1",
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
"react-fuzzy": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/react-fuzzy/-/react-fuzzy-0.5.2.tgz",
|
||||
@ -23747,6 +23987,18 @@
|
||||
"is-dom": "1.0.9"
|
||||
}
|
||||
},
|
||||
"react-jss": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-jss/-/react-jss-8.4.0.tgz",
|
||||
"integrity": "sha512-yIi4udcTIIh5u4KJ47wsL3UZYMuSrp5xR1YBvPeRNshpCdRoJxt5BWmCu1RA3LIa+//dnRsAtAQmMAYeg1W9oQ==",
|
||||
"requires": {
|
||||
"hoist-non-react-statics": "2.3.1",
|
||||
"jss": "9.8.1",
|
||||
"jss-preset-default": "4.5.0",
|
||||
"prop-types": "15.6.1",
|
||||
"theming": "1.3.0"
|
||||
}
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.2.tgz",
|
||||
@ -23800,6 +24052,22 @@
|
||||
"integrity": "sha512-p84kBqGaMoa7VYT0vZ/aOYRfJB+gw34yjpda1Z5KeLflg70HipZOT+MXQenEhdkPAABuE2Astq4zEPdMqUQxcg==",
|
||||
"dev": true
|
||||
},
|
||||
"react-popper": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-0.10.4.tgz",
|
||||
"integrity": "sha1-rypBXqIike3VBGeNev2opu4ylao=",
|
||||
"requires": {
|
||||
"popper.js": "1.14.3",
|
||||
"prop-types": "15.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"popper.js": {
|
||||
"version": "1.14.3",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.3.tgz",
|
||||
"integrity": "sha1-FDj5jQRqz3tNeM1QK/QYrGTU8JU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.6.tgz",
|
||||
@ -23855,6 +24123,17 @@
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
"react-scrollbar-size": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-scrollbar-size/-/react-scrollbar-size-2.1.0.tgz",
|
||||
"integrity": "sha512-9dDUJvk7S48r0TRKjlKJ9e/LkLLYgc9LdQR6W21I8ZqtSrEsedPOoMji4nU3DHy7fx2l8YMScJS/N7qiloYzXQ==",
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0",
|
||||
"prop-types": "15.6.1",
|
||||
"react-event-listener": "0.5.3",
|
||||
"stifle": "1.0.4"
|
||||
}
|
||||
},
|
||||
"react-select": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-select/-/react-select-1.1.0.tgz",
|
||||
@ -25106,6 +25385,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"scroll": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/scroll/-/scroll-2.0.3.tgz",
|
||||
"integrity": "sha512-3ncZzf8gUW739h3LeS68nSssO60O+GGjT3SxzgofQmT8PIoyHzebql9HHPJopZX8iT6TKOdwaWFMqL6LzUN3DQ==",
|
||||
"requires": {
|
||||
"rafl": "1.2.2"
|
||||
}
|
||||
},
|
||||
"scrypt": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/scrypt/-/scrypt-6.0.3.tgz",
|
||||
@ -26522,6 +26809,11 @@
|
||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||
},
|
||||
"stifle": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/stifle/-/stifle-1.0.4.tgz",
|
||||
"integrity": "sha1-izvN9SQZsKnHnjWtrc5QEjwdjpk="
|
||||
},
|
||||
"stream-browserify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
|
||||
@ -27985,6 +28277,17 @@
|
||||
"integrity": "sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI=",
|
||||
"dev": true
|
||||
},
|
||||
"theming": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/theming/-/theming-1.3.0.tgz",
|
||||
"integrity": "sha512-ya5Ef7XDGbTPBv5ENTwrwkPUexrlPeiAg/EI9kdlUAZhNlRbCdhMKRgjNX1IcmsmiPcqDQZE6BpSaH+cr31FKw==",
|
||||
"requires": {
|
||||
"brcast": "3.0.1",
|
||||
"is-function": "1.0.1",
|
||||
"is-plain-object": "2.0.4",
|
||||
"prop-types": "15.6.1"
|
||||
}
|
||||
},
|
||||
"thenify": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz",
|
||||
|
@ -136,6 +136,7 @@
|
||||
"lodash.shuffle": "^4.2.0",
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
"loglevel": "^1.4.1",
|
||||
"material-ui": "1.0.0-beta.44",
|
||||
"metamascara": "^2.0.0",
|
||||
"metamask-logo": "^2.1.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
|
@ -1,5 +1,4 @@
|
||||
const PASSWORD = 'password123'
|
||||
const reactTriggerChange = require('react-trigger-change')
|
||||
const {
|
||||
timeout,
|
||||
findAsync,
|
||||
@ -11,6 +10,11 @@ async function runFirstTimeUsageTest (assert, done) {
|
||||
|
||||
const app = await queryAsync($, '#app-content')
|
||||
|
||||
// Used to set values on TextField input component
|
||||
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
|
||||
window.HTMLInputElement.prototype, 'value'
|
||||
).set
|
||||
|
||||
await skipNotices(app)
|
||||
|
||||
const welcomeButton = (await findAsync(app, '.welcome-screen__button'))[0]
|
||||
@ -21,12 +25,14 @@ async function runFirstTimeUsageTest (assert, done) {
|
||||
assert.equal(title, 'Create Password', 'create password screen')
|
||||
|
||||
// enter password
|
||||
const pwBox = (await findAsync(app, '.first-time-flow__input'))[0]
|
||||
const confBox = (await findAsync(app, '.first-time-flow__input'))[1]
|
||||
pwBox.value = PASSWORD
|
||||
confBox.value = PASSWORD
|
||||
reactTriggerChange(pwBox)
|
||||
reactTriggerChange(confBox)
|
||||
const pwBox = (await findAsync(app, '#create-password'))[0]
|
||||
const confBox = (await findAsync(app, '#confirm-password'))[0]
|
||||
|
||||
nativeInputValueSetter.call(pwBox, PASSWORD)
|
||||
pwBox.dispatchEvent(new Event('input', { bubbles: true}))
|
||||
|
||||
nativeInputValueSetter.call(confBox, PASSWORD)
|
||||
confBox.dispatchEvent(new Event('input', { bubbles: true}))
|
||||
|
||||
// Create Password
|
||||
const createButton = (await findAsync(app, 'button.first-time-flow__button'))[0]
|
||||
@ -71,10 +77,16 @@ async function runFirstTimeUsageTest (assert, done) {
|
||||
assert.ok(lock, 'Lock menu item found')
|
||||
lock.click()
|
||||
|
||||
const pwBox2 = (await findAsync(app, '#password-box'))[0]
|
||||
pwBox2.value = PASSWORD
|
||||
await timeout(1000)
|
||||
|
||||
const createButton2 = (await findAsync(app, 'button.primary'))[0]
|
||||
const pwBox2 = (await findAsync(app, '#password'))[0]
|
||||
pwBox2.focus()
|
||||
await timeout(1000)
|
||||
|
||||
nativeInputValueSetter.call(pwBox2, PASSWORD)
|
||||
pwBox2.dispatchEvent(new Event('input', { bubbles: true}))
|
||||
|
||||
const createButton2 = (await findAsync(app, 'button[type="submit"]'))[0]
|
||||
createButton2.click()
|
||||
|
||||
const detail2 = (await findAsync(app, '.wallet-view'))[0]
|
||||
|
@ -21,7 +21,7 @@ async function runTxListItemsTest(assert, done) {
|
||||
selectState.val('tx list items')
|
||||
reactTriggerChange(selectState[0])
|
||||
|
||||
const metamaskLogo = await queryAsync($, '.left-menu-wrapper')
|
||||
const metamaskLogo = await queryAsync($, '.app-header__logo-container')
|
||||
assert.ok(metamaskLogo[0], 'metamask logo present')
|
||||
metamaskLogo[0].click()
|
||||
|
||||
@ -46,7 +46,7 @@ async function runTxListItemsTest(assert, done) {
|
||||
const failedTx = txListItems[4]
|
||||
const failedTxRenderedStatus = await findAsync($(failedTx), '.tx-list-status')
|
||||
assert.equal(failedTxRenderedStatus[0].textContent, 'Failed', 'failedTx has correct label')
|
||||
|
||||
|
||||
const shapeShiftTx = txListItems[5]
|
||||
const shapeShiftTxStatus = await findAsync($(shapeShiftTx), '.flex-column div:eq(1)')
|
||||
assert.equal(shapeShiftTxStatus[0].textContent, 'No deposits received', 'shapeShiftTx has correct status')
|
||||
|
@ -74,8 +74,8 @@ async function captureAllScreens() {
|
||||
await driver.findElement(By.css('button')).click()
|
||||
await captureLanguageScreenShots('create password')
|
||||
|
||||
const passwordBox = await driver.findElement(By.css('input[type=password]:nth-of-type(1)'))
|
||||
const passwordBoxConfirm = await driver.findElement(By.css('input[type=password]:nth-of-type(2)'))
|
||||
const passwordBox = await driver.findElement(By.css('input#create-password'))
|
||||
const passwordBoxConfirm = await driver.findElement(By.css('input#confirm-password'))
|
||||
passwordBox.sendKeys('123456789')
|
||||
passwordBoxConfirm.sendKeys('123456789')
|
||||
await delay(500)
|
||||
|
@ -317,6 +317,7 @@ function tryUnlockMetamask (password) {
|
||||
background.verifySeedPhrase(err => {
|
||||
if (err) {
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
resolve()
|
||||
@ -330,6 +331,7 @@ function tryUnlockMetamask (password) {
|
||||
.catch(err => {
|
||||
dispatch(actions.unlockFailed(err.message))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
return Promise.reject(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
130
ui/app/app.js
130
ui/app/app.js
@ -1,7 +1,7 @@
|
||||
const { Component } = require('react')
|
||||
const PropTypes = require('prop-types')
|
||||
const connect = require('react-redux').connect
|
||||
const { Route, Switch, withRouter } = require('react-router-dom')
|
||||
const { Route, Switch, withRouter, matchPath } = require('react-router-dom')
|
||||
const { compose } = require('recompose')
|
||||
const h = require('react-hyperscript')
|
||||
const actions = require('./actions')
|
||||
@ -22,7 +22,7 @@ const Home = require('./components/pages/home')
|
||||
const Authenticated = require('./components/pages/authenticated')
|
||||
const Initialized = require('./components/pages/initialized')
|
||||
const Settings = require('./components/pages/settings')
|
||||
const UnlockPage = require('./components/pages/unlock')
|
||||
const UnlockPage = require('./components/pages/unlock-page')
|
||||
const RestoreVaultPage = require('./components/pages/keychains/restore-vault')
|
||||
const RevealSeedConfirmation = require('./components/pages/keychains/reveal-seed')
|
||||
const AddTokenPage = require('./components/pages/add-token')
|
||||
@ -30,8 +30,6 @@ const CreateAccountPage = require('./components/pages/create-account')
|
||||
const NoticeScreen = require('./components/pages/notice')
|
||||
|
||||
const Loading = require('./components/loading-screen')
|
||||
const NetworkIndicator = require('./components/network')
|
||||
const Identicon = require('./components/identicon')
|
||||
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
|
||||
const NetworkDropdown = require('./components/dropdowns/network-dropdown')
|
||||
const AccountMenu = require('./components/account-menu')
|
||||
@ -39,6 +37,8 @@ const AccountMenu = require('./components/account-menu')
|
||||
// Global Modals
|
||||
const Modal = require('./components/modals/index').Modal
|
||||
|
||||
const AppHeader = require('./components/app-header')
|
||||
|
||||
// Routes
|
||||
const {
|
||||
DEFAULT_ROUTE,
|
||||
@ -69,11 +69,11 @@ class App extends Component {
|
||||
return (
|
||||
h(Switch, [
|
||||
h(Route, { path: INITIALIZE_ROUTE, component: InitializeScreen }),
|
||||
h(Initialized, { path: REVEAL_SEED_ROUTE, exact, component: RevealSeedConfirmation }),
|
||||
h(Initialized, { path: UNLOCK_ROUTE, exact, component: UnlockPage }),
|
||||
h(Initialized, { path: SETTINGS_ROUTE, component: Settings }),
|
||||
h(Initialized, { path: RESTORE_VAULT_ROUTE, exact, component: RestoreVaultPage }),
|
||||
h(Initialized, { path: NOTICE_ROUTE, exact, component: NoticeScreen }),
|
||||
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, component: ConfirmTxScreen }),
|
||||
h(Authenticated, { path: SEND_ROUTE, exact, component: SendTransactionScreen2 }),
|
||||
h(Authenticated, { path: ADD_TOKEN_ROUTE, exact, component: AddTokenPage }),
|
||||
@ -83,6 +83,15 @@ class App extends Component {
|
||||
)
|
||||
}
|
||||
|
||||
renderAppHeader () {
|
||||
const { location } = this.props
|
||||
const isInitializing = matchPath(location.pathname, {
|
||||
path: INITIALIZE_ROUTE, exact: false,
|
||||
})
|
||||
|
||||
return isInitializing ? null : h(AppHeader)
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
isLoading,
|
||||
@ -119,8 +128,7 @@ class App extends Component {
|
||||
// global modal
|
||||
h(Modal, {}, []),
|
||||
|
||||
// app bar
|
||||
this.renderAppBar(),
|
||||
this.renderAppHeader(),
|
||||
|
||||
// sidebar
|
||||
this.renderSidebar(),
|
||||
@ -197,110 +205,6 @@ class App extends Component {
|
||||
])
|
||||
}
|
||||
|
||||
renderAppBar () {
|
||||
const {
|
||||
isUnlocked,
|
||||
network,
|
||||
provider,
|
||||
networkDropdownOpen,
|
||||
showNetworkDropdown,
|
||||
hideNetworkDropdown,
|
||||
isInitialized,
|
||||
welcomeScreenSeen,
|
||||
isPopup,
|
||||
betaUI,
|
||||
} = this.props
|
||||
|
||||
if (window.METAMASK_UI_TYPE === 'notification') {
|
||||
return null
|
||||
}
|
||||
|
||||
const props = this.props
|
||||
const {isMascara, isOnboarding} = props
|
||||
|
||||
// Do not render header if user is in mascara onboarding
|
||||
if (isMascara && isOnboarding) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Do not render header if user is in mascara buy ether
|
||||
if (isMascara && props.currentView.name === 'buyEth') {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
h('.full-width', {
|
||||
style: {},
|
||||
}, [
|
||||
|
||||
(isInitialized || welcomeScreenSeen || isPopup || !betaUI) && h('.app-header.flex-row.flex-space-between', {
|
||||
className: classnames({
|
||||
'app-header--initialized': !isOnboarding,
|
||||
}),
|
||||
}, [
|
||||
h('div.app-header-contents', {}, [
|
||||
h('div.left-menu-wrapper', {
|
||||
onClick: () => props.history.push(DEFAULT_ROUTE),
|
||||
}, [
|
||||
// mini logo
|
||||
h('img.metafox-icon', {
|
||||
height: 42,
|
||||
width: 42,
|
||||
src: '/images/metamask-fox.svg',
|
||||
}),
|
||||
|
||||
// metamask name
|
||||
h('.flex-row', [
|
||||
h('h1', this.context.t('appName')),
|
||||
h('div.beta-label', this.context.t('beta')),
|
||||
]),
|
||||
|
||||
]),
|
||||
|
||||
betaUI && isInitialized && h('div.header__right-actions', [
|
||||
h('div.network-component-wrapper', {
|
||||
style: {},
|
||||
}, [
|
||||
// Network Indicator
|
||||
h(NetworkIndicator, {
|
||||
network,
|
||||
provider,
|
||||
disabled: this.props.location.pathname === CONFIRM_TRANSACTION_ROUTE,
|
||||
onClick: (event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return networkDropdownOpen === false
|
||||
? showNetworkDropdown()
|
||||
: hideNetworkDropdown()
|
||||
},
|
||||
}),
|
||||
|
||||
]),
|
||||
|
||||
isUnlocked && h('div.account-menu__icon', { onClick: this.props.toggleAccountMenu }, [
|
||||
h(Identicon, {
|
||||
address: this.props.selectedAddress,
|
||||
diameter: 32,
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
|
||||
!isInitialized && !isPopup && betaUI && h('.alpha-warning__container', {}, [
|
||||
h('h2', {
|
||||
className: classnames({
|
||||
'alpha-warning': welcomeScreenSeen,
|
||||
'alpha-warning-welcome-screen': !welcomeScreenSeen,
|
||||
}),
|
||||
}, 'Please be aware that this version is still under development'),
|
||||
]),
|
||||
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
toggleMetamaskActive () {
|
||||
if (!this.props.isUnlocked) {
|
||||
// currently inactive: redirect to password box
|
||||
|
106
ui/app/components/app-header/app-header.component.js
Normal file
106
ui/app/components/app-header/app-header.component.js
Normal file
@ -0,0 +1,106 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
|
||||
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../../../app/scripts/lib/enums')
|
||||
const { DEFAULT_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes')
|
||||
const Identicon = require('../identicon')
|
||||
const NetworkIndicator = require('../network')
|
||||
|
||||
class AppHeader extends Component {
|
||||
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()
|
||||
}
|
||||
|
||||
renderAccountMenu () {
|
||||
const { isUnlocked, toggleAccountMenu, selectedAddress } = this.props
|
||||
|
||||
return isUnlocked && (
|
||||
<div
|
||||
className="account-menu__icon"
|
||||
onClick={toggleAccountMenu}
|
||||
>
|
||||
<Identicon
|
||||
address={selectedAddress}
|
||||
diameter={32}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
network,
|
||||
provider,
|
||||
history,
|
||||
location,
|
||||
isUnlocked,
|
||||
} = this.props
|
||||
|
||||
if (window.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION) {
|
||||
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"
|
||||
src="/images/metamask-fox.svg"
|
||||
height={42}
|
||||
width={42}
|
||||
/>
|
||||
<div className="flex-row">
|
||||
<h1>{ this.context.t('appName') }</h1>
|
||||
<div className="app-header__beta-label">
|
||||
{ this.context.t('beta') }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="app-header__account-menu-container">
|
||||
<div className="network-component-wrapper">
|
||||
<NetworkIndicator
|
||||
network={network}
|
||||
provider={provider}
|
||||
onClick={event => this.handleNetworkIndicatorClick(event)}
|
||||
disabled={location.pathname === CONFIRM_TRANSACTION_ROUTE}
|
||||
/>
|
||||
</div>
|
||||
{ this.renderAccountMenu() }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default AppHeader
|
38
ui/app/components/app-header/app-header.container.js
Normal file
38
ui/app/components/app-header/app-header.container.js
Normal file
@ -0,0 +1,38 @@
|
||||
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)
|
2
ui/app/components/app-header/index.js
Normal file
2
ui/app/components/app-header/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import AppHeader from './app-header.container'
|
||||
module.exports = AppHeader
|
@ -37,7 +37,7 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
color: $curious-blue;
|
||||
|
||||
|
2
ui/app/components/pages/unlock-page/index.js
Normal file
2
ui/app/components/pages/unlock-page/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import UnlockPage from './unlock-page.container'
|
||||
module.exports = UnlockPage
|
181
ui/app/components/pages/unlock-page/unlock-page.component.js
Normal file
181
ui/app/components/pages/unlock-page/unlock-page.component.js
Normal file
@ -0,0 +1,181 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Button from 'material-ui/Button'
|
||||
import TextField from '../../text-field'
|
||||
|
||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../../../../app/scripts/lib/enums')
|
||||
const { getEnvironmentType } = require('../../../../../app/scripts/lib/util')
|
||||
const getCaretCoordinates = require('textarea-caret')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const Mascot = require('../../mascot')
|
||||
const { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } = require('../../../routes')
|
||||
|
||||
class UnlockPage extends Component {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
password: '',
|
||||
error: null,
|
||||
}
|
||||
|
||||
this.animationEventEmitter = new EventEmitter()
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
const { isUnlocked, history } = this.props
|
||||
|
||||
if (isUnlocked) {
|
||||
history.push(DEFAULT_ROUTE)
|
||||
}
|
||||
}
|
||||
|
||||
tryUnlockMetamask (password) {
|
||||
const { tryUnlockMetamask, history } = this.props
|
||||
tryUnlockMetamask(password)
|
||||
.then(() => history.push(DEFAULT_ROUTE))
|
||||
.catch(({ message }) => this.setState({ error: message }))
|
||||
}
|
||||
|
||||
handleSubmit (event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
const { password } = this.state
|
||||
const { tryUnlockMetamask, history } = this.props
|
||||
|
||||
if (password === '') {
|
||||
return
|
||||
}
|
||||
|
||||
this.setState({ error: null })
|
||||
|
||||
tryUnlockMetamask(password)
|
||||
.then(() => history.push(DEFAULT_ROUTE))
|
||||
.catch(({ message }) => this.setState({ error: message }))
|
||||
}
|
||||
|
||||
handleInputChange ({ target }) {
|
||||
this.setState({ password: target.value, error: null })
|
||||
|
||||
// tell mascot to look at page action
|
||||
const element = target
|
||||
const boundingRect = element.getBoundingClientRect()
|
||||
const coordinates = getCaretCoordinates(element, element.selectionEnd)
|
||||
this.animationEventEmitter.emit('point', {
|
||||
x: boundingRect.left + coordinates.left - element.scrollLeft,
|
||||
y: boundingRect.top + coordinates.top - element.scrollTop,
|
||||
})
|
||||
}
|
||||
|
||||
renderSubmitButton () {
|
||||
const style = {
|
||||
backgroundColor: '#f7861c',
|
||||
color: 'white',
|
||||
marginTop: '20px',
|
||||
height: '60px',
|
||||
fontWeight: '400',
|
||||
boxShadow: 'none',
|
||||
borderRadius: '4px',
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
type="submit"
|
||||
style={style}
|
||||
disabled={!this.state.password}
|
||||
fullWidth
|
||||
variant="raised"
|
||||
size="large"
|
||||
onClick={event => this.handleSubmit(event)}
|
||||
disableRipple
|
||||
>
|
||||
{ this.context.t('login') }
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { error } = this.state
|
||||
|
||||
return (
|
||||
<div className="unlock-page__container">
|
||||
<div className="unlock-page">
|
||||
<div className="unlock-page__mascot-container">
|
||||
<Mascot
|
||||
animationEventEmitter={this.animationEventEmitter}
|
||||
width="120"
|
||||
height="120"
|
||||
/>
|
||||
</div>
|
||||
<h1 className="unlock-page__title">
|
||||
{ this.context.t('welcomeBack') }
|
||||
</h1>
|
||||
<div>{ this.context.t('unlockMessage') }</div>
|
||||
<form
|
||||
className="unlock-page__form"
|
||||
onSubmit={event => this.handleSubmit(event)}
|
||||
>
|
||||
<TextField
|
||||
id="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
value={this.state.password}
|
||||
onChange={event => this.handleInputChange(event)}
|
||||
error={error}
|
||||
autoFocus
|
||||
autoComplete="current-password"
|
||||
fullWidth
|
||||
/>
|
||||
</form>
|
||||
{ this.renderSubmitButton() }
|
||||
<div className="unlock-page__links">
|
||||
<div
|
||||
className="unlock-page__link"
|
||||
onClick={() => {
|
||||
this.props.markPasswordForgotten()
|
||||
this.props.history.push(RESTORE_VAULT_ROUTE)
|
||||
|
||||
if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) {
|
||||
global.platform.openExtensionInBrowser()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{ this.context.t('restoreFromSeed') }
|
||||
</div>
|
||||
<div
|
||||
className="unlock-page__link unlock-page__link--import"
|
||||
onClick={() => {
|
||||
this.props.markPasswordForgotten()
|
||||
this.props.history.push(RESTORE_VAULT_ROUTE)
|
||||
|
||||
if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) {
|
||||
global.platform.openExtensionInBrowser()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{ this.context.t('importUsingSeed') }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
UnlockPage.propTypes = {
|
||||
forgotPassword: PropTypes.func,
|
||||
tryUnlockMetamask: PropTypes.func,
|
||||
markPasswordForgotten: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
isUnlocked: PropTypes.bool,
|
||||
t: PropTypes.func,
|
||||
useOldInterface: PropTypes.func,
|
||||
setNetworkEndpoints: PropTypes.func,
|
||||
}
|
||||
|
||||
export default UnlockPage
|
33
ui/app/components/pages/unlock-page/unlock-page.container.js
Normal file
33
ui/app/components/pages/unlock-page/unlock-page.container.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { connect } from 'react-redux'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { compose } from 'recompose'
|
||||
|
||||
const {
|
||||
tryUnlockMetamask,
|
||||
forgotPassword,
|
||||
markPasswordForgotten,
|
||||
setNetworkEndpoints,
|
||||
} = require('../../../actions')
|
||||
|
||||
import UnlockPage from './unlock-page.component'
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { metamask: { isUnlocked } } = state
|
||||
return {
|
||||
isUnlocked,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
forgotPassword: () => dispatch(forgotPassword()),
|
||||
tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)),
|
||||
markPasswordForgotten: () => dispatch(markPasswordForgotten()),
|
||||
setNetworkEndpoints: type => dispatch(setNetworkEndpoints(type)),
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
connect(mapStateToProps, mapDispatchToProps)
|
||||
)(UnlockPage)
|
51
ui/app/components/pages/unlock-page/unlock-page.scss
Normal file
51
ui/app/components/pages/unlock-page/unlock-page.scss
Normal file
@ -0,0 +1,51 @@
|
||||
.unlock-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 357px;
|
||||
padding: 30px;
|
||||
font-weight: 400;
|
||||
color: $silver-chalice;
|
||||
|
||||
&__container {
|
||||
background: $white;
|
||||
display: flex;
|
||||
align-self: stretch;
|
||||
justify-content: center;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
&__mascot-container {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin-top: 5px;
|
||||
font-size: 2rem;
|
||||
font-weight: 800;
|
||||
color: $tundora;
|
||||
}
|
||||
|
||||
&__form {
|
||||
width: 100%;
|
||||
margin: 56px 0 8px;
|
||||
}
|
||||
|
||||
&__links {
|
||||
margin-top: 25px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__link {
|
||||
cursor: pointer;
|
||||
|
||||
&--import {
|
||||
color: $ecstasy;
|
||||
}
|
||||
|
||||
&--use-classic {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
const { Component } = require('react')
|
||||
const PropTypes = require('prop-types')
|
||||
const connect = require('../../metamask-connect')
|
||||
const h = require('react-hyperscript')
|
||||
const { withRouter } = require('react-router-dom')
|
||||
const { compose } = require('recompose')
|
||||
const {
|
||||
tryUnlockMetamask,
|
||||
forgotPassword,
|
||||
markPasswordForgotten,
|
||||
setNetworkEndpoints,
|
||||
setFeatureFlag,
|
||||
} = require('../../actions')
|
||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums')
|
||||
const { getEnvironmentType } = require('../../../../app/scripts/lib/util')
|
||||
const getCaretCoordinates = require('textarea-caret')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const Mascot = require('../mascot')
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../../app/scripts/controllers/network/enums')
|
||||
const { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } = require('../../routes')
|
||||
|
||||
class UnlockScreen extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
error: null,
|
||||
}
|
||||
|
||||
this.animationEventEmitter = new EventEmitter()
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
const { isUnlocked, history } = this.props
|
||||
|
||||
if (isUnlocked) {
|
||||
history.push(DEFAULT_ROUTE)
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const passwordBox = document.getElementById('password-box')
|
||||
|
||||
if (passwordBox) {
|
||||
passwordBox.focus()
|
||||
}
|
||||
}
|
||||
|
||||
tryUnlockMetamask (password) {
|
||||
const { tryUnlockMetamask, history } = this.props
|
||||
tryUnlockMetamask(password)
|
||||
.then(() => history.push(DEFAULT_ROUTE))
|
||||
.catch(({ message }) => this.setState({ error: message }))
|
||||
}
|
||||
|
||||
onSubmit (event) {
|
||||
const input = document.getElementById('password-box')
|
||||
const password = input.value
|
||||
this.tryUnlockMetamask(password)
|
||||
}
|
||||
|
||||
onKeyPress (event) {
|
||||
if (event.key === 'Enter') {
|
||||
this.submitPassword(event)
|
||||
}
|
||||
}
|
||||
|
||||
submitPassword (event) {
|
||||
var element = event.target
|
||||
var password = element.value
|
||||
// reset input
|
||||
element.value = ''
|
||||
this.tryUnlockMetamask(password)
|
||||
}
|
||||
|
||||
inputChanged (event) {
|
||||
// tell mascot to look at page action
|
||||
var element = event.target
|
||||
var boundingRect = element.getBoundingClientRect()
|
||||
var coordinates = getCaretCoordinates(element, element.selectionEnd)
|
||||
this.animationEventEmitter.emit('point', {
|
||||
x: boundingRect.left + coordinates.left - element.scrollLeft,
|
||||
y: boundingRect.top + coordinates.top - element.scrollTop,
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const { error } = this.state
|
||||
return (
|
||||
h('.unlock-screen', [
|
||||
|
||||
h(Mascot, {
|
||||
animationEventEmitter: this.animationEventEmitter,
|
||||
}),
|
||||
|
||||
h('h1', {
|
||||
style: {
|
||||
fontSize: '1.4em',
|
||||
textTransform: 'uppercase',
|
||||
color: '#7F8082',
|
||||
},
|
||||
}, this.props.t('appName')),
|
||||
|
||||
h('input.large-input', {
|
||||
type: 'password',
|
||||
id: 'password-box',
|
||||
placeholder: 'enter password',
|
||||
style: {
|
||||
background: 'white',
|
||||
},
|
||||
onKeyPress: this.onKeyPress.bind(this),
|
||||
onInput: this.inputChanged.bind(this),
|
||||
}),
|
||||
|
||||
h('.error', {
|
||||
style: {
|
||||
display: error ? 'block' : 'none',
|
||||
padding: '0 20px',
|
||||
textAlign: 'center',
|
||||
},
|
||||
}, error),
|
||||
|
||||
h('button.primary.cursor-pointer', {
|
||||
onClick: this.onSubmit.bind(this),
|
||||
style: {
|
||||
margin: 10,
|
||||
},
|
||||
}, this.props.t('login')),
|
||||
|
||||
h('p.pointer', {
|
||||
onClick: () => {
|
||||
this.props.markPasswordForgotten()
|
||||
this.props.history.push(RESTORE_VAULT_ROUTE)
|
||||
|
||||
if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) {
|
||||
global.platform.openExtensionInBrowser()
|
||||
}
|
||||
},
|
||||
style: {
|
||||
fontSize: '0.8em',
|
||||
color: 'rgb(247, 134, 28)',
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
}, this.props.t('restoreFromSeed')),
|
||||
|
||||
h('p.pointer', {
|
||||
onClick: () => {
|
||||
this.props.useOldInterface()
|
||||
.then(() => this.props.setNetworkEndpoints(OLD_UI_NETWORK_TYPE))
|
||||
},
|
||||
style: {
|
||||
fontSize: '0.8em',
|
||||
color: '#aeaeae',
|
||||
textDecoration: 'underline',
|
||||
marginTop: '32px',
|
||||
},
|
||||
}, this.props.t('classicInterface')),
|
||||
])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
UnlockScreen.propTypes = {
|
||||
forgotPassword: PropTypes.func,
|
||||
tryUnlockMetamask: PropTypes.func,
|
||||
markPasswordForgotten: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
isUnlocked: PropTypes.bool,
|
||||
t: PropTypes.func,
|
||||
useOldInterface: PropTypes.func,
|
||||
setNetworkEndpoints: PropTypes.func,
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { metamask: { isUnlocked } } = state
|
||||
return {
|
||||
isUnlocked,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
forgotPassword: () => dispatch(forgotPassword()),
|
||||
tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)),
|
||||
markPasswordForgotten: () => dispatch(markPasswordForgotten()),
|
||||
useOldInterface: () => dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')),
|
||||
setNetworkEndpoints: type => dispatch(setNetworkEndpoints(type)),
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = compose(
|
||||
withRouter,
|
||||
connect(mapStateToProps, mapDispatchToProps)
|
||||
)(UnlockScreen)
|
2
ui/app/components/text-field/index.js
Normal file
2
ui/app/components/text-field/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import TextField from './text-field.component'
|
||||
module.exports = TextField
|
59
ui/app/components/text-field/text-field.component.js
Normal file
59
ui/app/components/text-field/text-field.component.js
Normal file
@ -0,0 +1,59 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withStyles } from 'material-ui/styles'
|
||||
import { default as MaterialTextField } from 'material-ui/TextField'
|
||||
|
||||
const styles = {
|
||||
cssLabel: {
|
||||
'&$cssFocused': {
|
||||
color: '#aeaeae',
|
||||
},
|
||||
'&$cssError': {
|
||||
color: '#aeaeae',
|
||||
},
|
||||
fontWeight: '400',
|
||||
color: '#aeaeae',
|
||||
},
|
||||
cssFocused: {},
|
||||
cssUnderline: {
|
||||
'&:after': {
|
||||
backgroundColor: '#f7861c',
|
||||
},
|
||||
},
|
||||
cssError: {},
|
||||
}
|
||||
|
||||
const TextField = props => {
|
||||
const { error, classes, ...textFieldProps } = props
|
||||
|
||||
return (
|
||||
<MaterialTextField
|
||||
error={Boolean(error)}
|
||||
helperText={error}
|
||||
InputLabelProps={{
|
||||
FormLabelClasses: {
|
||||
root: classes.cssLabel,
|
||||
focused: classes.cssFocused,
|
||||
error: classes.cssError,
|
||||
},
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
underline: classes.cssUnderline,
|
||||
},
|
||||
}}
|
||||
{...textFieldProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
TextField.defaultProps = {
|
||||
error: null,
|
||||
}
|
||||
|
||||
TextField.propTypes = {
|
||||
error: PropTypes.string,
|
||||
classes: PropTypes.object,
|
||||
}
|
||||
|
||||
export default withStyles(styles)(TextField)
|
24
ui/app/components/text-field/text-field.stories.js
Normal file
24
ui/app/components/text-field/text-field.stories.js
Normal file
@ -0,0 +1,24 @@
|
||||
import React from 'react'
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import TextField from './'
|
||||
|
||||
storiesOf('TextField', module)
|
||||
.add('text', () =>
|
||||
<TextField
|
||||
label="Text"
|
||||
type="text"
|
||||
/>
|
||||
)
|
||||
.add('password', () =>
|
||||
<TextField
|
||||
label="Password"
|
||||
type="password"
|
||||
/>
|
||||
)
|
||||
.add('error', () =>
|
||||
<TextField
|
||||
type="text"
|
||||
label="Name"
|
||||
error="Invalid value"
|
||||
/>
|
||||
)
|
@ -102,6 +102,7 @@ WalletView.prototype.render = function () {
|
||||
selectedIdentity,
|
||||
keyrings,
|
||||
showAccountDetailModal,
|
||||
sidebarOpen,
|
||||
hideSidebar,
|
||||
history,
|
||||
} = this.props
|
||||
@ -182,7 +183,10 @@ WalletView.prototype.render = function () {
|
||||
h(TokenList),
|
||||
|
||||
h('button.btn-primary.wallet-view__add-token-button', {
|
||||
onClick: () => history.push(ADD_TOKEN_ROUTE),
|
||||
onClick: () => {
|
||||
history.push(ADD_TOKEN_ROUTE)
|
||||
sidebarOpen && hideSidebar()
|
||||
},
|
||||
}, this.context.t('addToken')),
|
||||
])
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
.app-header {
|
||||
align-items: center;
|
||||
visibility: visible;
|
||||
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;
|
||||
width: 100%;
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, .08);
|
||||
z-index: $mobile-header-z-index;
|
||||
}
|
||||
@ -17,48 +17,75 @@
|
||||
@media screen and (min-width: 576px) {
|
||||
height: 75px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.metafox-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.app-header--initialized {
|
||||
|
||||
@media screen and (min-width: 576px) {
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
background: $gallery;
|
||||
bottom: -32px;
|
||||
&--back-drop {
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
background: $gallery;
|
||||
bottom: -32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app-header-contents {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-flow: row nowrap;
|
||||
width: 100%;
|
||||
height: 6.9vh;
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
height: 100%;
|
||||
&__metafox {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 576px) {
|
||||
width: 85vw;
|
||||
&__beta-label {
|
||||
font-family: Roboto;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
font-size: .8rem;
|
||||
color: $buttercup;
|
||||
margin-left: 5px;
|
||||
line-height: initial;
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
width: 80vw;
|
||||
&__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;
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
.identicon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,20 +103,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.beta-label {
|
||||
font-family: Roboto;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
font-size: .8rem;
|
||||
color: $buttercup;
|
||||
margin-left: 5px;
|
||||
line-height: initial;
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
h2.page-subtitle {
|
||||
text-transform: uppercase;
|
||||
color: #aeaeae;
|
||||
@ -102,20 +115,3 @@ h2.page-subtitle {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.left-menu-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.header__right-actions {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
|
||||
.identicon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
@import './unlock.scss';
|
||||
|
||||
@import './reveal-seed.scss';
|
||||
|
||||
@import '../../../../components/pages/unlock-page/unlock-page.scss';
|
||||
|
@ -1,9 +0,0 @@
|
||||
.unlock-page {
|
||||
box-shadow: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgb(247, 247, 247);
|
||||
width: 100%;
|
||||
}
|
@ -95,19 +95,6 @@ textarea.twelve-word-phrase {
|
||||
margin: -2px 8px 0px -8px;
|
||||
}
|
||||
|
||||
.unlock-screen #metamask-mascot-container {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.unlock-screen h1 {
|
||||
margin-top: -28px;
|
||||
margin-bottom: 42px;
|
||||
}
|
||||
|
||||
.unlock-screen input[type=password] {
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
.sizing-input {
|
||||
font-size: 14px;
|
||||
height: 30px;
|
||||
@ -118,34 +105,6 @@ textarea.twelve-word-phrase {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Webkit */
|
||||
|
||||
.unlock-screen input::-webkit-input-placeholder {
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
/* Firefox 18- */
|
||||
|
||||
.unlock-screen input:-moz-placeholder {
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
/* Firefox 19+ */
|
||||
|
||||
.unlock-screen input::-moz-placeholder {
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
/* IE */
|
||||
|
||||
.unlock-screen input:-ms-input-placeholder {
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
/* accounts */
|
||||
|
||||
.accounts-section {
|
||||
|
@ -3,8 +3,6 @@
|
||||
background: $white;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
height: auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.settings__header {
|
||||
@ -29,6 +27,8 @@
|
||||
|
||||
.settings__content {
|
||||
padding: 0 25px;
|
||||
height: auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.settings__content-row {
|
||||
|
@ -1,59 +1,60 @@
|
||||
.welcome-screen {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: Roboto;
|
||||
font-weight: 400;
|
||||
width: 100%;
|
||||
flex: 1 0 auto;
|
||||
padding: 70px 0;
|
||||
background: $white;
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: Roboto;
|
||||
font-weight: 400;
|
||||
width: 100%;
|
||||
flex: 1 0 auto;
|
||||
padding: 70px 0;
|
||||
background: $white;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
padding: 0;
|
||||
&__header {
|
||||
font-size: 1.65em;
|
||||
margin-bottom: 14px;
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
|
||||
&__header {
|
||||
font-size: 1.65em;
|
||||
margin-bottom: 14px;
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
&__copy {
|
||||
font-size: 1em;
|
||||
width: 400px;
|
||||
max-width: 90vw;
|
||||
text-align: center;
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
height: 54px;
|
||||
width: 198px;
|
||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.14);
|
||||
color: #FFFFFF;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 26px;
|
||||
&__copy {
|
||||
font-size: 1em;
|
||||
width: 400px;
|
||||
max-width: 90vw;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
margin: 35px 0 14px;
|
||||
transition: 200ms ease-in-out;
|
||||
background-color: rgba(247, 134, 28, 0.9);
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
font-size: .9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
height: 54px;
|
||||
width: 198px;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .14);
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
margin: 35px 0 14px;
|
||||
transition: 200ms ease-in-out;
|
||||
background-color: rgba(247, 134, 28, .9);
|
||||
}
|
||||
}
|
||||
|
@ -205,10 +205,8 @@ input.large-input {
|
||||
}
|
||||
|
||||
&__content {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
min-height: 250px;
|
||||
max-height: 400px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__warning-container {
|
||||
@ -256,6 +254,7 @@ input.large-input {
|
||||
overflow-y: auto;
|
||||
background-color: $white;
|
||||
border-radius: 0;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const AccountAndTransactionDetails = require('./account-and-transaction-details')
|
||||
const Settings = require('./components/pages/settings')
|
||||
const UnlockScreen = require('./components/pages/unlock')
|
||||
const UnlockScreen = require('./components/pages/unlock-page')
|
||||
const log = require('loglevel')
|
||||
|
||||
module.exports = MainContainer
|
||||
|
141
ui/app/unlock.js
141
ui/app/unlock.js
@ -1,141 +0,0 @@
|
||||
const inherits = require('util').inherits
|
||||
const Component = require('react').Component
|
||||
const PropTypes = require('prop-types')
|
||||
const h = require('react-hyperscript')
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('./actions')
|
||||
const getCaretCoordinates = require('textarea-caret')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/controllers/network/enums')
|
||||
const { getEnvironmentType } = require('../../app/scripts/lib/util')
|
||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../app/scripts/lib/enums')
|
||||
|
||||
const Mascot = require('./components/mascot')
|
||||
|
||||
UnlockScreen.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps)(UnlockScreen)
|
||||
|
||||
|
||||
inherits(UnlockScreen, Component)
|
||||
function UnlockScreen () {
|
||||
Component.call(this)
|
||||
this.animationEventEmitter = new EventEmitter()
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
warning: state.appState.warning,
|
||||
}
|
||||
}
|
||||
|
||||
UnlockScreen.prototype.render = function () {
|
||||
const state = this.props
|
||||
const warning = state.warning
|
||||
return (
|
||||
h('.unlock-screen', [
|
||||
|
||||
h(Mascot, {
|
||||
animationEventEmitter: this.animationEventEmitter,
|
||||
}),
|
||||
|
||||
h('h1', {
|
||||
style: {
|
||||
fontSize: '1.4em',
|
||||
textTransform: 'uppercase',
|
||||
color: '#7F8082',
|
||||
},
|
||||
}, this.context.t('appName')),
|
||||
|
||||
h('input.large-input', {
|
||||
type: 'password',
|
||||
id: 'password-box',
|
||||
placeholder: 'enter password',
|
||||
style: {
|
||||
background: 'white',
|
||||
},
|
||||
onKeyPress: this.onKeyPress.bind(this),
|
||||
onInput: this.inputChanged.bind(this),
|
||||
}),
|
||||
|
||||
h('.error', {
|
||||
style: {
|
||||
display: warning ? 'block' : 'none',
|
||||
padding: '0 20px',
|
||||
textAlign: 'center',
|
||||
},
|
||||
}, warning),
|
||||
|
||||
h('button.primary.cursor-pointer', {
|
||||
onClick: this.onSubmit.bind(this),
|
||||
style: {
|
||||
margin: 10,
|
||||
},
|
||||
}, this.context.t('login')),
|
||||
|
||||
h('p.pointer', {
|
||||
onClick: () => {
|
||||
this.props.dispatch(actions.markPasswordForgotten())
|
||||
if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) {
|
||||
global.platform.openExtensionInBrowser()
|
||||
}
|
||||
},
|
||||
style: {
|
||||
fontSize: '0.8em',
|
||||
color: 'rgb(247, 134, 28)',
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
}, this.context.t('restoreFromSeed')),
|
||||
|
||||
h('p.pointer', {
|
||||
onClick: () => {
|
||||
this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
|
||||
.then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
|
||||
},
|
||||
style: {
|
||||
fontSize: '0.8em',
|
||||
color: '#aeaeae',
|
||||
textDecoration: 'underline',
|
||||
marginTop: '32px',
|
||||
},
|
||||
}, this.context.t('classicInterface')),
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
UnlockScreen.prototype.componentDidMount = function () {
|
||||
document.getElementById('password-box').focus()
|
||||
}
|
||||
|
||||
UnlockScreen.prototype.onSubmit = function (event) {
|
||||
const input = document.getElementById('password-box')
|
||||
const password = input.value
|
||||
this.props.dispatch(actions.tryUnlockMetamask(password))
|
||||
}
|
||||
|
||||
UnlockScreen.prototype.onKeyPress = function (event) {
|
||||
if (event.key === 'Enter') {
|
||||
this.submitPassword(event)
|
||||
}
|
||||
}
|
||||
|
||||
UnlockScreen.prototype.submitPassword = function (event) {
|
||||
var element = event.target
|
||||
var password = element.value
|
||||
// reset input
|
||||
element.value = ''
|
||||
this.props.dispatch(actions.tryUnlockMetamask(password))
|
||||
}
|
||||
|
||||
UnlockScreen.prototype.inputChanged = function (event) {
|
||||
// tell mascot to look at page action
|
||||
var element = event.target
|
||||
var boundingRect = element.getBoundingClientRect()
|
||||
var coordinates = getCaretCoordinates(element, element.selectionEnd)
|
||||
this.animationEventEmitter.emit('point', {
|
||||
x: boundingRect.left + coordinates.left - element.scrollLeft,
|
||||
y: boundingRect.top + coordinates.top - element.scrollTop,
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user