Browse Source

Merge pull request #109 from pbca26/redux

Redux
all-modes
pbca26 8 years ago
committed by GitHub
parent
commit
a01213ef44
  1. 1
      .gitignore
  2. 82
      react/src/actions/actionCreators.js
  3. 278
      react/src/components/addcoin/addcoin.js
  4. 6
      react/src/components/addcoin/addcoinOptionsCrypto.js
  5. 1
      react/src/components/app/app.js
  6. 16
      react/src/components/dashboard/coinTileItem.js
  7. 49
      react/src/components/dashboard/settings.js
  8. 235
      react/src/components/dashboard/syncOnly.js
  9. 4
      react/src/components/dashboard/walletsBalance.js
  10. 53
      react/src/components/dashboard/walletsData.js
  11. 52
      react/src/components/dashboard/walletsNativeTxHistory.js
  12. 14
      react/src/components/login/login.js
  13. 96
      react/src/reducers/activeCoin.js
  14. 24
      react/src/reducers/errors.js
  15. 2
      react/src/reducers/index.js
  16. 21
      react/src/reducers/syncOnly.js
  17. 87
      react/src/styles/index.scss

1
.gitignore

@ -1 +0,0 @@
react

82
react/src/actions/actionCreators.js

@ -51,9 +51,16 @@ export const SYNC_ONLY_MODAL_TOGGLE = 'SYNC_ONLY_MODAL_TOGGLE';
export const SYNC_ONLY_DATA = 'SYNC_ONLY_DATA';
export const LOAD_APP_CONFIG = 'LOAD_APP_CONFIG';
export const SAVE_APP_CONFIG = 'SAVE_APP_CONFIG';
export const SERVICE_ERROR = 'SERVICE_ERROR';
var iguanaForks = {}; // forks in mem array
function updateErrosStack(method) {
return {
apiMethod: method,
}
}
export function toggleSyncOnlyModal(display) {
return {
type: SYNC_ONLY_MODAL_TOGGLE,
@ -607,6 +614,7 @@ export function iguanaActiveHandle(getMainAddress) {
})
.catch(function(error) {
console.log(error);
dispatch(updateErrosStack('activeHandle'));
dispatch(triggerToaster(true, translate('TOASTR.IGUANA_ARE_YOU_SURE'), translate('TOASTR.SERVICE_NOTIFICATION'), 'error'));
})
.then(response => response.json())
@ -771,7 +779,7 @@ export function getBasiliskTransactionsList(coin, address) {
'timeout': 60000
};
if (sessionStorage.getItem('useCache')) {
//if (sessionStorage.getItem('useCache')) {
const pubkey = JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey;
return dispatch => {
@ -787,13 +795,17 @@ export function getBasiliskTransactionsList(coin, address) {
})
.then(response => response.json())
.then(function(json) {
if (json.result && json.result.indexOf('no file with handle') > -1) {
console.log('new cache');
}
json = json.result.basilisk;
if (json[coin][address].listtransactions) {
dispatch(getNativeTxHistoryState({ 'result': json[coin][address].listtransactions.data }));
}
})
}
} else {
/*} else {
return dispatch => {
return fetch('http://127.0.0.1:' + (Config.useBasiliskInstance ? Config.basiliskPort : Config.iguanaCorePort), {
method: 'POST',
@ -806,7 +818,7 @@ export function getBasiliskTransactionsList(coin, address) {
.then(response => response.json())
.then(json => dispatch(getNativeTxHistoryState(json)))
}
}
}*/
}
export function getPeersList(coin) {
@ -923,6 +935,7 @@ export function getAddressesByAccount(coin, mode) {
})
.catch(function(error) {
console.log(error);
dispatch(updateErrosStack('activeHandle'));
dispatch(triggerToaster(true, 'getAddressesByAccount', 'Error', 'error'));
})
.then(response => response.json())
@ -1062,7 +1075,7 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
};
}
if (sessionStorage.getItem('useCache') && mode === 'basilisk') {
if (/*sessionStorage.getItem('useCache') &&*/ mode === 'basilisk') {
const pubkey = JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey;
fetch('http://127.0.0.1:' + Config.agamaPort + '/shepherd/cache?pubkey=' + pubkey, {
@ -1222,7 +1235,7 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
}));
}
if (sessionStorage.getItem('useCache') && mode === 'basilisk') {
if (/*sessionStorage.getItem('useCache') &&*/ mode === 'basilisk') {
const pubkey = JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey;
fetch('http://127.0.0.1:' + Config.agamaPort + '/shepherd/cache?pubkey=' + pubkey, {
@ -1328,14 +1341,26 @@ export function fetchUtxoCache(_payload) {
}
}
function getShepherdCacheState(json) {
return {
type: DASHBOARD_ACTIVE_COIN_GET_CACHE,
cache: json && json.result && json.result.basilisk ? json.result.basilisk : null,
function getShepherdCacheState(json, pubkey, coin) {
if (json.result && json.error && json.result.indexOf('no file with handle') > -1) {
console.log('new cache');
return dispatch => {
dispatch(fetchNewCacheData({
'pubkey': pubkey,
'allcoins': false,
'coin': coin,
'calls': 'listtransactions:getbalance:listunspent',
}));
}
} else {
return {
type: DASHBOARD_ACTIVE_COIN_GET_CACHE,
cache: json && json.result && json.result.basilisk ? json.result.basilisk : null,
}
}
}
export function getShepherdCache(pubkey) {
export function getShepherdCache(pubkey, coin) {
return dispatch => {
return fetch('http://127.0.0.1:' + Config.agamaPort + '/shepherd/cache?pubkey=' + pubkey, {
method: 'GET',
@ -1348,7 +1373,7 @@ export function getShepherdCache(pubkey) {
dispatch(triggerToaster(true, 'getShepherdCache', 'Error', 'error'));
})
.then(response => response.json())
.then(json => dispatch(getShepherdCacheState(json)))
.then(json => dispatch(getShepherdCacheState(json, pubkey, coin)))
}
}
@ -2521,6 +2546,41 @@ export function stopIguanaFork(pmid) {
}
}
export function shepherdGetCoinList() {
return new Promise((resolve, reject) => {
fetch('http://127.0.0.1:' + Config.agamaPort + '/shepherd/coinslist', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.catch(function(error) {
console.log(error);
dispatch(triggerToaster(true, 'shepherdGetCoinList', 'Error', 'error'));
})
.then(response => response.json())
.then(json => resolve(json))
});
}
export function shepherdPostCoinList(data) {
return new Promise((resolve, reject) => {
fetch('http://127.0.0.1:' + Config.agamaPort + '/shepherd/coinslist', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'payload': data }),
})
.catch(function(error) {
console.log(error);
dispatch(triggerToaster(true, 'shepherdPostCoinList', 'Error', 'error'));
})
.then(response => response.json())
.then(json => resolve(json))
});
}
/*function Shepherd_SendPendValue() {
Shepherd_SysInfo().then(function(result){
var ram_data = formatBytes(result.totalmem_bytes)

278
react/src/components/addcoin/addcoin.js

@ -1,6 +1,11 @@
import React from 'react';
import { translate } from '../../translate/translate';
import { addCoin, toggleAddcoinModal } from '../../actions/actionCreators';
import {
addCoin,
toggleAddcoinModal,
shepherdGetCoinList,
shepherdPostCoinList
} from '../../actions/actionCreators';
import Store from '../../store';
import AddCoinOptionsCrypto from './addcoinOptionsCrypto';
import AddCoinOptionsAC from './addcoinOptionsAC';
@ -10,39 +15,77 @@ class AddCoin extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedCoin: null,
fullMode: {
disabled: true,
checked: false,
},
basiliskMode: {
disabled: true,
checked: false,
},
nativeMode: {
disabled: true,
checked: false,
coins: [],
defaultCoinState: {
selectedCoin: null,
fullMode: {
disabled: true,
checked: false,
},
basiliskMode: {
disabled: true,
checked: false,
},
nativeMode: {
disabled: true,
checked: false,
},
mode: -2,
syncOnly: false,
},
mode: -2,
display: false,
syncOnly: false,
actionsMenu: false,
};
this.updateSelectedCoin = this.updateSelectedCoin.bind(this);
this.updateSelectedMode = this.updateSelectedMode.bind(this);
this.setNativeMode = this.setNativeMode.bind(this);
this.setBasiliskMode = this.setBasiliskMode.bind(this);
this.setFullMode = this.setFullMode.bind(this);
this.activateCoin = this.activateCoin.bind(this);
this.dismiss = this.dismiss.bind(this);
this.toggleSyncOnlyMode = this.toggleSyncOnlyMode.bind(this);
this.addNewItem = this.addNewItem.bind(this);
this.activateAllCoins = this.activateAllCoins.bind(this);
this.toggleActionsMenu = this.toggleActionsMenu.bind(this);
this.saveCoinSelection = this.saveCoinSelection.bind(this);
this.loadCoinSelection = this.loadCoinSelection.bind(this);
}
saveCoinSelection() {
shepherdPostCoinList(this.state.coins)
.then(function(json) {
console.log(json);
this.toggleActionsMenu();
}.bind(this));
}
loadCoinSelection() {
shepherdGetCoinList()
.then(function(json) {
console.log(json);
this.setState(Object.assign({}, this.state, {
coins: json.result,
actionsMenu: false,
}));
}.bind(this));
}
toggleSyncOnlyMode() {
toggleSyncOnlyMode(index) {
let _coins = this.state.coins;
_coins[index] = Object.assign({}, _coins[index], {
syncOnly: !this.state.coins[index].syncOnly,
});
this.setState(Object.assign({}, this.state, {
syncOnly: !this.state.syncOnly,
coins: _coins,
}));
}
toggleActionsMenu() {
this.setState(Object.assign({}, this.state, {
actionsMenu: !this.state.actionsMenu,
}));
}
componentWillMount() {
this.addNewItem();
}
componentWillReceiveProps(props) {
if (props) {
this.setState(Object.assign({}, this.state, {
@ -51,7 +94,7 @@ class AddCoin extends React.Component {
}
}
updateSelectedCoin(e) {
updateSelectedCoin(e, index) {
const coin = e.target.value.split('|');
const defaultMode = coin[1];
const modeToValue = {
@ -59,8 +102,9 @@ class AddCoin extends React.Component {
'basilisk': 0,
'native': -1,
};
let _coins = this.state.coins;
this.setState(Object.assign({}, this.state, {
_coins[index] = {
[e.target.name]: e.target.value,
fullMode: {
disabled: e.target.value.indexOf('full') > -1 ? false : true,
@ -75,11 +119,19 @@ class AddCoin extends React.Component {
checked: defaultMode === 'native' ? true : false,
},
mode: modeToValue[defaultMode] !== undefined ? modeToValue[defaultMode] : -2,
syncOnly: this.state.coins[index].syncOnly,
}
this.setState(Object.assign({}, this.state, {
coins: _coins
}));
}
updateSelectedMode(_value) {
this.setState(Object.assign({}, this.state, {
updateSelectedMode(_value, index) {
let _coins = this.state.coins;
_coins[index] = {
selectedCoin: _coins[index].selectedCoin,
fullMode: {
...this.state.fullMode,
checked: _value === '1' ? true : false,
@ -93,27 +145,121 @@ class AddCoin extends React.Component {
checked: _value === '-1' ? true : false,
},
mode: _value,
syncOnly: this.state.coins[index].syncOnly,
};
this.setState(Object.assign({}, this.state, {
coins: _coins
}));
console.log(this.state.coins);
}
activateCoin() {
Store.dispatch(addCoin(this.state.coins[0].selectedCoin.split('|')[0], this.state.coins[0].mode, this.state.coins[0].syncOnly));
}
setNativeMode() {
this.updateSelectedMode('-1');
dismiss() {
Store.dispatch(toggleAddcoinModal(false, false));
}
setBasiliskMode() {
this.updateSelectedMode('0');
addNewItem() {
let _coins = this.state.coins;
_coins.push(this.state.defaultCoinState);
this.setState(Object.assign({}, this.state, {
coins: _coins,
}));
}
setFullMode() {
this.updateSelectedMode('1');
removeCoin(index) {
let _coins = this.state.coins;
_coins.splice(index, 1);
this.setState(Object.assign({}, this.state, {
coins: _coins,
}));
}
activateCoin() {
Store.dispatch(addCoin(this.state.selectedCoin.split('|')[0], this.state.mode, this.state.syncOnly));
activateAllCoins() {
Store.dispatch(addCoin(this.state.coins[0].selectedCoin.split('|')[0], this.state.coins[0].mode, this.state.coins[0].syncOnly));
for (let i = 1; i < this.state.coins.length; i++) {
const _item = this.state.coins[i];
setTimeout(function() {
Store.dispatch(addCoin(_item.selectedCoin.split('|')[0], _item.mode, _item.syncOnly));
}, 2000 * i);
}
}
dismiss() {
Store.dispatch(toggleAddcoinModal(false, false));
renderCoinSelectors() {
let items = [];
for (let i = 0; i < this.state.coins.length; i++) {
const _item = this.state.coins[i];
const _coin = _item.selectedCoin || '';
items.push(
<div className={this.state.coins.length > 1 ? 'multi' : 'single'} key={'add-coin-' + i}>
<div className="col-sm-8">
<div className="form-group">
<select className="form-control form-material" name="selectedCoin" id="addcoin_select_coin_mdl_options-login" value={_coin} onChange={(event) => this.updateSelectedCoin(event, i)}>
<option>{translate('INDEX.SELECT')}</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
</div>
<div className={this.state.coins.length > 1 ? 'hide' : 'col-sm-4'}>
<button type="button" className="btn btn-primary mdl_addcoin_done_btn-login" data-toggle="modal" data-dismiss="modal" id="mdl_addcoin_done_btn-login" onClick={() => this.activateCoin(i)} disabled={_item.mode === -2 }>{translate('INDEX.ACTIVATE_COIN')}</button>
</div>
<div className="col-sm-12 text-center">
<div className="form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login">
<input type="radio" className="to-labelauty labelauty" name={`mode-${i}`} id={`addcoin_mdl_full_mode_login-${i}`} disabled={_item.fullMode.disabled} checked={_item.fullMode.checked} />
<label htmlFor={`addcoin_mdl_full_mode_login-${i}`} onClick={() => this.updateSelectedMode('1', i)} style={{ pointerEvents: _item.fullMode.disabled ? 'none' : 'all' }}>
<span className="labelauty-unchecked-image" style={{ display: _item.fullMode.checked ? 'none' : 'inline-block' }}></span>
<span className="labelauty-unchecked" style={{ display: _item.fullMode.checked ? 'none' : 'inline-block' }}>{translate('INDEX.FULL_MODE')}</span>
<span className="labelauty-checked-image" style={{ display: _item.fullMode.checked ? 'inline-block' : 'none' }}></span>
<span className="labelauty-checked" style={{ display: _item.fullMode.checked ? 'inline-block' : 'none' }}>{translate('INDEX.FULL_MODE')}</span>
</label>
</div>
<div className="form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login">
<input type="radio" className="to-labelauty labelauty" name={`mode-${i}`} id={`addcoin_mdl_basilisk_mode_login-${i}`} disabled={_item.basiliskMode.disabled} checked={_item.basiliskMode.checked} />
<label htmlFor={`addcoin_mdl_basilisk_mode_login-${i}`} onClick={() => this.updateSelectedMode('0', i)} style={{ pointerEvents: _item.basiliskMode.disabled ? 'none' : 'all' }}>
<span className="labelauty-unchecked-image" style={{ display: _item.basiliskMode.checked ? 'none' : 'inline-block' }}></span>
<span className="labelauty-unchecked" style={{ display: _item.basiliskMode.checked ? 'none' : 'inline-block' }}>{translate('INDEX.BASILISK_MODE')}</span>
<span className="labelauty-checked-image" style={{ display: _item.basiliskMode.checked ? 'inline-block' : 'none' }}></span>
<span className="labelauty-checked" style={{ display: _item.basiliskMode.checked ? 'inline-block' : 'none' }}>{translate('INDEX.BASILISK_MODE')}</span>
</label>
</div>
<div className="form-group col-lg-4 col-md-4 col-sm-12 col-xs-12 style-addcoin-lbl-mdl-login">
<input type="radio" className="to-labelauty labelauty" name={`mode-${i}`} id={`addcoin_mdl_native_mode_login-${i}`} disabled={_item.nativeMode.disabled} checked={_item.nativeMode.checked} />
<label htmlFor={`addcoin_mdl_native_mode_login-${i}`} onClick={() => this.updateSelectedMode('-1', i)} style={{ pointerEvents: _item.nativeMode.disabled ? 'none' : 'all' }}>
<span className="labelauty-unchecked-image" style={{ display: _item.nativeMode.checked ? 'none' : 'inline-block' }}></span>
<span className="labelauty-unchecked" style={{ display: _item.nativeMode.checked ? 'none' : 'inline-block' }}>{translate('INDEX.NATIVE_MODE')}</span>
<span className="labelauty-checked-image" style={{ display: _item.nativeMode.checked ? 'inline-block' : 'none' }}></span>
<span className="labelauty-checked" style={{ display: _item.nativeMode.checked ? 'inline-block' : 'none' }}>{translate('INDEX.NATIVE_MODE')}</span>
</label>
</div>
</div>
<div className={this.state.coins.length > 1 && i !== 0 ? 'col-sm-1' : 'hide'}>
<button type="button" className="btn btn-primary mdl_addcoin_done_btn-login" data-toggle="modal" data-dismiss="modal" id="mdl_addcoin_done_btn-login" onClick={() => this.removeCoin(i)}>
<i className="fa fa-trash-o"></i>
</button>
</div>
<div className={_item.mode === '1' || _item.mode === 1 ? 'col-sm-12' : 'hide'}>
<div className="pull-left margin-right-10">
<input type="checkbox" id="addcoin_sync_only" data-plugin="switchery" data-size="small" checked={_item.syncOnly} />
</div>
<label className="padding-top-3 padding-bottom-10" htmlFor="addcoin_sync_only" onClick={() => this.toggleSyncOnlyMode(i)}>Sync only</label>
</div>
</div>
);
}
return items;
}
render() {
@ -129,53 +275,17 @@ class AddCoin extends React.Component {
<h4 className="modal-title white">{translate('INDEX.SELECT_A_COIN')}</h4>
</div>
<div className="modal-body">
<div className="col-sm-8">
<div className="form-group">
<select className="form-control form-material" name="selectedCoin" id="addcoin_select_coin_mdl_options-login" onChange={this.updateSelectedCoin}>
<option>{translate('INDEX.SELECT')}</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
</div>
<div className="col-sm-4">
<button type="button" className="btn btn-primary mdl_addcoin_done_btn-login" data-toggle="modal" data-dismiss="modal" id="mdl_addcoin_done_btn-login" onClick={this.activateCoin} disabled={this.state.mode === -2 }>{translate('INDEX.ACTIVATE_COIN')}</button>
</div>
<div className="col-sm-12 text-center">
<div className="form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login">
<input type="radio" className="to-labelauty labelauty" name="mode" id="addcoin_mdl_full_mode_login" disabled={this.state.fullMode.disabled} checked={this.state.fullMode.checked} />
<label htmlFor="addcoin_mdl_full_mode_login" onClick={this.setFullMode} style={{ pointerEvents: this.state.fullMode.disabled ? 'none' : 'all' }}>
<span className="labelauty-unchecked-image" style={{ display: this.state.fullMode.checked ? 'none' : 'inline-block' }}></span>
<span className="labelauty-unchecked" style={{ display: this.state.fullMode.checked ? 'none' : 'inline-block' }}>{translate('INDEX.FULL_MODE')}</span>
<span className="labelauty-checked-image" style={{ display: this.state.fullMode.checked ? 'inline-block' : 'none' }}></span>
<span className="labelauty-checked" style={{ display: this.state.fullMode.checked ? 'inline-block' : 'none' }}>{translate('INDEX.FULL_MODE')}</span>
</label>
</div>
<div className="form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login">
<input type="radio" className="to-labelauty labelauty" name="mode" id="addcoin_mdl_basilisk_mode_login" disabled={this.state.basiliskMode.disabled} checked={this.state.basiliskMode.checked} />
<label htmlFor="addcoin_mdl_basilisk_mode_login" onClick={this.setBasiliskMode} style={{ pointerEvents: this.state.basiliskMode.disabled ? 'none' : 'all' }}>
<span className="labelauty-unchecked-image" style={{ display: this.state.basiliskMode.checked ? 'none' : 'inline-block' }}></span>
<span className="labelauty-unchecked" style={{ display: this.state.basiliskMode.checked ? 'none' : 'inline-block' }}>{translate('INDEX.BASILISK_MODE')}</span>
<span className="labelauty-checked-image" style={{ display: this.state.basiliskMode.checked ? 'inline-block' : 'none' }}></span>
<span className="labelauty-checked" style={{ display: this.state.basiliskMode.checked ? 'inline-block' : 'none' }}>{translate('INDEX.BASILISK_MODE')}</span>
</label>
</div>
<div className="form-group col-lg-4 col-md-4 col-sm-12 col-xs-12 style-addcoin-lbl-mdl-login">
<input type="radio" className="to-labelauty labelauty" name="mode" id="addcoin_mdl_native_mode_login" disabled={this.state.nativeMode.disabled} checked={this.state.nativeMode.checked} />
<label htmlFor="addcoin_mdl_native_mode_login" onClick={this.setNativeMode} style={{ pointerEvents: this.state.nativeMode.disabled ? 'none' : 'all' }}>
<span className="labelauty-unchecked-image" style={{ display: this.state.nativeMode.checked ? 'none' : 'inline-block' }}></span>
<span className="labelauty-unchecked" style={{ display: this.state.nativeMode.checked ? 'none' : 'inline-block' }}>{translate('INDEX.NATIVE_MODE')}</span>
<span className="labelauty-checked-image" style={{ display: this.state.nativeMode.checked ? 'inline-block' : 'none' }}></span>
<span className="labelauty-checked" style={{ display: this.state.nativeMode.checked ? 'inline-block' : 'none' }}>{translate('INDEX.NATIVE_MODE')}</span>
</label>
</div>
</div>
<div className={this.state.mode === 1 ? 'col-sm-12' : 'hide'}>
<div className="pull-left margin-right-10">
<input type="checkbox" id="addcoin_sync_only" data-plugin="switchery" data-size="small" />
</div>
<label className="padding-top-3 padding-bottom-10" htmlFor="addcoin_sync_only" onClick={this.toggleSyncOnlyMode}>Sync only</label>
<button className="btn btn-primary btn-add-coin-item" onClick={this.addNewItem}>+</button>
<button className="btn btn-outline-primary btn-add-coin-item-options" onClick={this.toggleActionsMenu}>
<i className={this.state.actionsMenu ? 'fa-chevron-up' : 'fa-chevron-down' }></i>
</button>
<span className={!this.state.actionsMenu ? 'hide' : ''}>
<button className="btn btn-outline-primary btn-save-coin-selection" onClick={this.saveCoinSelection}>Save Selection</button>
<button className="btn btn-outline-primary btn-load-coin-selection" onClick={this.loadCoinSelection}>Load Selection</button>
</span>
{this.renderCoinSelectors()}
<div className={this.state.coins.length > 1 ? 'col-sm-12' : 'hide'} style={{textAlign: 'center', margin: '20px 0'}}>
<button type="button" className="btn btn-primary col-sm-4" style={{float: 'none'}} data-toggle="modal" data-dismiss="modal" id="mdl_addcoin_done_btn-login" onClick={this.activateAllCoins}>Activate all</button>
</div>
<div className="col-sm-12">
<p>

6
react/src/components/addcoin/addcoinOptionsCrypto.js

@ -3,13 +3,13 @@ import { translate } from '../../translate/translate';
class AddCoinOptionsCrypto extends React.Component {
render() {
//<option value="ANC|full">AnonCoin (ANC)</option>
//<option value="MZC|full">MazaCoin (MZC)</option>
//<option value="SYS|full">SysCoin (SYS)</option>
return (
<optgroup label="Crypto Currencies">
<option value="BTCD|full">BitcoinDark (BTCD)</option>
<option value="BTC|full|basilisk">Bitcoin (BTC)</option>
<option value="ANC|full" data-full-mode="true">AnonCoin (ANC)</option>
<option value="MZC|full">MazaCoin (MZC)</option>
<option value="SYS|full">SysCoin (SYS)</option>
<option value="BTM|full">Bitmark (BTM)</option>
<option value="CARB|full">Carboncoin (CARB)</option>
<option value="DGB|full">Digibyte (DGB)</option>

1
react/src/components/app/app.js

@ -14,6 +14,7 @@ function mapStateToProps(state) {
Settings: state.Settings,
Interval: state.Interval,
SyncOnly: state.SyncOnly,
Errors: state.Errors,
};
}

16
react/src/components/dashboard/coinTileItem.js

@ -53,7 +53,7 @@ class CoinTileItem extends React.Component {
Store.dispatch(iguanaActiveHandle(true));
if (this.props && this.props.Dashboard && this.props.Dashboard.activeHandle && this.props.Dashboard.activeHandle[coin]) {
Store.dispatch(getShepherdCache(this.props.Dashboard.activeHandle.pubkey));
Store.dispatch(getShepherdCache(this.props.Dashboard.activeHandle.pubkey, coin));
Store.dispatch(getBasiliskTransactionsList(coin, useAddress));
Store.dispatch(getKMDAddressesNative(coin, mode, useAddress));
//Store.dispatch(iguanaEdexBalance(coin, mode));
@ -88,14 +88,12 @@ class CoinTileItem extends React.Component {
}.bind(this), 3000);
var _basiliskCache = setInterval(function() {
if (sessionStorage.getItem('useCache')) {
Store.dispatch(fetchNewCacheData({
'pubkey': this.props.Dashboard.activeHandle.pubkey,
'allcoins': false,
'coin': this.props.ActiveCoin.coin,
'calls': 'listtransactions:getbalance',
}));
}
Store.dispatch(fetchNewCacheData({
'pubkey': this.props.Dashboard.activeHandle.pubkey,
'allcoins': false,
'coin': this.props.ActiveCoin.coin,
'calls': 'listtransactions:getbalance',
}));
}.bind(this), 60000);
Store.dispatch(startInterval('sync', _iguanaActiveHandle));
Store.dispatch(startInterval('basilisk', _basiliskCache));

49
react/src/components/dashboard/settings.js

@ -28,6 +28,7 @@ class Settings extends React.Component {
activeTab: 0,
debugLinesCount: 10,
debugTarget: 'iguana',
activeTabHeight: '10px',
};
this.exportWifKeys = this.exportWifKeys.bind(this);
this.updateInput = this.updateInput.bind(this);
@ -43,9 +44,13 @@ class Settings extends React.Component {
Store.dispatch(iguanaActiveHandle());
}
openTab(tab) {
openTab(elemId, tab) {
console.log(elemId);
const _height = document.querySelector('#' + elemId + ' .panel-collapse .panel-body').clientHeight;
console.log(_height);
this.setState(Object.assign({}, this.state, {
activeTab: tab,
activeTabHeight: _height,
}));
}
@ -121,13 +126,13 @@ class Settings extends React.Component {
<div className="col-xlg-12 col-md-12">
<h4 className="font-size-14 text-uppercase">{translate('INDEX.WALLET_SETTINGS')}</h4>
<div className="panel-group" id="SettingsAccordion" aria-multiselectable="true" role="tablist">
<div className="panel">
<div className="panel-heading" id="WalletInfo" role="tab" onClick={() => this.openTab(0)}>
<div className="panel" id="WalletInfo">
<div className="panel-heading" role="tab" onClick={() => this.openTab('WalletInfo', 0)}>
<a className={this.state.activeTab === 0 ? 'panel-title' : 'panel-title collapsed'} data-toggle="collapse" data-parent="#SettingsAccordion">
<i className="icon md-balance-wallet" aria-hidden="true"></i>{translate('INDEX.WALLET_INFO')}
</a>
</div>
<div className={this.state.activeTab === 0 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} id="WalletInfoTab" aria-labelledby="WalletInfo" role="tabpanel">
<div className={this.state.activeTab === 0 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} style={{height: this.state.activeTab === 0 ? this.state.activeTabHeight + 'px' : '10px'}} id="WalletInfoTab" aria-labelledby="WalletInfo" role="tabpanel">
<div className="panel-body">
<table className="table" id="wallet-info-table">
<thead>
@ -179,13 +184,13 @@ class Settings extends React.Component {
</div>
</div>
<div className="panel">
<div className="panel-heading" id="AddNodeforCoin" role="tab" onClick={() => this.openTab(1)}>
<div className="panel" id="AddNodeforCoin">
<div className="panel-heading" role="tab" onClick={() => this.openTab('AddNodeforCoin', 1)}>
<a className={this.state.activeTab === 1 ? 'panel-title' : 'panel-title collapsed'} data-toggle="collapse" data-parent="#SettingsAccordion">
<i className="icon md-plus-square" aria-hidden="true"></i>{translate('INDEX.ADD_NODE')}
</a>
</div>
<div className={this.state.activeTab === 1 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} id="AddNodeforCoinTab" aria-labelledby="AddNodeforCoin" role="tabpanel">
<div className={this.state.activeTab === 1 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} style={{height: this.state.activeTab === 1 ? this.state.activeTabHeight + 'px' : '10px'}} id="AddNodeforCoinTab" aria-labelledby="AddNodeforCoin" role="tabpanel">
<div className="panel-body">
<div className="row">
<div className="col-sm-6">
@ -243,35 +248,35 @@ class Settings extends React.Component {
</div>
</div>
<div className="panel">
<div className="panel-heading" id="DumpWallet" role="tab" onClick={() => this.openTab(2)}>
<div className="panel" id="DumpWallet">
<div className="panel-heading" role="tab" onClick={() => this.openTab('DumpWallet', 2)}>
<a className={this.state.activeTab === 2 ? 'panel-title' : 'panel-title collapsed'} data-toggle="collapse" data-parent="#SettingsAccordion">
<i className="icon wb-briefcase" aria-hidden="true"></i>{translate('INDEX.WALLET_BACKUP')}
</a>
</div>
<div className={this.state.activeTab === 2 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} id="DumpWalletTab" aria-labelledby="DumpWallet" role="tabpanel">
<div className={this.state.activeTab === 2 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} style={{height: this.state.activeTab === 2 ? this.state.activeTabHeight + 'px' : '10px'}} id="DumpWalletTab" aria-labelledby="DumpWallet" role="tabpanel">
<div className="panel-body">Wallet Backup section to be updated soon.</div>
</div>
</div>
<div className="panel">
<div className="panel-heading" id="FiatCurrencySettings" role="tab" onClick={() => this.openTab(3)}>
<div className="panel" id="FiatCurrencySettings">
<div className="panel-heading" role="tab" onClick={() => this.openTab('FiatCurrencySettings', 3)}>
<a className={this.state.activeTab === 3 ? 'panel-title' : 'panel-title collapsed'} data-toggle="collapse" data-parent="#SettingsAccordion">
<i className="icon fa-money" aria-hidden="true"></i>{translate('INDEX.FIAT_CURRENCY')}
</a>
</div>
<div className={this.state.activeTab === 3 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} id="FiatCurrencySettingsTab" aria-labelledby="FiatCurrencySettings" role="tabpanel">
<div className={this.state.activeTab === 3 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} style={{height: this.state.activeTab === 3 ? this.state.activeTabHeight + 'px' : '10px'}} id="FiatCurrencySettingsTab" aria-labelledby="FiatCurrencySettings" role="tabpanel">
<div className="panel-body">Fiat currency settings section to be updated soon.</div>
</div>
</div>
<div className="panel">
<div className="panel-heading" id="ExportKeys" role="tab" onClick={() => this.openTab(4)}>
<div className="panel" id="ExportKeys">
<div className="panel-heading" role="tab" onClick={() => this.openTab('ExportKeys', 4)}>
<a className={this.state.activeTab === 4 ? 'panel-title' : 'panel-title collapsed'} data-toggle="collapse" data-parent="#SettingsAccordion">
<i className="icon md-key" aria-hidden="true"></i>{translate('INDEX.EXPORT_KEYS')}
</a>
</div>
<div className={this.state.activeTab === 4 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} id="ExportKeysTab" aria-labelledby="ExportKeys" role="tabpanel">
<div className={this.state.activeTab === 4 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} style={{height: this.state.activeTab === 4 ? this.state.activeTabHeight + 'px' : '10px'}} id="ExportKeysTab" aria-labelledby="ExportKeys" role="tabpanel">
<div className="panel-body">
<p>
<div>{translate('INDEX.ONLY_ACTIVE_WIF_KEYS')}</div><br/>
@ -312,13 +317,13 @@ class Settings extends React.Component {
</div>
</div>
<div className="panel">
<div className="panel-heading" id="ImportKeys" role="tab" onClick={() => this.openTab(5)}>
<div className="panel" id="ImportKeys">
<div className="panel-heading" role="tab" onClick={() => this.openTab('ImportKeys', 5)}>
<a className={this.state.activeTab === 5 ? 'panel-title' : 'panel-title collapsed'} data-toggle="collapse">
<i className="icon md-key" aria-hidden="true"></i>{translate('INDEX.IMPORT_KEYS')}
</a>
</div>
<div className={this.state.activeTab === 5 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} id="ImportKeysTab" aria-labelledby="ImportKeys" role="tabpanel">
<div className={this.state.activeTab === 5 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} style={{height: this.state.activeTab === 5 ? this.state.activeTabHeight + 'px' : '10px'}} id="ImportKeysTab" aria-labelledby="ImportKeys" role="tabpanel">
<div className="panel-body">
<p>
<div>{translate('INDEX.IMPORT_KEYS_DESC_P1')}</div><br/>
@ -347,13 +352,13 @@ class Settings extends React.Component {
</div>
</div>
<div className="panel">
<div className="panel-heading" id="DebugLog" role="tab" onClick={() => this.openTab(6)}>
<div className="panel" id="DebugLog">
<div className="panel-heading" role="tab" onClick={() => this.openTab('DebugLog', 6)}>
<a className={this.state.activeTab === 6 ? 'panel-title' : 'panel-title collapsed'} data-toggle="collapse" data-parent="#SettingsAccordion">
<i className="icon md-info" aria-hidden="true"></i>{translate('INDEX.DEBUG_LOG')}
</a>
</div>
<div className={this.state.activeTab === 6 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} id="DebugLogTab" aria-labelledby="DebugLog" role="tabpanel">
<div className={this.state.activeTab === 6 ? 'panel-collapse collapse in' : 'panel-collapse collapse'} style={{height: this.state.activeTab === 6 ? this.state.activeTabHeight + 'px' : '10px'}} id="DebugLogTab" aria-labelledby="DebugLog" role="tabpanel">
<div className="panel-body">
<p>{translate('INDEX.DEBUG_LOG_DESC')}</p>
<div className="col-sm-12"></div>

235
react/src/components/dashboard/syncOnly.js

@ -0,0 +1,235 @@
import React from 'react';
import { translate } from '../../translate/translate';
import {
toggleSyncOnlyModal,
stopInterval,
stopIguanaFork,
restartIguanaInstance,
addCoin
} from '../../actions/actionCreators';
import Store from '../../store';
class SyncOnly extends React.Component {
constructor(props) {
super(props);
this.closeSyncOnlyModal = this.closeSyncOnlyModal.bind(this);
}
isFullySynced(fork) {
if (fork.balances && ((Number(fork.balances) +
Number(fork.validated) +
Number(fork.bundles) +
Number(fork.utxo)) / 4 === 100)) {
return true;
} else {
return false;
}
}
renderCoinName(coin) {
let coinlogo;
let coinname;
switch (coin) {
case 'BTC':
coinlogo = 'bitcoin';
coinname = 'Bitcoin';
break;
case 'BTCD':
coinlogo = 'bitcoindark';
coinname = 'BitcoinDark';
break;
case 'LTC':
coinlogo = 'litecoin';
coinname = 'Litecoin';
break;
case 'VPN':
coinlogo = 'vpncoin';
coinname = 'VPNcoin';
break;
case 'SYS':
coinlogo = 'syscoin';
coinname = 'Syscoin';
break;
case 'ZEC':
coinlogo = 'zcash';
coinname = 'Zcash';
break;
case 'NMC':
coinlogo = 'namecoin';
coinname = 'Namecoin';
break;
case 'DEX':
coinlogo = 'dex';
coinname = 'InstantDEX';
break;
case 'DOGE':
coinlogo = 'dogecoin';
coinname = 'Dogecoin';
break;
case 'DGB':
coinlogo = 'digibyte';
coinname = 'Digibyte';
break;
case 'MZC':
coinlogo = 'mazacoin';
coinname = 'Mazacoin';
break;
case 'UNO':
coinlogo = 'unobtanium';
coinname = 'Unobtanium';
break;
case 'ZET':
coinlogo = 'zetacoin';
coinname = 'Zetacoin';
break;
case 'KMD':
coinlogo = 'komodo';
coinname = 'Komodo';
break;
case 'BTM':
coinlogo = 'bitmark';
coinname = 'Bitmark';
break;
case 'CARB':
coinlogo = 'carboncoin';
coinname = 'Carboncoin';
break;
case 'ANC':
coinlogo = 'anoncoin';
coinname = 'AnonCoin';
break;
case 'FRK':
coinlogo = 'franko';
coinname = 'Franko';
break;
case 'GAME':
coinlogo = 'GAME';
coinname = 'GameCredits';
break;
}
return {
'logo': coinlogo,
'name': coinname
};
}
closeSyncOnlyModal() {
Store.dispatch(stopInterval('syncOnly', this.props.Interval.interval));
Store.dispatch(toggleSyncOnlyModal(false));
}
_stopIguanaFork(pmid) {
Store.dispatch(stopIguanaFork(pmid));
}
_restartIguanaFork(coin, pmid, port) {
restartIguanaInstance(pmid)
.then(function(json) {
setTimeout(function() {
Store.dispatch(addCoin(coin, '1', null, port));
console.log('restartSyncOnlyInstance', json);
}, 2000);
});
}
renderProgress(fork) {
return (
<div>
<div>
<div className="progress progress-sm">
<div className={this.isFullySynced(fork) ? 'progress-bar progress-bar-striped active progress-bar-indicating progress-bar-success' : 'hide'} style={{width: '100%', fontSize: '80%'}} role="progressbar" id="currency-bundles">
{translate('INDEX.BUNDLES')} <span data-edexcoin="GAME" id="currency-bundles-percent">({fork.coin}) 100.00% - ( {fork.blocks} / {fork.blocks} ) ==&gt;&gt; RT{fork.RTheight}</span>
</div>
<div className={this.isFullySynced(fork) ? 'hide' : 'progress-bar progress-bar-info progress-bar-striped active'} style={{width: fork.bundles + '%', fontSize: '80%'}} role="progressbar" data-edexcoin="COIN" id="currency-bundles">
{translate('INDEX.BUNDLES')} <span data-edexcoin="COIN" id="currency-bundles-percent">{fork.bundles}%</span>
</div>
</div>
</div>
<div data-edexcoin="COIN" id="additional-progress-bars" className={this.isFullySynced(fork) ? 'hide' : ''}>
<div className="progress progress-sm">
<div className="progress-bar progress-bar-warning progress-bar-striped active" style={{width: fork.utxo + '%', fontSize: '80%'}} role="progressbar" data-edexcoin="COIN" id="currency-utxo">
utxo <span data-edexcoin="COIN" id="currency-utxo-percent">{fork.utxo}%</span>
</div>
</div>
<div className="progress progress-sm">
<div className="progress-bar progress-bar-danger progress-bar-striped active" style={{width: fork.balances + '%', fontSize: '80%'}} role="progressbar" data-edexcoin="COIN" id="currency-balances">
{translate('INDEX.BALANCES')} <span data-edexcoin="COIN" id="currency-balances-percent">{fork.balances}%</span>
</div>
</div>
<div className="progress progress-sm">
<div className="progress-bar progress-bar-success progress-bar-striped active" style={{width: fork.validated + '%', fontSize: '80%'}} role="progressbar" data-edexcoin="COIN" id="currency-validated">
{translate('INDEX.VALIDATED')} <span data-edexcoin="COIN" id="currency-validated-percent">{fork.validated}%</span>
</div>
</div>
</div>
</div>
);
}
renderForksList() {
let items = [];
for (let port in this.props.SyncOnly.forks) {
const forkInfo = this.props.SyncOnly.forks[port];
if (forkInfo && forkInfo.registry && forkInfo.getinfo) {
items.push(
<div key={port} style={{width: '100%'}} className="padding-bottom-60">
<div className="avatar" href="javascript:void(0)">
<img className="img-responsive margin-bottom-5" src={'assets/images/cryptologo/' + this.renderCoinName(forkInfo.registry.coin).logo + '.png'} alt="{forkInfo.registry.coin}"/>
<span className="badge up badge-success margin-bottom-5" data-toggle="tooltip" data-placement="top" data-original-title="full">Full</span>
<div className="coin-name">{this.renderCoinName(forkInfo.registry.coin).name} ({forkInfo.registry.coin.toUpperCase()})</div>
<div className="margin-top-10">
<span className="btn btn-primary" onClick={() => this._stopIguanaFork(forkInfo.registry.pmid)}>
<span className="fa fa-stop"></span> Stop
</span>
<span className="btn btn-primary margin-left-10" onClick={() => this._restartIguanaFork(forkInfo.registry.coin.toUpperCase(), forkInfo.registry.pmid, port)}>
<span className="fa fa-undo"></span> Restart
</span>
</div>
</div>
<div className="progress-bars">
{this.renderProgress(forkInfo.getinfo)}
</div>
</div>
);
}
}
if (items.length) {
return items;
} else {
return (
<div>Loading...</div>
);
}
}
render() {
if (this.props && this.props.SyncOnly.display) {
return (
<div>
<div className="modal show sync-only-forks" aria-hidden="false" role="dialog">
<div className="modal-dialog modal-center modal-lg">
<div className="modal-content">
<div className="modal-body" style={{height: '590px'}}>
{this.renderForksList()}
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" onClick={this.closeSyncOnlyModal}>Close</button>
</div>
</div>
</div>
</div>
<div className="modal-backdrop show in"></div>
</div>
);
} else {
return null;
}
}
}
export default SyncOnly;

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

@ -4,11 +4,11 @@ import { translate } from '../../translate/translate';
class WalletsBalance extends React.Component {
constructor(props) {
super(props);
this.isFullySynced = this.isFullySynced.bind(bind);
this.isFullySynced = this.isFullySynced.bind(this);
}
isFullySynced() {
if ((Number(this.props.Dashboard.progress.balances) +
if (this.props.Dashboard.progress && (Number(this.props.Dashboard.progress.balances) +
Number(this.props.Dashboard.progress.validated) +
Number(this.props.Dashboard.progress.bundles) +
Number(this.props.Dashboard.progress.utxo)) / 4 === 100) {

53
react/src/components/dashboard/walletsData.js

@ -173,7 +173,7 @@ class WalletsData extends React.Component {
}
componentWillReceiveProps(props) {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length) {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory !== 'loading' && this.props.ActiveCoin.txhistory !== 'no data' && this.props.ActiveCoin.txhistory.length) {
if (!this.state.itemsList || (this.state.itemsList && !this.state.itemsList.length) || (props.ActiveCoin.txhistory !== this.props.ActiveCoin.txhistory)) {
let historyToSplit = sortByDate(this.props.ActiveCoin.txhistory);
historyToSplit = historyToSplit.slice((this.state.activePage - 1) * this.state.itemsPerPage, this.state.activePage * this.state.itemsPerPage);
@ -188,6 +188,10 @@ class WalletsData extends React.Component {
this.setState(Object.assign({}, this.state, {
itemsList: 'no data',
}));
} else if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory === 'loading') {
this.setState(Object.assign({}, this.state, {
itemsList: 'loading',
}));
}
}
@ -216,7 +220,7 @@ class WalletsData extends React.Component {
}
renderPaginationItemsPerPageSelector() {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length > 10) {
if (this.props.ActiveCoin.txhistory && this.state.itemsList !== 'loading' && this.props.ActiveCoin.txhistory.length > 10) {
return (
<div className="dataTables_length" id="kmd-tx-history-tbl_length">
<label>
@ -237,7 +241,7 @@ class WalletsData extends React.Component {
}
renderPagination() {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length > 10) {
if (this.props.ActiveCoin.txhistory && this.state.itemsList !== 'loading' && this.props.ActiveCoin.txhistory.length > 10) {
return (
<div className="row unselectable">
<div className="col-sm-5">
@ -302,29 +306,25 @@ class WalletsData extends React.Component {
}
renderTxHistoryList() {
if (this.state.itemsList && this.state.itemsList.length && this.state.itemsList !== 'no data') {
return this.state.itemsList.map((tx, index) =>
<tr key={tx.txid + tx.amount}>
<td>{this.renderTxType(tx.category || tx.type)}</td>
<td>{tx.confirmations}</td>
<td>{tx.amount || translate('DASHBOARD.UNKNOWN')}</td>
<td>{secondsToString(tx.blocktime || tx.timestamp)}</td>
<td>{tx.address}</td>
<td>
<button type="button" className="btn btn-xs white btn-info waves-effect waves-light btn-kmdtxid" onClick={() => this.toggleTxInfoModal(!this.props.ActiveCoin.showTransactionInfo, index)}><i className="icon fa-search"></i></button>
</td>
</tr>
);
}
if (this.state.itemsList === 'no data') {
if (this.state.itemsList === 'loading') {
return (
<span>No data</span>
<div>Loading history...</div>
);
}
if (!this.state.itemsList) {
return null;
} else {
if (this.state.itemsList && this.state.itemsList.length && this.state.itemsList !== 'no data') {
return this.state.itemsList.map((tx, index) =>
<tr key={tx.txid + tx.amount}>
<td>{this.renderTxType(tx.category || tx.type)}</td>
<td>{tx.confirmations}</td>
<td>{tx.amount || translate('DASHBOARD.UNKNOWN')}</td>
<td>{secondsToString(tx.blocktime || tx.timestamp)}</td>
<td>{tx.address}</td>
<td>
<button type="button" className="btn btn-xs white btn-info waves-effect waves-light btn-kmdtxid" onClick={() => this.toggleTxInfoModal(!this.props.ActiveCoin.showTransactionInfo, index)}><i className="icon fa-search"></i></button>
</td>
</tr>
);
}
}
}
@ -405,7 +405,10 @@ class WalletsData extends React.Component {
}
renderAddressList() {
if (this.props.Dashboard && this.props.Dashboard.activeHandle && this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] && this.props.ActiveCoin.mode === 'basilisk') {
if (this.props.Dashboard &&
this.props.Dashboard.activeHandle &&
this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] &&
this.props.ActiveCoin.mode === 'basilisk') {
return (
<div className={'btn-group bootstrap-select form-control form-material showkmdwalletaddrs show-tick ' + (this.state.addressSelectorOpen ? 'open' : '')}>
<button type="button" className="btn dropdown-toggle btn-info" data-toggle="dropdown" data-id="kmd_wallet_send_from" title="- Select Transparent or Private Address -" aria-expanded="true" onClick={this.openDropMenu}>

52
react/src/components/dashboard/walletsNativeTxHistory.js

@ -81,7 +81,7 @@ class WalletsNativeTxHistory extends React.Component {
componentWillReceiveProps(props) {
if (!this.state.itemsList || (this.state.itemsList && !this.state.itemsList.length) || (props.ActiveCoin.txhistory !== this.props.ActiveCoin.txhistory)) {
if (this.props.ActiveCoin.txhistory) {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory !== 'loading') {
let historyToSplit = sortByDate(this.props.ActiveCoin.txhistory);
historyToSplit = historyToSplit.slice((this.state.activePage - 1) * this.state.itemsPerPage, this.state.activePage * this.state.itemsPerPage);
@ -117,7 +117,7 @@ class WalletsNativeTxHistory extends React.Component {
}
renderPaginationItemsPerPageSelector() {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length > 10) {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory !== 'loading' && this.props.ActiveCoin.txhistory.length > 10) {
return (
<div className="dataTables_length" id="kmd-tx-history-tbl_length">
<label>
@ -138,7 +138,7 @@ class WalletsNativeTxHistory extends React.Component {
}
renderPagination() {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length > 10) {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory !== 'loading' && this.props.ActiveCoin.txhistory.length > 10) {
return (
<div className="row unselectable">
<div className="col-sm-5">
@ -165,26 +165,32 @@ class WalletsNativeTxHistory extends React.Component {
}
renderTxHistoryList() {
if (this.state.itemsList && this.state.itemsList.length && this.props.ActiveCoin.nativeActiveSection === 'default') {
return this.state.itemsList.map((tx, index) =>
<tr key={tx.txid + tx.amount}>
<td>
<span className="label label-default">
<i className="icon fa-eye"></i> {translate('IAPI.PUBLIC_SM')}
</span>
</td>
<td>{this.renderTxType(tx.category)}</td>
<td>{tx.confirmations}</td>
<td>{tx.amount}</td>
<td>{secondsToString(tx.time)}</td>
<td>{this.renderAddress(tx)}</td>
<td>
<button type="button" className="btn btn-xs white btn-info waves-effect waves-light btn-kmdtxid" onClick={() => this.toggleTxInfoModal(!this.props.ActiveCoin.showTransactionInfo, index)}><i className="icon fa-search"></i></button>
</td>
</tr>
);
} else {
return null;
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory === 'no data') {
return 'no data';
} else if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory === 'loading') {
return 'loading history...';
} else if (this.props.ActiveCoin.txhistory && (this.props.ActiveCoin.txhistory !== 'loading' && this.props.ActiveCoin.txhistory !== 'no data')) {
if (this.state.itemsList && this.state.itemsList.length && this.props.ActiveCoin.nativeActiveSection === 'default') {
return this.state.itemsList.map((tx, index) =>
<tr key={tx.txid + tx.amount}>
<td>
<span className="label label-default">
<i className="icon fa-eye"></i> {translate('IAPI.PUBLIC_SM')}
</span>
</td>
<td>{this.renderTxType(tx.category)}</td>
<td>{tx.confirmations}</td>
<td>{tx.amount}</td>
<td>{secondsToString(tx.time)}</td>
<td>{this.renderAddress(tx)}</td>
<td>
<button type="button" className="btn btn-xs white btn-info waves-effect waves-light btn-kmdtxid" onClick={() => this.toggleTxInfoModal(!this.props.ActiveCoin.showTransactionInfo, index)}><i className="icon fa-search"></i></button>
</td>
</tr>
);
} else {
return null;
}
}
}

14
react/src/components/login/login.js

@ -7,7 +7,9 @@ import {
iguanaActiveHandle,
toggleSyncOnlyModal,
startInterval,
getSyncOnlyForks
stopInterval,
getSyncOnlyForks,
getDexCoins
} from '../../actions/actionCreators';
import Store from '../../store';
import { PassPhraseGenerator } from '../../util/crypto/passphrasegenerator';
@ -66,11 +68,21 @@ class Login extends React.Component {
this.setState({
display: false,
});
// Store.dispatch(stopInterval('activeCoins', this.props.Interval.interval));
}
if (props && props.Main && !props.Main.isLoggedIn) {
this.setState({
display: true,
});
if (!this.props.Interval.interval.activeCoins) {
var _iguanaActiveCoins = setInterval(function() {
Store.dispatch(getDexCoins());
}.bind(this), 10000);
Store.dispatch(startInterval('activeCoins', _iguanaActiveCoins));
}
document.body.className = 'page-login layout-full page-dark';
}
if (this.state.activeLoginSection !== 'signup') {

96
react/src/reducers/activeCoin.js

@ -17,9 +17,10 @@ import {
DASHBOARD_DISPLAY_NOTARIES_MODAL
} from '../actions/actionCreators';
// TODO: keep all coin data in array of objects instead of single object
// TODO: refactor
export function ActiveCoin(state = {
coins: {},
coin: null,
mode: null,
send: false,
@ -38,17 +39,88 @@ export function ActiveCoin(state = {
}, action) {
switch (action.type) {
case DASHBOARD_ACTIVE_COIN_CHANGE:
return Object.assign({}, state, {
coin: action.coin,
mode: action.mode,
balance: 0,
txhistory: [],
send: false,
receive: false,
showTransactionInfo: false,
showTransactionInfoTxIndex: null,
nativeActiveSection: 'default',
});
if (state.coins[action.coin]) {
const _coinData = state.coins[action.coin];
const _coinDataToStore = {
addresses: state.addresses,
coin: state.coin,
mode: state.mode,
balance: state.balance,
txhistory: state.txhistory,
send: state.send,
receive: state.receive,
showTransactionInfo: state.showTransactionInfo,
showTransactionInfoTxIndex: state.showTransactionInfoTxIndex,
nativeActiveSection: state.nativeActiveSection,
lastSendToResponse: state.lastSendToResponse,
mainBasiliskAddress: state.mainBasiliskAddress,
opids: state.opids,
};
let _coins = state.coins;
_coins[state.coin] = _coinDataToStore;
return Object.assign({}, state, {
coins: _coins,
addresses: _coinData.addresses,
coin: _coinData.coin,
mode: _coinData.mode,
balance: _coinData.balance,
txhistory: _coinData.txhistory,
send: _coinData.send,
receive: _coinData.receive,
showTransactionInfo: _coinData.showTransactionInfo,
showTransactionInfoTxIndex: _coinData.showTransactionInfoTxIndex,
nativeActiveSection: _coinData.nativeActiveSection,
lastSendToResponse: _coinData.lastSendToResponse,
mainBasiliskAddress: _coinData.mainBasiliskAddress,
opids: _coinData.opids,
});
} else {
if (state.coin) {
const _coinData = {
addresses: state.addresses,
coin: state.coin,
mode: state.mode,
balance: state.balance,
txhistory: state.txhistory,
send: state.send,
receive: state.receive,
showTransactionInfo: state.showTransactionInfo,
showTransactionInfoTxIndex: state.showTransactionInfoTxIndex,
nativeActiveSection: state.nativeActiveSection,
lastSendToResponse: state.lastSendToResponse,
mainBasiliskAddress: state.mainBasiliskAddress,
opids: state.opids,
};
let _coins = state.coins;
_coins[state.coin] = _coinData;
return Object.assign({}, state, {
coins: _coins,
coin: action.coin,
mode: action.mode,
balance: 0,
txhistory: 'loading',
send: false,
receive: false,
showTransactionInfo: false,
showTransactionInfoTxIndex: null,
nativeActiveSection: 'default',
});
} else {
return Object.assign({}, state, {
coin: action.coin,
mode: action.mode,
balance: 0,
txhistory: 'loading',
send: false,
receive: false,
showTransactionInfo: false,
showTransactionInfoTxIndex: null,
nativeActiveSection: 'default',
});
}
}
case DASHBOARD_ACTIVE_COIN_BALANCE:
return Object.assign({}, state, {
balance: action.balance,

24
react/src/reducers/errors.js

@ -0,0 +1,24 @@
import { SERVICE_ERROR } from '../actions/actionCreators';
export function Errors(state = {
errors: {},
}, action) {
switch (action.type) {
case SERVICE_ERROR:
let _errors = Object.assign({}, state);
if (_errors[action.apiMethod]) {
_errors[action.apiMethod]++;
} else {
_errors[action.apiMethod] = 1;
}
return Object.assign({}, state, {
errors: _errors,
});
default:
return state;
}
}
export default Errors;

2
react/src/reducers/index.js

@ -10,6 +10,7 @@ import { Atomic } from './atomic';
import { Settings } from './settings';
import { Interval } from './interval';
import { SyncOnly } from './syncOnly';
import { Errors } from './errors';
const rootReducer = combineReducers({
AddCoin,
@ -21,6 +22,7 @@ const rootReducer = combineReducers({
Settings,
Interval,
SyncOnly,
Errors,
routing: routerReducer,
});

21
react/src/reducers/syncOnly.js

@ -0,0 +1,21 @@
import { SYNC_ONLY_MODAL_TOGGLE, SYNC_ONLY_DATA } from '../actions/actionCreators';
export function SyncOnly(state = {
display: false,
forks: null
}, action) {
switch (action.type) {
case SYNC_ONLY_MODAL_TOGGLE:
return Object.assign({}, state, {
display: action.display,
});
case SYNC_ONLY_DATA:
return Object.assign({}, state, {
forks: action.forks,
});
default:
return state;
}
}
export default SyncOnly;

87
react/src/styles/index.scss

@ -161,17 +161,82 @@ body {
color: #ffa726;
}
.btn-add-coin-item,
.btn-add-coin-item-options,
.btn-save-coin-selection,
.btn-load-coin-selection {
position: absolute;
right: 32px;
z-index: 50;
}
.btn-add-coin-item {
right: 60px;
}
.btn-add-coin-item-options {
padding: 6px;
}
.btn-save-coin-selection {
top: 60px;
}
.btn-load-coin-selection {
top: 95px;
}
.btn-outline-primary {
color: #FF6600;
background-color: #fff;
border-color: #FF6600;
}
.add-coin-modal {
.modal-body {
max-height: 590px;
overflow-y: auto;
}
.multi {
.col-sm-8 {
width: 30%;
}
.col-sm-12 {
&.text-center {
width: 60%;
padding: 0;
.col-lg-4 {
width: 25%;
margin-right: 8%;
padding: 0;
.input.to-labelauty+label {
max-width: 136px;
}
}
.col-lg-4:last-child {
margin-right: 0;
}
.col-sm-1 {
width: 44px;
padding: 0;
}
}
}
}
}
.sync-only-forks {
color: #757575;
.modal-body {
overflow-y: auto;
}
.badge.up {
position: absolute;
top: 40px;
left: 65px;
margin: 0 5px;
.badge{
&.up {
position: absolute;
top: 40px;
left: 65px;
margin: 0 5px;
}
}
.avatar {
width: 20%;
@ -195,6 +260,18 @@ body {
}
}
#SettingsAccordion {
.panel {
.panel-collapse {
transition: all .3s;
&.collapse {
height: 10px;
}
}
}
}
/*.toaster .single-toast:nth-child(0) {
bottom: 12px;
}

Loading…
Cancel
Save