Browse Source

passphrase import modal; rescan handling; bug fixes

all-modes
pbca26 7 years ago
parent
commit
776d011335
  1. 6
      assets/mainWindow/js/loading.js
  2. 8
      react/src/actions/actionCreators.js
  3. 57
      react/src/actions/actions/nativeDashboardUpdate.js
  4. 25
      react/src/actions/actions/nativeSyncInfo.js
  5. 1
      react/src/actions/actions/walletAuth.js
  6. 3
      react/src/actions/storeType.js
  7. 2
      react/src/components/addcoin/addcoinOptionsAC.js
  8. 3
      react/src/components/addcoin/payload.js
  9. 5
      react/src/components/dashboard/claimInterestModal/claimInterestModal.js
  10. 31
      react/src/components/dashboard/coinTile/coinTileItem.js
  11. 243
      react/src/components/dashboard/importKeyModal/importKeyModal.js
  12. 136
      react/src/components/dashboard/importKeyModal/importKeyModal.render.js
  13. 33
      react/src/components/dashboard/importKeyModal/importKeyModal.scss
  14. 8
      react/src/components/dashboard/jumblr/jumblr.js
  15. 4
      react/src/components/dashboard/main/dashboard.js
  16. 4
      react/src/components/dashboard/main/dashboard.render.js
  17. 6
      react/src/components/dashboard/navbar/navbar.js
  18. 7
      react/src/components/dashboard/navbar/navbar.render.js
  19. 4
      react/src/components/dashboard/sendCoin/sendCoin.js
  20. 31
      react/src/components/dashboard/walletsProgress/walletsProgress.js
  21. 50
      react/src/components/dashboard/walletsProgress/walletsProgress.render.js
  22. 4
      react/src/components/overrides.scss
  23. 7
      react/src/reducers/activeCoin.js
  24. 10
      react/src/reducers/dashboard.js
  25. 1
      react/src/styles/index.scss
  26. 3
      react/src/translate/en.js
  27. 4
      react/src/util/coinHelper.js
  28. 1
      react/src/util/crypto/gen/cryptojs.sha256.js

6
assets/mainWindow/js/loading.js

@ -209,10 +209,10 @@ function closeMainWindow(isKmdOnly, isCustom) {
window.createWindow('open');
window.hide();
}, 3000);
} else {
window.createWindow('open');
window.hide();
}
window.createWindow('open');
window.hide();
}
function quitApp() {

8
react/src/actions/actionCreators.js

@ -30,6 +30,7 @@ import {
START_INTERVAL,
STOP_INTERVAL,
DASHBOARD_SYNC_ONLY_UPDATE,
DISPLAY_IMPORT_KEY_MODAL,
} from './storeType';
export * from './actions/nativeSyncInfo';
@ -349,4 +350,11 @@ export function skipFullDashboardUpdate(skip) {
type: DASHBOARD_SYNC_ONLY_UPDATE,
skipFullDashboardUpdate: skip,
}
}
export function displayImportKeyModal(display) {
return {
type: DISPLAY_IMPORT_KEY_MODAL,
displayImportKeyModal: display,
}
}

57
react/src/actions/actions/nativeDashboardUpdate.js

