import styles from './Backup.scss'
import {connect} from 'react-redux'
import {chainClient} from 'utility/environment'
+import actions from 'actions'
class Backup extends React.Component {
constructor(props) {
super(props)
- this.connection = chainClient().connection
+ this.state = {
+ value: null
+ }
}
- backup() {
- this.connection.request('/backup-wallet').then(resp => {
- const date = new Date()
- const dateStr = date.toLocaleDateString().split(' ')[0]
- const timestamp = date.getTime()
- const fileName = ['bytom-wallet-backup-', dateStr, timestamp].join('-')
-
- var element = document.createElement('a')
- element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(resp.data)))
- element.setAttribute('download', fileName)
- element.style.display = 'none'
- document.body.appendChild(element)
- element.click()
-
- document.body.removeChild(element)
+ setValue(event) {
+ this.setState({
+ value:event.target.value
})
}
+ backup() {
+ chainClient().backUp.backup()
+ .then(resp => {
+ const date = new Date()
+ const dateStr = date.toLocaleDateString().split(' ')[0]
+ const timestamp = date.getTime()
+ const fileName = ['bytom-wallet-backup-', dateStr, timestamp].join('-')
+
+ let element = document.createElement('a')
+ element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(resp.data)))
+ element.setAttribute('download', fileName)
+ element.style.display = 'none'
+ document.body.appendChild(element)
+ element.click()
+
+ document.body.removeChild(element)
+ })
+ .catch(err => { throw {_error: err} })
+ }
+
handleFileChange(event) {
const files = event.target.files
if (files.length <= 0) {
const fileReader = new FileReader()
fileReader.onload = fileLoadedEvent => {
const backupData = JSON.parse(fileLoadedEvent.target.result)
- this.connection.request('/restore-wallet', backupData).then(resp => {
- if (resp.status === 'fail') {
- this.props.showError(new Error(resp.msg))
- return
- }
- this.props.showRestoreSuccess()
- })
+ this.props.restoreFile(backupData)
}
fileReader.readAsText(files[0], 'UTF-8')
render() {
const lang = this.props.core.lang
- const newButton = <button className='btn btn-primary' onClick={this.backup.bind(this)}>
- {lang === 'zh' ? '备份' : 'Backup'}
+
+ const newButton = <button className={`btn btn-primary btn-lg ${styles.submit}`} onClick={this.backup.bind(this)}>
+ {lang === 'zh' ? '下载备份' : 'Download Backup'}
</button>
- const restoreButton = <button className='btn btn-primary' onClick={this.restore.bind(this)}>
- {lang === 'zh' ? '恢复' : 'Restore'}
+ const restoreButton = <button className={`btn btn-primary btn-lg ${styles.submit}`} onClick={this.restore.bind(this)}>
+ {lang === 'zh' ? '选择备份文件' : 'Select Restore File'}
+ </button>
+ const rescanButton = <button className={`btn btn-primary btn-lg ${styles.submit}`} onClick={() => this.props.rescan()}>
+ {lang === 'zh' ? '重新扫描' : 'Rescan'}
</button>
return (
- <div className={componentClassNames(this, 'flex-container', styles.mainContainer)}>
+ <div className='flex-container'>
<PageTitle title={lang === 'zh' ? '备份与恢复' : 'Backup and Restore'}/>
<PageContent>
- {newButton}
- <hr/>
- {restoreButton}
- <input id='bytom-restore-file-upload' type='file' style={{'display': 'none', 'alignItems': 'center', 'fontSize': '12px'}}
- onChange={this.handleFileChange.bind(this)}/>
+
+ <div onChange={e => this.setValue(e)}>
+ <div className={styles.choices}>
+ <div className={styles.choice_wrapper}>
+ <label>
+ <input className={styles.choice_radio_button}
+ type='radio'
+ name='type'
+ value='backup'/>
+ <div className={`${styles.choice} ${styles.new} `}>
+ <span className={styles.choice_title}>{lang === 'zh' ?'备份':'Back Up'}</span>
+ <p>
+ This option will back up all data stored in this core,
+ including blockchain data, accounts, assets
+ and balances.
+ </p>
+ </div>
+ </label>
+ </div>
+
+ <div className={styles.choice_wrapper}>
+ <label>
+ <input className={styles.choice_radio_button}
+ type='radio'
+ name='type'
+ value='restore' />
+ <div className={`${styles.choice} ${styles.join}`}>
+ <span className={styles.choice_title}>{lang === 'zh' ?'恢复':'Restore'}</span>
+ <p>
+ This option will restore the wallet data form files.
+ You might need to rescan your wallet, if you balance is not up to date
+ </p>
+ </div>
+ </label>
+ </div>
+
+ <div className={styles.choice_wrapper}>
+ <label>
+ <input className={styles.choice_radio_button}
+ type='radio'
+ name='type'
+ value='rescan' />
+ <div className={`${styles.choice} ${styles.join}`}>
+ <span className={styles.choice_title}>{lang === 'zh' ?'重新扫描':'Rescan'}</span>
+ <p>
+ This option will rescan your wallet and update your balance.
+ </p>
+ </div>
+ </label>
+ </div>
+
+
+ </div>
+
+ <div className={styles.choices}>
+ <div>
+ {
+ this.state.value === 'backup'
+ &&<span className={styles.submitWrapper}>{newButton}</span>
+ }
+ </div>
+
+ <div>
+ {
+ this.state.value === 'restore'
+ &&
+ <span className={styles.submitWrapper}>{restoreButton}</span>
+ }
+ <input id='bytom-restore-file-upload' type='file'
+ style={{'display': 'none', 'alignItems': 'center', 'fontSize': '12px'}}
+ onChange={this.handleFileChange.bind(this)}/>
+ </div>
+ <div>
+ {
+ this.state.value === 'rescan'
+ &&
+ <span className={styles.submitWrapper}>{rescanButton}</span>
+ }
+ </div>
+ </div>
+ </div>
+
</PageContent>
</div>
)
})
const mapDispatchToProps = (dispatch) => ({
- showError: (err) => {
- dispatch({type: 'ERROR', payload: err})
- },
- showRestoreSuccess: () => dispatch({type: 'RESTORE_SUCCESS'})
+ backup: () => dispatch(actions.backUp.backup()),
+ rescan: () => dispatch(actions.backUp.rescan()),
+ restoreFile: (backUpFile) => dispatch(actions.backUp.restore(backUpFile)),
})
export default connect(
-.page_header h1 {
- margin-bottom: 0;
+.mainContainer {
+ background-color: $background-color;
+}
+
+code {
+ padding-left: 0;
+ font-size: $font-size-code;
}
-.table {
- margin-bottom: $grid-gutter-width;
+.choices {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
- td {
- vertical-align: top;
+ > div {
+ width: 30%;
+ min-height: 100%;
}
}
-.row_label {
- padding-right: $grid-gutter-width;
- text-transform: capitalize;
- font-weight: 500;
- white-space: pre;
-}
+.choice_wrapper {
+ display: flex;
+ min-height: 100%;
-.row_value {
- white-space: pre;
- text-align: right;
+ > label {
+ display: flex;
+ min-height:100%;
+ font-weight: normal;
+ }
}
-.block_hash {
- display: block;
- word-wrap: break-word;
- word-break: break-all;
+.choice_radio_button {
+ position: absolute;
+ visibility: hidden;
}
-.flex {
- display: flex;
- //overflow:hidden;
-}
+.choice {
+ border: 1px solid $table-border-color;
+ border-radius: $border-radius-base;
+ cursor: pointer;
+ min-height: 100%;
+ padding: 20px $grid-gutter-width;
+ padding-top: 110px;
+ text-align: center;
-.col {
- display: flex;
- width: 50%;
- padding: $grid-gutter-width;
- h4 {
- margin-top: 0;
+ background-color: $background-color;
+ background-repeat: no-repeat;
+ background-position: center 25px;
+ background-size: 90px 90px;
+
+ &:hover {
+ background-color: $background-emphasis-color;
}
-}
-.sub-row {
- padding: $grid-gutter-width $grid-gutter-width 0;
-}
+ &.disabled {
+ cursor: default;
+ background-color: $background-emphasis-color;
+ opacity: 0.75;
-.top {
- border-bottom: 1px solid $border-color;
-}
+ .choice_title {
+ color: $text-light-color;
+ }
+ }
-.left {
- padding-left: 0;
- width: 67%;
-}
+ p {
+ line-height: 1.4;
+ }
-.right {
- border-left: 1px solid $border-color;
- width: 33%;
-}
+ svg {
+ display: block;
+ margin: 0 auto;
+ width: 80px;
+ height: 80px;
+ }
-.replication_lag {
- display: inline-block;
- float: right;
- border-radius: $border-radius-base;
- color: white;
- padding: 0 8px;
- line-height: 1.5;
- margin-top: 2px;
- margin-left: -8px;
+ .choice_title{
+ display: block;
+ font-size: $font-size-section-title;
+ margin: 12px 0;
+ color: $text-strong-color;
+ font-weight: 600;
+ }
}
-.green {
- background: $highlight-secondary;
+.new {
+ background-image: url('images/config/new.png')
}
-.yellow {
- background: $brand-warning;
+.join {
+ background-image: url('images/config/join.png')
}
-.red {
- background: darken($highlight-danger-background, 20%);
+.testnet {
+ background-image: url('images/config/testnet.png')
}
-.mainContainer {
- background-color: $background-color;
-}
+input[type=radio]:checked ~ .choice {
+ strong {
+ color: $text-danger;
+ }
-code {
- padding-left: 0;
- font-size: $font-size-code;
-}
+ &:hover {
+ background-color: $background-color;
+ }
-.switch {
- position: relative;
- display: inline-block;
- width: 44px;
- height: 22px;
+ &.new {
+ background-image: url('images/config/new-active.png')
+ }
- /* Hide default HTML checkbox */
- input {display:none;}
+ &.join {
+ background-image: url('images/config/join-active.png')
+ }
- input:checked + .slider {
- background-color: $highlight-default;
+ &.testnet {
+ background-image: url('images/config/testnet-active.png')
}
- input:focus + .slider {
- box-shadow: 0 0 1px $highlight-default;
+
+ .choice_title {
+ color: $brand-primary;
}
- input:checked + .slider:before {
- -webkit-transform: translateX(22px);
- -ms-transform: translateX(22px);
- transform: translateX(22px);
+ svg {
+ polygon {
+ stroke: $brand-primary;
+ fill: transparentize($brand-primary, 0.85);
+ }
+
+ rect, path {
+ fill: $brand-primary
+ }
}
}
-/* The slider */
-.slider {
- position: absolute;
- cursor: pointer;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: #ccc;
- -webkit-transition: .4s;
- transition: .4s;
- border-radius: 34px;
+.submitWrapper {
+ display: block;
+ margin-top: 30px;
+}
+
+.submit {
+ display: block;
+ width: 100%;
+ margin-top: $gutter-size;
+}
+
+.infoLink {
+ position: relative;
+ left: 4px;
+ top: 1px;
+ color:$text-light-color;
}
-.slider:before {
- position: absolute;
- content: "";
- height: 18px;
- width: 18px;
- left: 2px;
- bottom: 2px;
- background-color: white;
- -webkit-transition: .4s;
- transition: .4s;
- border-radius: 50%;
-}
\ No newline at end of file