clientApi,
})
+create.submitForm = (data) => function (dispatch) {
+ if (typeof data.alias == 'string') data.alias = data.alias.trim()
+
+ return clientApi().create(data)
+ .then((resp) => {
+ if (resp.status === 'fail') {
+ throw resp
+ }
+
+ dispatch({type: 'NEW_KEY', data: resp.data.mnemonic})
+ dispatch( push('/keys/mnemonic') )
+ })
+}
+
const resetPassword = {
submitResetForm: (params) => {
let promise = Promise.resolve()
})
}
+const createSuccess = ()=> (dispatch) =>{
+ dispatch(create.created())
+ dispatch(push('/keys'))
+}
+
export default {
...create,
...list,
...resetPassword,
checkPassword,
- createExport
+ createExport,
+ createSuccess
}
--- /dev/null
+import React from 'react'
+import {connect} from 'react-redux'
+import actions from 'actions'
+import { NotFound, Step, StepList, ConfirmMnemonic, Mnemonic, PageContent, PageTitle } from 'features/shared/components'
+import {Skip} from '../'
+import styles from './MnemonicStepper.scss'
+
+class MnemonicStepper extends React.Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ if (this.props.mnemonic.length === 0) {
+ return <NotFound />
+ }
+
+ return (
+ <div>
+ <PageTitle title={'Mnemonic'} />
+
+ <PageContent>
+ <div className={styles.main}>
+ <StepList>
+ <Step>
+ <Skip/>
+ <button className={`btn btn-primary ${styles.marginRight}`}
+ onClick={() => this.props.succeeded()}
+ >
+ skip
+ </button>
+ </Step>
+ <Step>
+ <Mnemonic
+ mnemonic={this.props.mnemonic}
+ />
+ </Step>
+
+ <Step>
+ <ConfirmMnemonic
+ mnemonic={this.props.mnemonic}
+ succeeded={this.props.succeeded}
+ />
+
+ </Step>
+ </StepList>
+ </div>
+ </PageContent>
+ </div>
+ )
+ }
+}
+
+const mapStateToProps = (state) => {
+ const mnemonic = (state.key || {}).mnemonic || []
+ if (mnemonic) return {mnemonic}
+ return {}
+}
+
+const mapDispatchToProps = ( dispatch ) => ({
+ succeeded: () => dispatch(actions.key.createSuccess()),
+})
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(MnemonicStepper)
--- /dev/null
+.main{
+ background-color: $background-color;
+ border: 1px solid $border-color;
+ padding: $gutter-size;
+ word-wrap: break-word;
+}
+
+.marginRight{
+ margin-right: $gutter-size/2;
+}
\ No newline at end of file
--- /dev/null
+import React from 'react'
+
+class Skip extends React.Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ return (
+ <div>
+ <h2>Continue with Mnemonic</h2>
+ <p>Mnemonic can be used to restore the relevant key information. You can either skip the Mnemonic step or keep it.</p>
+ </div>
+ )
+ }
+}
+
+export default Skip
import List from './List'
import New from './New'
+import MnemonicStepper from './MnemonicStepper/MnemonicStepper'
import Show from './Show'
import ResetPassword from './ResetPassword/ResetPassword'
import CheckPassword from './CheckPassword/CheckPassword'
+import Skip from './Skip/Skip'
export {
List,
New,
+ MnemonicStepper,
Show,
ResetPassword,
- CheckPassword
+ CheckPassword,
+ Skip
}
}
return state
},
+ mnemonic: (state = [], action) => {
+ if (action.type == 'NEW_KEY') {
+ return action.data
+ }
+ return state
+ },
})
-import { List, New, Show, ResetPassword, CheckPassword } from './components'
+import { List, New, Show, ResetPassword, CheckPassword, MnemonicStepper } from './components'
import { makeRoutes } from 'features/shared'
export default (store) => makeRoutes(store, 'key', List, New, Show,
path: ':id/check-password',
component: CheckPassword,
},
+ {
+ path: 'mnemonic',
+ component: MnemonicStepper
+ }
],skipFilter: true, name: 'key' })
\ No newline at end of file
import React from 'react'
import { ErrorBanner, SingletonField} from 'features/shared/components'
import {reduxForm} from 'redux-form'
+import style from './ConfirmMnemonic.scss'
class ConfirmMnemonic extends React.Component {
constructor(props) {
<form onSubmit={handleSubmit(this.submitWithValidation)}>
<h2>Enter your wallet recover phrase</h2>
<p>Confirm that you backup your Recovery phrase by filling in the missing words:</p>
- {seedWords.map((seedWord) => {
- return ( seedWord.show ?
- <div key={seedWord.index} className='seedWord'>{seedWord.word}</div> :
- (words[counter]? <SingletonField
- key={seedWord.index}
- fieldProps={ words[counter++].value }
- /> : null)
- )
- })}
+ <div className={style.seedArea}>
+ {seedWords.map((seedWord) => {
+ return ( seedWord.show ?
+ <div key={seedWord.index} className={`${style.seed} ${style.seedWord}`}>{seedWord.word}</div> :
+ (words[counter]? <SingletonField
+ className={style.seedWord}
+ key={seedWord.index}
+ fieldProps={ words[counter++].value }
+ /> : null)
+ )
+ })}
+ </div>
{error&& <ErrorBanner error={error} />}
- <button type='submit' disabled={submitting}>submit</button>
+ <button
+ className={`btn btn-primary ${style.submit}`}
+ type='submit'
+ disabled={submitting}>
+ submit
+ </button>
</form>
)
--- /dev/null
+.submit{
+ float: left;
+}
+
+.seed{
+ user-select: none;
+ background-color: #48566e;
+ border-radius: 3px;
+ color: #fff;
+}
+
+.seedWord{
+ width: 100px;
+ height: 23px;
+ margin: 5px;
+ text-align: center;
+}
+
+.seedArea{
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+}
import React from 'react'
import { copyToClipboard } from 'utility/clipboard'
-
+import styles from './Mnemonic.scss'
class Mnemonic extends React.Component {
constructor(props) {
super(props)
+ this.state={
+ mnemonicArray : this.props.mnemonic.split(' ')
+ }
}
render() {
+ const {mnemonicArray} = this.state
return (
<div>
- {this.props.mnemonic}
+ <h2>Mnemonic</h2>
+ <p>Write down the following seed and save it in a secure location.</p>
+ <div>
+ {
+ mnemonicArray.map((seedWord) =>
+ <div className={styles.seed}>{seedWord}</div>)
+ }
+ <button
+ className={`btn btn-primary ${styles.copy}`}
+ onClick={() => copyToClipboard(this.props.mnemonic)}
+ >
+ Copy to clipboard
+ </button>
+ </div>
- <button
- className='btn btn-primary'
- onClick={() => copyToClipboard(this.props.mnemonic)}
- >
- Copy to clipboard
- </button>
</div>
)
}
--- /dev/null
+.seed{
+ user-select: none;
+ width: 100px;
+ height: 23px;
+ background-color: #48566e;
+ border-radius: 3px;
+ color: #fff;
+ margin: 5px;
+ float: left;
+ text-align: center;
+}
+
+.copy{
+ width: 177px;
+ margin: 4px;
+}
return(
<div className={touched && error &&'has-error'}>
<input
- className='form-control'
+ className={`form-control ${this.props.className}`}
autoFocus={!!this.props.autoFocus}
{...disableAutocomplete}
{...fieldProps} />
import React from 'react'
+import styles from './stepper.scss'
class Step extends React.Component {
isActive,
displayPrevious,
displayNext,
- displaySubmit,
component,
children,
} = this.props
return (
<div>
{component ? React.createElement(component) : children}
- <Previous
- isActive={displayPrevious}
- goToPreviousStep={() => this.props.goToPreviousStep()}
- />
<Next
isActive={displayNext}
goToNextStep={() => this.props.goToNextStep()}
/>
+ <Previous
+ isActive={displayPrevious}
+ goToPreviousStep={() => this.props.goToPreviousStep()}
+ />
</div>
)
}
if (isActive === false) return null
return (
- <button onClick={() => this.props.goToNextStep()}>
- Next
+ <button
+ className='btn btn-default'
+ onClick={() => this.props.goToNextStep()}>
+ Continue
</button>
)
}
if (isActive === false) return null
return (
- <button onClick={() => this.props.goToPreviousStep()}>
- Previous
- </button>
- )
- }
-}
-
-class Submit extends React.Component {
-
- render() {
- const { isActive } = this.props
- if (isActive === false) return null
-
- return (
- <button
- type='submit'
- onClick={() => this.props.submit()}
- >
- { this.props.submitLabel || 'Submit' }
- </button>
+ <a
+ className= {styles.marginLeft}
+ onClick={() => this.props.goToPreviousStep()}>
+ Cancel
+ </a>
)
-
}
}
-
export default Step
\ No newline at end of file
--- /dev/null
+.marginLeft{
+ margin-left: $gutter-size/2;
+ cursor: pointer;
+}
\ No newline at end of file
"title":"Backup and Restore",
"backup":"Back Up",
"backupDescription":"This option will back up all data stored in this core, including blockchain data, accounts, assets and balances.",
- "restoreKeystore":"Restore by File",
+ "restoreKeystore":"Restore from File",
"restoreKeystoreDescription":"This option will restore the wallet data form a file. You might need to rescan your wallet, if you balance is not up to date.",
"restoreMnemonic":"Restore by Mnemonic",
"restoreMnemonicDescription":"This option will restore the key related data by mnemonic. You might need to rescan your wallet, if you balance is not up to date.",