@ -43,25 +43,44 @@ export function getDashboardUpdate(coin, activeCoinProps) {
}
}
export function getDashboardUpdateState(json, coin) {
let _listtransactions = json.result['listtransactions'];
export function getDashboardUpdateState(json, coin, fakeResponse) {
// rescan or similar resource heavy process
if (fakeResponse ||
((json.result['getinfo'].error && json.result['getinfo'].error === 'daemon is busy') &&
(json.result['z_getoperationstatus'].error && json.result['z_getoperationstatus'].error === 'daemon is busy') &&
(json.result['listtransactions'].error && json.result['listtransactions'].error === 'daemon is busy') &&
(json.result['listtransactions'].error && json.result['listtransactions'].error === 'daemon is busy'))) {
return {
type: DASHBOARD_UPDATE,
progress: null,
opids: null,
txhistory: null,
balance: null,
addresses: null,
coin: coin,
rescanInProgress: true,
};
} else {
let _listtransactions = json.result['listtransactions'];
if (_listtransactions &&
_listtransactions.error) {
_listtransactions = null;
} else if (_listtransactions && _listtransactions.result && _listtransactions.result.length) {
_listtransactions = _listtransactions.result;
} else if (!_listtransactions || (!_listtransactions.result || !_listtransactions.result.length)) {
_listtransactions = 'no data';
}
if (_listtransactions &&
_listtransactions.error) {
_listtransactions = null;
} else if (_listtransactions && _listtransactions.result && _listtransactions.result.length) {
_listtransactions = _listtransactions.result;
} else if (!_listtransactions || (!_listtransactions.result || !_listtransactions.result.length)) {
_listtransactions = 'no data';
}
return {
type: DASHBOARD_UPDATE,
progress: json.result['getinfo'].result,
opids: json.result['z_getoperationstatus'].result,
txhistory: _listtransactions,
balance: json.result['z_gettotalbalance'].result,
addresses: json.result['addresses'],
coin: coin,
};
return {
type: DASHBOARD_UPDATE,
progress: json.result['getinfo'].result,
opids: json.result['z_getoperationstatus'].result,
txhistory: _listtransactions,
balance: json.result['z_gettotalbalance'].result,
addresses: json.result['addresses'],
coin: coin,
rescanInProgress: false,
};
}
}

25
react/src/actions/actions/nativeSyncInfo.js

@ -73,7 +73,7 @@ function getSyncInfoNativeState(json, coin, skipDebug, skipRemote) {
}
}
export function getSyncInfoNative(coin, skipDebug, skipRemote) {
export function getSyncInfoNative(coin, skipDebug, skipRemote, suppressErrors) {
let payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: getPassthruAgent(coin),
@ -113,13 +113,15 @@ export function getSyncInfoNative(coin, skipDebug, skipRemote) {
)
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getSyncInfo',
'Error',
'error'
)
);
if (!suppressErrors) { // rescan case
dispatch(
triggerToaster(
'getSyncInfo',
'Error',
'error'
)
);
}
})
.then(function(response) {
const _response = response.text().then(function(text) { return text; });
@ -127,6 +129,11 @@ export function getSyncInfoNative(coin, skipDebug, skipRemote) {
})
.then(json => {
if (json === 'Work queue depth exceeded') {
if (coin === 'KMD') {
dispatch(getDebugLog('komodo', 100));
} else {
dispatch(getDebugLog('komodo', 100, coin));
}
dispatch(
getSyncInfoNativeState(
{
@ -135,7 +142,7 @@ export function getSyncInfoNative(coin, skipDebug, skipRemote) {
id: null
},
coin,
skipDebug,
true,
skipRemote
)
);

1
react/src/actions/actions/walletAuth.js

@ -160,6 +160,7 @@ export function iguanaActiveHandle(getMainAddress) {
export function iguanaWalletPassphraseState(json, dispatch, skipToastr) {
sessionStorage.setItem('IguanaActiveAccount', JSON.stringify(json));
if (!skipToastr) {
dispatch(
triggerToaster(

3
react/src/actions/storeType.js

@ -44,4 +44,5 @@ export const CLI = 'CLI';
export const LOGOUT = 'LOGOUT';
export const DISPLAY_COIND_DOWN_MODAL = 'DISPLAY_COIND_DOWN_MODAL';
export const DISPLAY_LOGIN_SETTINGS_MODAL = 'DISPLAY_LOGIN_SETTINGS_MODAL';
export const DISPLAY_CLAIM_INTEREST_MODAL = 'DISPLAY_CLAIM_INTEREST_MODAL';
export const DISPLAY_CLAIM_INTEREST_MODAL = 'DISPLAY_CLAIM_INTEREST_MODAL';
export const DISPLAY_IMPORT_KEY_MODAL = 'DISPLAY_IMPORT_KEY_MODAL';

2
react/src/components/addcoin/addcoinOptionsAC.js

@ -19,7 +19,7 @@ class AddCoinOptionsAC extends React.Component {
'revs',
'shark',
'supernet',
'wlc'
'wlc',
];
let _items = [];

3
react/src/components/addcoin/payload.js

@ -688,6 +688,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) {
'seedipaddr': '78.47.196.146'
};
// TODO: move netmagic to node
const acConfig = {
'SUPERNET': {
'name': 'SUPERNET',
@ -790,7 +791,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) {
'supply': 72000000,
'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {'coin':'COQUI','conf':'COQUI.conf','path':confpath,'RELAY':-1,'VALIDATE':1,'startpend':4,'endpend':4,'maxpeers':8,'newcoin':'COQUI','name':'COQUI','netmagic':'4cbd5ef4','p2p':assetChainPorts.COQUI - 1,'rpc':assetChainPorts.COQUI}) : {},
'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,'RELAY':mode,'VALIDATE':mode,'startpend':tmpPendValue,'endpend':tmpPendValue,'maxpeers':8,'newcoin':'COQUI','name':'COQUI','netmagic':'4cbd5ef4','p2p':assetChainPorts.COQUI - 1,'rpc':assetChainPorts.COQUI})
}
},
};
if (mode === '-1') {

5
react/src/components/dashboard/claimInterestModal/claimInterestModal.js

@ -54,7 +54,7 @@ class ClaimInterestModal extends React.Component {
interest: json[i].interest,
txid: json[i].txid,
});
_totalInterest =+ json[i].interest;
_totalInterest += Number(json[i].interest);
if (i === json.length - 1) {
this.setState({
@ -84,7 +84,7 @@ class ClaimInterestModal extends React.Component {
} else if (json.result && json.result.length && json.result.length === 64) {
Store.dispatch(
triggerToaster(
`translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P1') ${this.state.transactionsList[0].address}. translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P2')`,
`${translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P1')} ${this.state.transactionsList[0].address}. ${translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P2')}`,
translate('TOASTR.WALLET_NOTIFICATION'),
'success',
false
@ -138,6 +138,7 @@ class ClaimInterestModal extends React.Component {
return ClaimInterestModalRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {

31
react/src/components/dashboard/coinTile/coinTileItem.js

@ -75,23 +75,43 @@ class CoinTileItem extends React.Component {
const _propsDashboard = this.props.ActiveCoin;
const syncPercentage = _propsDashboard && _propsDashboard.progress && (parseFloat(parseInt(_propsDashboard.progress.blocks, 10) * 100 / parseInt(_propsDashboard.progress.longestchain, 10)).toFixed(2)).replace('NaN', 0);
if (syncPercentage < 100 &&
!this.props.Dashboard.displayCoindDownModal) {
Store.dispatch(getDebugLog('komodo', 10));
if ((syncPercentage < 100 &&
!this.props.Dashboard.displayCoindDownModal) ||
this.props.ActiveCoin.rescanInProgress) {
if (coin === 'KMD') {
Store.dispatch(getDebugLog('komodo', 50));
} else {
Store.dispatch(getDebugLog('komodo', 50, coin));
}
}
if (!this.props.Dashboard.displayCoindDownModal &&
_propsDashboard.progress &&
_propsDashboard.progress.blocks &&
_propsDashboard.progress.longestchain &&
syncPercentage &&
(Config.iguanaLessMode || syncPercentage >= NATIVE_MIN_SYNC_PERCENTAGE_THRESHOLD)) {
Store.dispatch(getSyncInfoNative(coin, true, this.props.Dashboard.skipFullDashboardUpdate));
Store.dispatch(
getSyncInfoNative(
coin,
true,
this.props.Dashboard.skipFullDashboardUpdate,
this.props.ActiveCoin.rescanInProgress
)
);
if (!this.props.Dashboard.skipFullDashboardUpdate) {
Store.dispatch(getDashboardUpdate(coin, _propsDashboard));
}
} else {
Store.dispatch(getSyncInfoNative(coin, null, this.props.Dashboard.skipFullDashboardUpdate));
Store.dispatch(
getSyncInfoNative(
coin,
null,
this.props.Dashboard.skipFullDashboardUpdate,
this.props.ActiveCoin.rescanInProgress
)
);
}
}
if (mode === 'full') {
@ -237,6 +257,7 @@ const mapStateToProps = (state) => {
addresses: state.ActiveCoin.addresses,
mainBasiliskAddress: state.ActiveCoin.mainBasiliskAddress,
progress: state.ActiveCoin.progress,
rescanInProgress: state.ActiveCoin.rescanInProgress,
},
Dashboard: state.Dashboard,
Interval: {

243
react/src/components/dashboard/importKeyModal/importKeyModal.js

@ -0,0 +1,243 @@
import React from 'react';
import { connect } from 'react-redux';
import ReactDOM from 'react-dom';
import Store from '../../../store';
import {
displayImportKeyModal,
importPrivkey,
triggerToaster,
copyCoinAddress,
getDebugLog,
getDashboardUpdateState
} from '../../../actions/actionCreators';
import { translate } from '../../../translate/translate';
import {
ImportKeyModalRender,
} from './importKeyModal.render';
// import gen komodo keys utils
import '../../../util/crypto/gen/array.map.js';
import '../../../util/crypto/gen/cryptojs.js';
import '../../../util/crypto/gen/cryptojs.sha256.js';
import '../../../util/crypto/gen/cryptojs.pbkdf2.js';
import '../../../util/crypto/gen/cryptojs.hmac.js';
import '../../../util/crypto/gen/cryptojs.aes.js';
import '../../../util/crypto/gen/cryptojs.blockmodes.js';
import '../../../util/crypto/gen/cryptojs.ripemd160.js';
import '../../../util/crypto/gen/securerandom.js';
import '../../../util/crypto/gen/ellipticcurve.js';
import '../../../util/crypto/gen/biginteger.js';
import '../../../util/crypto/gen/crypto-scrypt.js';
import { Bitcoin } from '../../../util/crypto/gen/bitcoin.js';
class ImportKeyModal extends React.Component {
constructor() {
super();
this.state = {
open: false,
wif: '',
wifkeysPassphrase: '',
passphraseWif: null,
passphraseAddress: null,
keyImportResult: null,
importWithRescan: false,
seedInputVisibility: false,
toggleSeedInputVisibility: false,
trimPassphraseTimer: null,
};
this.generateKeysFromPassphrase = this.generateKeysFromPassphrase.bind(this);
this.toggleImportWithRescan = this.toggleImportWithRescan.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this._copyCoinAddress = this._copyCoinAddress.bind(this);
this.showPassphraseAddress = this.showPassphraseAddress.bind(this);
this.importWifAddress = this.importWifAddress.bind(this);
this.updateInput = this.updateInput.bind(this);
this.importFromPassphrase = this.importFromPassphrase.bind(this);
this.importFromWif = this.importFromWif.bind(this);
}
_copyCoinAddress(address) {
Store.dispatch(copyCoinAddress(address));
}
updateInput(e) {
if (e.target.name === 'wifkeysPassphrase') {
// remove any empty chars from the start/end of the string
const newValue = e.target.value;
clearTimeout(this.state.trimPassphraseTimer);
const _trimPassphraseTimer = setTimeout(() => {
this.setState({
wifkeysPassphrase: newValue ? newValue.trim() : '', // hardcoded field name
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name]: newValue,
});
} else {
this.setState({
[e.target.name]: e.target.value,
});
}
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#wifkeysPassphraseTextarea').style.height = '1px';
document.querySelector('#wifkeysPassphraseTextarea').style.height = `${(15 + document.querySelector('#wifkeysPassphraseTextarea').scrollHeight)}px`;
}
}, 100);
}
toggleSeedInputVisibility() {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
});
}
showPassphraseAddress() {
const _address = this.generateKeysFromPassphrase();
if (_address) {
this.setState({
passphraseAddress: _address.address,
passphraseWif: _address.wif,
});
}
}
importFromPassphrase() {
const _address = this.generateKeysFromPassphrase();
if (_address) {
this.importWifAddress(_address.wif, true);
}
}
importFromWif() {
this.importWifAddress(this.state.wif, this.state.importWithRescan);
}
importWifAddress(wif, rescan) {
let _rescanInProgress = true;
if (rescan) {
setTimeout(() => {
if (_rescanInProgress) {
setTimeout(() => {
if (this.props.ActiveCoin.coin === 'KMD') {
Store.dispatch(getDebugLog('komodo', 100));
} else {
Store.dispatch(getDebugLog('komodo', 100, this.props.ActiveCoin.coin));
}
}, 2000);
Store.dispatch(getDashboardUpdateState(null, this.props.ActiveCoin.coin, true));
Store.dispatch(
triggerToaster(
'Address imported. Wallet rescan is in progress. Please wait until it\s finished.',
translate('TOASTR.WALLET_NOTIFICATION'),
'info',
false
)
);
this.closeModal();
}
}, 2000);
}
importPrivkey(
this.props.ActiveCoin.coin,
wif,
rescan
).then((json) => {
_rescanInProgress = false;
if (!json.id &&
!json.result &&
!json.error) {
// console.warn('importPrivkey', json);
Store.dispatch(
triggerToaster(
rescan ? 'Wallet rescan finished' : 'Address imported',
translate('TOASTR.WALLET_NOTIFICATION'),
'success',
false
)
);
} else {
Store.dispatch(
triggerToaster(
json.error.message,
'Error',
'error'
)
);
}
});
}
generateKeysFromPassphrase() {
if (this.state.wifkeysPassphrase &&
this.state.wifkeysPassphrase.length) {
const bytes = Crypto.SHA256(this.state.wifkeysPassphrase, { asBytes: true });
// byte flipping to make it compat with iguana core
bytes[0] &= 248;
bytes[31] &= 127;
bytes[31] |= 64;
const btcKey = new Bitcoin.ECKey(bytes).setCompressed(true);
const kmdAddress = btcKey.getBitcoinAddress();
const wifAddress = btcKey.getBitcoinWalletImportFormat();
return {
address: kmdAddress,
wif: wifAddress,
};
} else {
Store.dispatch(
triggerToaster(
'Empty passphrase field',
'Error',
'error'
)
);
return null;
}
}
toggleImportWithRescan() {
this.setState({
importWithRescan: !this.state.importWithRescan,
});
}
closeModal() {
Store.dispatch(displayImportKeyModal(false));
}
render() {
return ImportKeyModalRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
balance: state.ActiveCoin.balance,
},
Dashboard: {
displayImportKeyModal: state.Dashboard.displayImportKeyModal,
},
};
};
export default connect(mapStateToProps)(ImportKeyModal);

136
react/src/components/dashboard/importKeyModal/importKeyModal.render.js

@ -0,0 +1,136 @@
import React from 'react';
import { translate } from '../../../translate/translate';
/*export const _ClaimInterestTableRender = function() {
};*/
export const ImportKeyModalRender = function() {
return (
<span>
<div className={ 'modal modal-import-key modal-3d-sign ' + (this.props.Dashboard.displayImportKeyModal ? 'show in' : 'fade hide') }>
<div className="modal-dialog modal-center modal-sm">
<div className="modal-content">
<div className="modal-header bg-orange-a400 wallet-send-header">
<button
type="button"
className="close white"
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">Import key</h4>
</div>
<div className="modal-body">
<div className="padding-bottom-40">
Two forms below allow you to import either <strong>Iguana Core / ICO</strong> passphrase (seed) or <strong>WIF (Wallet Import Format)</strong> key.
</div>
<div>
<strong>Passphrase / seed</strong>
<p className="margin-top-10">
<strong>Notice:</strong> importing a passphrase will trigger a full wallet rescan.&nbsp;
<span className={ this.props.ActiveCoin.coin === 'KMD' ? '' : 'hide' }>This process can take hours to rescan the whole blockchain.</span>
</p>
<form
className="wifkeys-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="password"
className={ !this.state.seedInputVisibility ? 'form-control' : 'hide' }
name="wifkeysPassphrase"
id="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase } />
<textarea
className={ this.state.seedInputVisibility ? 'form-control' : 'hide' }
id="wifkeysPassphraseTextarea"
name="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase }></textarea>
<i
className={ 'seed-toggle fa fa-eye' + (!this.state.seedInputVisibility ? '-slash' : '') }
onClick={ this.toggleSeedInputVisibility }></i>
<label
className="floating-label"
htmlFor="wifkeysPassphrase">{ translate('INDEX.PASSPHRASE') }</label>
</div>
<div className="text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-right-20"
onClick={ this.importFromPassphrase }>Import</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.showPassphraseAddress }>Show address and WIF</button>
</div>
</form>
{ this.state.passphraseAddress && this.state.passphraseWif &&
<div className="margin-top-60">
<p>
<strong>Address: </strong> { this.state.passphraseAddress }
<button
className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(this.state.passphraseAddress) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</p>
<p>
<strong>WIF: </strong> { this.state.passphraseWif }
<button
className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(this.state.passphraseWif) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</p>
</div>
}
</div>
<div className="line">or</div>
<div>
<strong>WIF (Wallet Import Format)</strong>
<div className="toggle-box padding-top-20">
<span className="pointer">
<label className="switch">
<input
type="checkbox"
checked={ this.state.importWithRescan } />
<div
className="slider"
onClick={ this.toggleImportWithRescan }></div>
</label>
<div
className="toggle-label"
onClick={ this.toggleImportWithRescan }>
Trigger rescan
<i
className="icon fa-question-circle settings-help"
title="Use this option if you want to trigger rescan after WIF is imported. If you have several addresses that you want to import add them one by one and toggle this option on the last address import."></i>
</div>
</span>
</div>
<div className="margin-top-20">
<label htmlFor="wif" className="bold">Wif key</label>
<input
type="text"
className="form-control"
name="wif"
onChange={ this.updateInput }
value={ this.state.wif } />
</div>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-top-10"
onClick={ this.importFromWif }>{ this.state.importWithRescan ? 'Import and rescan' : 'Import' }</button>
</div>
</div>
</div>
</div>
</div>
<div className={ 'modal-backdrop ' + (this.props.Dashboard.displayImportKeyModal ? 'show in' : 'fade hide') }></div>
</span>
);
};

33
react/src/components/dashboard/importKeyModal/importKeyModal.scss

@ -0,0 +1,33 @@
.modal-import-key {
.modal-dialog {
width: 70%;
max-height: 90vh;
overflow-y: auto;
overflow-x: hidden;
}
.line {
padding: 50px 0 40px 0;
text-transform: uppercase;
font-weight: bold;
}
.line:before {
content: '';
display: inline-block;
height: 1px;
width: 47%;
background: #ccc;
margin-right: 10px;
position: relative;
top: -4px;
}
.line:after {
content: '';
display: inline-block;
height: 1px;
width: 47%;
background: #ccc;
margin-left: 10px;
position: relative;
top: -4px;
}
}

8
react/src/components/dashboard/jumblr/jumblr.js

@ -285,7 +285,9 @@ class Jumblr extends React.Component {
importPrivkey(this.props.ActiveCoin.coin, _genKeys.wif)
.then((json) => {
if (!json.id && !json.result && !json.error) {
if (!json.id &&
!json.result &&
!json.error) {
_jumblrSecretAddress.push(_genKeys);
this.setState(Object.assign({}, this.state, {
jumblrSecretAddressImport: _jumblrSecretAddress,
@ -344,7 +346,9 @@ class Jumblr extends React.Component {
importPrivkey(this.props.ActiveCoin.coin, _genKeys.wif)
.then((json) => {
if (!json.id && !json.result && !json.error) {
if (!json.id &&
!json.result &&
!json.error) {
// console.warn('importPrivkey', json);
setJumblrAddress(
this.props.ActiveCoin.coin,

4
react/src/components/dashboard/main/dashboard.js

@ -45,9 +45,7 @@ const mapStateToProps = (state) => {
ActiveCoin: {
mode: state.ActiveCoin.mode,
},
Dashboard: {
activeSection: state.Dashboard.activeSection,
},
Dashboard: state.Dashboard,
};
};

4
react/src/components/dashboard/main/dashboard.render.js

@ -16,6 +16,7 @@ import About from '../about/about';
import WalletsNative from '../walletsNative/walletsNative';
import WalletsTxInfo from '../walletsTxInfo/walletsTxInfo';
import CoindDownModal from '../coindDownModal/coindDownModal';
import ImportKeyModal from '../importKeyModal/importKeyModal';
const DashboardRender = function() {
return (
@ -25,6 +26,9 @@ const DashboardRender = function() {
id="section-dashboard">
<Navbar />
<CoindDownModal />
{ this.props.Dashboard.displayImportKeyModal &&
<ImportKeyModal />
}
<div className={ this.isSectionActive('wallets') ? 'show' : 'hide' }>
<CoinTile />
<WalletsNav />

6
react/src/components/dashboard/navbar/navbar.js

@ -7,6 +7,7 @@ import {
startInterval,
toggleSyncOnlyModal,
getSyncOnlyForks,
displayImportKeyModal,
logout,
} from '../../../actions/actionCreators';
import Store from '../../../store';
@ -67,6 +68,10 @@ class Navbar extends React.Component {
}
}
openImportKeyModal() {
Store.dispatch(displayImportKeyModal(true));
}
openDropMenu() {
this.setState(Object.assign({}, this.state, {
openDropMenu: !this.state.openDropMenu,
@ -126,6 +131,7 @@ class Navbar extends React.Component {
return NavbarRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {

7
react/src/components/dashboard/navbar/navbar.render.js

@ -64,6 +64,13 @@ const NavbarRender = function() {
</a>
</li>
}
{ this.state.nativeOnly &&
<li className="nav-top-menu">
<a onClick={ this.openImportKeyModal }>
<i className="site-menu-icon"></i> Import key
</a>
</li>
}
<li className={ this.state.nativeOnly ? 'hide' : (this.isSectionActive('atomic') ? 'active nav-top-menu' : 'nav-top-menu') }>
<a onClick={ () => this.dashboardChangeSection('atomic') }>
<i className="site-menu-icon"></i> Atomic Explorer

4
react/src/components/dashboard/sendCoin/sendCoin.js

@ -833,7 +833,7 @@ class SendCoin extends React.Component {
valid = false;
}
if ((this.props.ActiveCoin.mode === 'basilisk' && Number(this.state.amount) > Number(this.state.sendFromAmount)) ||
/*if ((this.props.ActiveCoin.mode === 'basilisk' && Number(this.state.amount) > Number(this.state.sendFromAmount)) ||
(this.props.ActiveCoin.mode === 'full' && Number(this.state.amount) > Number(this.checkBalance()))) {
Store.dispatch(
triggerToaster(
@ -843,7 +843,7 @@ class SendCoin extends React.Component {
)
);
valid = false;
}
}*/
return valid;
}

31
react/src/components/dashboard/walletsProgress/walletsProgress.js

@ -44,11 +44,16 @@ class WalletsProgress extends React.Component {
if (_progress) {
if ((!_progress.blocks && !_progress.longestchain) ||
(_progress.blocks < _progress.longestchain)) {
(_progress.blocks < _progress.longestchain) ||
this.props.ActiveCoin.rescanInProgress) {
return ChainActivationNotificationRender.call(this);
}
} else {
return null;
if (this.props.ActiveCoin.rescanInProgress) {
return ChainActivationNotificationRender.call(this);
} else {
return null;
}
}
}
@ -131,9 +136,28 @@ class WalletsProgress extends React.Component {
return TranslationComponentsRender.call(this, translationID);
}
renderRescanProgress() {
if (this.props.Settings.debugLog.indexOf('Still rescanning') > -1 &&
this.props.ActiveCoin.rescanInProgress) {
const temp = this.props.Settings.debugLog.split(' ');
let currentProgress;
for (let i = 0; i < temp.length; i++) {
if (temp[i].indexOf('Progress=') > -1) {
currentProgress = Number(temp[i].replace('Progress=', '')) * 100;
}
}
return currentProgress;
} else {
return null;
}
}
renderActivatingBestChainProgress() {
if (this.props.Settings &&
this.props.Settings.debugLog) {
this.props.Settings.debugLog &&
!this.props.ActiveCoin.rescanInProgress) {
if (this.props.Settings.debugLog.indexOf('UpdateTip') > -1 &&
!this.props.ActiveCoin.progress &&
!this.props.ActiveCoin.progress.blocks) {
@ -246,6 +270,7 @@ const mapStateToProps = (state) => {
mode: state.ActiveCoin.mode,
coin: state.ActiveCoin.coin,
progress: state.ActiveCoin.progress,
rescanInProgress: state.ActiveCoin.rescanInProgress,
},
};
};

50
react/src/components/dashboard/walletsProgress/walletsProgress.render.js

@ -18,23 +18,43 @@ export const SyncErrorBlocksRender = function() {
};
export const SyncPercentageRender = function(syncPercentage) {
return (
<div
className="progress-bar progress-bar-info progress-bar-striped active font-size-80-percent"
style={{ width: syncPercentage }}>
<span style={{ width: syncPercentage }}>{ syncPercentage }</span> | { this.props.ActiveCoin.progress.blocks } / { this.props.ActiveCoin.progress.longestchain } | { translate('INDEX.CONNECTIONS') }: { this.props.ActiveCoin.progress.connections }
</div>
);
if (this.props.ActiveCoin.rescanInProgress) {
return (
<div
className="progress-bar progress-bar-info progress-bar-striped active font-size-80-percent"
style={{ width: '100%' }}>
<span style={{ width: '100%' }}>Please wait until rescan process is finished</span>
</div>
);
} else {
return (
<div
className="progress-bar progress-bar-info progress-bar-striped active font-size-80-percent"
style={{ width: syncPercentage }}>
<span style={{ width: syncPercentage }}>{ syncPercentage } | { this.props.ActiveCoin.progress.blocks } / { this.props.ActiveCoin.progress.longestchain } | { translate('INDEX.CONNECTIONS') }: { this.props.ActiveCoin.progress.connections }</span>
</div>
);
}
};
export const LoadingBlocksRender = function() {
return (
<div
className="progress-bar progress-bar-info progress-bar-striped active font-size-80-percent"
style={{ width: '100%' }}>
<span style={{ width: '100%' }}>{ translate('INDEX.LOADING_BLOCKS') }</span>
</div>
);
if (this.props.ActiveCoin.rescanInProgress) {
return (
<div
className="progress-bar progress-bar-info progress-bar-striped active font-size-80-percent"
style={{ width: '100%' }}>
<span style={{ width: '100%' }}>Please wait until rescan process is finished</span>
</div>
);
} else {
return (
<div
className="progress-bar progress-bar-info progress-bar-striped active font-size-80-percent"
style={{ width: '100%' }}>
<span style={{ width: '100%' }}>{ translate('INDEX.LOADING_BLOCKS') }</span>
</div>
);
}
};
export const TranslationComponentsRender = function(translationID) {
@ -62,7 +82,7 @@ export const ChainActivationNotificationRender = function() {
type="button">
<span>×</span>
</button>
<h4>{ translate('INDEX.ACTIVATING_CHAIN') } { this.renderActivatingBestChainProgress() }
<h4>{ translate('INDEX.ACTIVATING_CHAIN') } { this.props.ActiveCoin.rescanInProgress ? (this.renderRescanProgress() ? `: ${this.renderRescanProgress().toFixed(2)}% (rescanning blocks)` : '(rescanning blocks)') : this.renderActivatingBestChainProgress() }
</h4>
<p>{ this.renderLB('INDEX.KMD_STARTED') }</p>
</div>

4
react/src/components/overrides.scss

@ -398,4 +398,8 @@ select{
.page-content-native {
position: relative;
top: -20px;
}
.bold {
font-weight: bold;
}

7
react/src/reducers/activeCoin.js

@ -38,6 +38,7 @@ export function ActiveCoin(state = {
mainBasiliskAddress: null,
activeAddress: null,
progress: null,
rescanInProgress: false,
}, action) {
switch (action.type) {
case DASHBOARD_ACTIVE_COIN_CHANGE:
@ -59,6 +60,7 @@ export function ActiveCoin(state = {
opids: state.opids,
activeBasiliskAddress: state.activeBasiliskAddress,
progress: state.progress,
rescanInProgress: state.rescanInProgress,
};
let _coins = state.coins;
_coins[state.coin] = _coinDataToStore;
@ -81,6 +83,7 @@ export function ActiveCoin(state = {
opids: _coinData.opids,
activeBasiliskAddress: _coinData.activeBasiliskAddress,
progress: _coinData.progress,
rescanInProgress: _coinData.rescanInProgress,
};
} else {
if (state.coin) {
@ -100,6 +103,7 @@ export function ActiveCoin(state = {
opids: state.opids,
activeBasiliskAddress: state.activeBasiliskAddress,
progress: state.progress,
rescanInProgress: state.rescanInProgress,
};
let _coins = state.coins;
_coins[state.coin] = _coinData;
@ -117,6 +121,7 @@ export function ActiveCoin(state = {
showTransactionInfoTxIndex: null,
activeSection: 'default',
progress: null,
rescanInProgress: false,
};
} else {
return {
@ -131,6 +136,7 @@ export function ActiveCoin(state = {
showTransactionInfoTxIndex: null,
activeSection: 'default',
progress: null,
rescanInProgress: false,
};
}
}
@ -227,6 +233,7 @@ export function ActiveCoin(state = {
txhistory: action.txhistory,
balance: action.balance,
addresses: action.addresses,
rescanInProgress: action.rescanInProgress,
};
}
default:

10
react/src/reducers/dashboard.js

@ -5,7 +5,8 @@ import {
TOGGLE_NOTIFICATIONS_MODAL,
DISPLAY_COIND_DOWN_MODAL,
DISPLAY_CLAIM_INTEREST_MODAL,
DASHBOARD_SYNC_ONLY_UPDATE
DASHBOARD_SYNC_ONLY_UPDATE,
DISPLAY_IMPORT_KEY_MODAL,
} from '../actions/storeType';
export function Dashboard(state = {
@ -16,6 +17,7 @@ export function Dashboard(state = {
displayCoindDownModal: false,
displayClaimInterestModal: false,
skipFullDashboardUpdate: false,
displayImportKeyModal: false,
}, action) {
switch (action.type) {
case DASHBOARD_SECTION_CHANGE:
@ -45,6 +47,12 @@ export function Dashboard(state = {
displayClaimInterestModal: action.displayClaimInterestModal,
};
break;
case DISPLAY_IMPORT_KEY_MODAL:
return {
...state,
displayImportKeyModal: action.displayImportKeyModal,
};
break;
case DASHBOARD_SYNC_ONLY_UPDATE:
return {
...state,

1
react/src/styles/index.scss

@ -37,6 +37,7 @@
@import '../components/dashboard/settings/settings.scss';
@import '../components/dashboard/walletsData/walletsData.scss';
@import '../components/dashboard/claimInterestModal/claimInterestModal.scss';
@import '../components/dashboard/importKeyModal/importKeyModal.scss';
@import '../components/dashboard/jumblr/jumblr.scss';
@import '../components/dashboard/qrModal/qrModal.scss';
@import '../components/dashboard/coindDownModal/coindDownModal.scss';

3
react/src/translate/en.js

@ -76,7 +76,7 @@ export const _lang = {
'RESCAN_SM': 'rescanning blocks',
'REINDEX': 'reindexing blocks from disk',
'BLOCKS_SM': 'blocks',
'LOADING_BLOCKS': 'Loading blocks...it can take up to 15 min to load blocks',
'LOADING_BLOCKS': 'Loading data please wait...',
'WEAK_SEED': 'Weak seed!',
'YOUR_SEED_MUST_CONTAIN': 'Your seed must contain:',
'YOUR_SEED_MUST_CONTAIN1': '- at least 1 upper case letter',
@ -707,5 +707,6 @@ export const _lang = {
'SUPERNET': 'SUPERNET (SUPERNET)',
'WLC': 'WIRELESS (WIRELESS)',
},
// 'CHIPS': 'CHIPS (CHIPS)',
},
};

4
react/src/util/coinHelper.js

@ -90,6 +90,10 @@ export function getCoinTitle(coin) {
coinlogo = 'SUPERNET';
coinname = 'SUPERNET';
break;
case 'CHIPS':
coinlogo = 'SUPERNET';
coinname = 'CHIPS';
break;
case 'REVS':
coinlogo = 'REVS';
coinname = 'REVS';

1
react/src/util/crypto/gen/cryptojs.sha256.js

@ -34,6 +34,7 @@
// Public API
var SHA256 = C.SHA256 = function (message, options) {
var digestbytes = util.wordsToBytes(SHA256._sha256(message));
return options && options.asBytes ? digestbytes :
options && options.asString ? Binary.bytesToString(digestbytes) :
util.bytesToHex(digestbytes);

Loading…
Cancel
Save