diff --git a/react/src/actions/actionCreators.js b/react/src/actions/actionCreators.js index f30361e..c9fc0f2 100644 --- a/react/src/actions/actionCreators.js +++ b/react/src/actions/actionCreators.js @@ -625,6 +625,42 @@ export function getPeersListState(json) { } } +/*params = { + 'userpass': tmpIguanaRPCAuth, + 'agent': 'dex', + 'method': 'listtransactions', + 'address': coinaddr_value, + 'count': 100, + 'skip': 0, + 'symbol': coin +};*/ + +export function getFullTransactionsList(coin) { + const payload = { + 'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'), + 'coin': coin, + 'method': 'listtransactions', + 'params': [ + 0, + 9999999, + [] + ] + }; + + return dispatch => { + return fetch('http://127.0.0.1:' + Config.iguanaCorePort, { + method: 'POST', + body: JSON.stringify(payload), + }) + .catch(function(error) { + console.log(error); + dispatch(triggerToaster(true, 'getFullTransactionsList', 'Error', 'error')); + }) + .then(response => response.json()) + .then(json => dispatch(getNativeTxHistoryState(json))) + } +} + export function getPeersList(coin) { const payload = { 'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'), @@ -772,7 +808,15 @@ export function stopInterval(name, intervals) { } } +// TODO: add custom json parser function getSyncInfoState(json) { + try { + JSON.parse(json); + json = JSON.parse(json); + } catch(e) { + // + } + return { type: SYNCING_FULL_MODE, progress: json, @@ -798,8 +842,16 @@ export function getSyncInfo(coin) { console.log(error); dispatch(triggerToaster(true, 'getSyncInfo', 'Error', 'error')); }) - .then(response => response.json()) - .then(json => dispatch(getSyncInfoState(json, dispatch))) + .then(function(response) { + const _response = response.text().then(function(text) { return text; }); + + return _response; + }) + .then(function(json) { + if (json.indexOf('coin is busy processing') === -1) { + dispatch(getSyncInfoState(json, dispatch)); + } + }) } } @@ -1225,9 +1277,15 @@ export function getNativeTxHistory(coin) { } export function getNativeTxHistoryState(json) { + if (json && json.error) { + json = null; + } else if (json && json.result) { + json = json.result; + } + return { type: DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY, - txhistory: json && !json.error ? json : 0, + txhistory: json, } } diff --git a/react/src/components/addcoin/addcoinOptionsCrypto.js b/react/src/components/addcoin/addcoinOptionsCrypto.js index 4f14c5a..df64b39 100644 --- a/react/src/components/addcoin/addcoinOptionsCrypto.js +++ b/react/src/components/addcoin/addcoinOptionsCrypto.js @@ -13,7 +13,7 @@ class AddCoinOptionsCrypto extends React.Component { - + diff --git a/react/src/components/addcoin/payload.js b/react/src/components/addcoin/payload.js index 3cf9a53..6ead715 100644 --- a/react/src/components/addcoin/payload.js +++ b/react/src/components/addcoin/payload.js @@ -131,7 +131,7 @@ export function checkCoinType(coin) { export function startCrypto(confpath, coin, mode) { var tmpinternval = 0, AddCoinData = {}, - tmpPendValue, + tmpPendValue = 4, // TODO: hook up to shepherd sysinfo tmpIguanaRPCAuth = 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'); if (coin !== 'BTC' && coin !== 'LTC' && coin !== 'DOGE') { diff --git a/react/src/components/dashboard/coinTileItem.js b/react/src/components/dashboard/coinTileItem.js index 2da45c3..bdc9c06 100644 --- a/react/src/components/dashboard/coinTileItem.js +++ b/react/src/components/dashboard/coinTileItem.js @@ -12,7 +12,8 @@ import { getKMDBalanceTotal, getNativeTxHistory, getKMDAddressesNative, - getKMDOPID + getKMDOPID, + getFullTransactionsList } from '../../actions/actionCreators'; import Store from '../../store'; @@ -24,37 +25,37 @@ class CoinTileItem extends React.Component { } dashboardChangeActiveCoin(coin, mode) { - if (mode === 'full' && coin !== this.props.ActiveCoin.coin) { + if (coin !== this.props.ActiveCoin.coin) { Store.dispatch(stopInterval('sync', this.props.Interval.interval)); - var _iguanaActiveHandle = setInterval(function() { - Store.dispatch(getSyncInfo(coin)); - Store.dispatch(iguanaEdexBalance(coin, mode)); + Store.dispatch(dashboardChangeActiveCoin(coin, mode)); + + if (mode === 'full') { + var _iguanaActiveHandle = setInterval(function() { + Store.dispatch(getSyncInfo(coin)); + Store.dispatch(iguanaEdexBalance(coin, mode)); + Store.dispatch(getAddressesByAccount(coin)); + Store.dispatch(getFullTransactionsList(coin)); + }, 3000); + Store.dispatch(startInterval('sync', _iguanaActiveHandle)); + } + if (mode === 'native') { + // TODO: add conditions to skip txhistory, balances, addresses while "activating best chain" + var _iguanaActiveHandle = setInterval(function() { + Store.dispatch(getSyncInfoNative(coin)); + Store.dispatch(getKMDBalanceTotal(coin)); + Store.dispatch(getNativeTxHistory(coin)); + Store.dispatch(getKMDAddressesNative(coin)); + Store.dispatch(getKMDOPID(null, coin)); + }, coin === 'KMD' ? 15000 : 3000); + Store.dispatch(startInterval('sync', _iguanaActiveHandle)); + } + if (mode === 'basilisk') { Store.dispatch(getAddressesByAccount(coin)); - }, 3000); - Store.dispatch(startInterval('sync', _iguanaActiveHandle)); - } else if (mode === 'native' && coin !== this.props.ActiveCoin.coin) { - Store.dispatch(stopInterval('sync', this.props.Interval.interval)); - // TODO: add conditions to skip txhistory, balances, addresses while "activating best chain" - var _iguanaActiveHandle = setInterval(function() { - Store.dispatch(getSyncInfoNative(coin)); - Store.dispatch(getKMDBalanceTotal(coin)); - Store.dispatch(getNativeTxHistory(coin)); - Store.dispatch(getKMDAddressesNative(coin)); - Store.dispatch(getKMDOPID(null, coin)); - }, coin === 'KMD' ? 15000 : 3000); - Store.dispatch(startInterval('sync', _iguanaActiveHandle)); - } else { - Store.dispatch(stopInterval('sync', this.props.Interval.interval)); - Store.dispatch(getAddressesByAccount(coin)); - // basilisk + // basilisk + } } - Store.dispatch(dashboardChangeActiveCoin(coin, mode)); Store.dispatch(iguanaActiveHandle(true)); - - /*this.setState(Object.assign({}, this.state, { - activeHandleInterval: _iguanaActiveHandle, - }));*/ } render() { diff --git a/react/src/components/dashboard/walletsBalance.js b/react/src/components/dashboard/walletsBalance.js index d84127d..2730435 100644 --- a/react/src/components/dashboard/walletsBalance.js +++ b/react/src/components/dashboard/walletsBalance.js @@ -3,7 +3,7 @@ import { translate } from '../../translate/translate'; class WalletsBalance extends React.Component { render() { - if (this.props && this.props.coin && this.props.mode !== 'native') { + if (this.props && this.props.coin && this.props.mode !== 'native' && this.props.balance && !this.props.send && !this.props.receive) { return (
@@ -37,7 +37,7 @@ class WalletsBalance extends React.Component { {translate('INDEX.BALANCE')}
- {this.props && this.props.ActiveCoin && this.props.ActiveCoin.balance ? this.props.ActiveCoin.balance : 0} + {this.props && this.props.balance ? this.props.balance : 0}
diff --git a/react/src/components/dashboard/walletsData.js b/react/src/components/dashboard/walletsData.js index 5ef9714..92a1e0b 100644 --- a/react/src/components/dashboard/walletsData.js +++ b/react/src/components/dashboard/walletsData.js @@ -1,5 +1,6 @@ import React from 'react'; import { translate } from '../../translate/translate'; +import { secondsToString } from '../../util/time'; import { basiliskRefresh, basiliskConnection, getDexNotaries } from '../../actions/actionCreators'; import Store from '../../store'; @@ -8,7 +9,11 @@ class WalletsData extends React.Component { super(props); this.state = { basiliskActionsMenu: false, + itemsPerPage: 10, + activePage: 1, + itemsList: null, }; + this.updateInput = this.updateInput.bind(this); this.toggleBasiliskActionsMenu = this.toggleBasiliskActionsMenu.bind(this); this.basiliskRefreshAction = this.basiliskRefreshAction.bind(this); this.basiliskConnectionAction = this.basiliskConnectionAction.bind(this); @@ -37,8 +42,154 @@ class WalletsData extends React.Component { Store.dispatch(getDexNotaries(this.props.ActiveCoin.coin)); } + updateInput(e) { + let historyToSplit = this.props.ActiveCoin.txhistory; + historyToSplit = historyToSplit.slice(0, e.target.value); + + this.setState({ + [e.target.name]: e.target.value, + activePage: 1, + itemsList: historyToSplit, + }); + } + + componentWillReceiveProps(props) { + if (this.props.ActiveCoin.txhistory && 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 = this.props.ActiveCoin.txhistory; + historyToSplit = historyToSplit.slice((this.state.activePage - 1) * this.state.itemsPerPage, this.state.activePage * this.state.itemsPerPage); + + this.setState(Object.assign({}, this.state, { + itemsList: historyToSplit, + })); + } + } + } + + updateCurrentPage(page) { + let historyToSplit = this.props.ActiveCoin.txhistory; + historyToSplit = historyToSplit.slice((page - 1) * this.state.itemsPerPage, page * this.state.itemsPerPage); + + this.setState(Object.assign({}, this.state, { + activePage: page, + itemsList: historyToSplit, + })); + } + + renderPaginationItems() { + let items = []; + + for (let i=0; i <= Math.floor(this.props.ActiveCoin.txhistory.length / this.state.itemsPerPage); i++) { + items.push( +
  • + this.updateCurrentPage(i + 1) : null}>{i + 1} +
  • + ); + } + + return items; + } + + renderPaginationItemsPerPageSelector() { + if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length > 10) { + return ( +
    + +
    + ); + } else { + return null; + } + } + + renderPagination() { + if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length > 10) { + return ( +
    +
    +
    Showing {((this.state.activePage - 1) * this.state.itemsPerPage) + 1} to {this.state.activePage * this.state.itemsPerPage} of {this.props.ActiveCoin.txhistory.length} entries
    +
    +
    + +
    +
    + ); + } else { + return null; + } + } + + renderTxType(category) { + if ( category === 'send' ) { + return ( + + {translate('DASHBOARD.OUT')} + + ); + } + if ( category === 'receive' ) { + return ( + + {translate('DASHBOARD.IN')} + + ); + } + if ( category === 'generate' ) { + return ( + + {translate('DASHBOARD.MINED')} + + ); + } + if ( category === 'immature' ) { + return ( + + {translate('DASHBOARD.IMMATURE')} + + ); + } + } + + renderTxHistoryList() { + if (this.state.itemsList && this.state.itemsList.length) { + return this.state.itemsList.map((tx, index) => + + {this.renderTxType(tx.category)} + {tx.confirmations} + {tx.amount} + {secondsToString(tx.blocktime)} + {tx.address} + + + + + ); + } else { + return null; + } + } + render() { - if (this.props && this.props.ActiveCoin && this.props.ActiveCoin.coin && this.props.ActiveCoin.mode !== 'native') { + if (this.props && this.props.ActiveCoin && this.props.ActiveCoin.coin && this.props.ActiveCoin.mode !== 'native' && !this.props.ActiveCoin.send && !this.props.ActiveCoin.receive) { return (
    @@ -84,28 +235,46 @@ class WalletsData extends React.Component {

    {translate('INDEX.TRANSACTION_HISTORY')}

    - - - - - - - - - - - - - - - - - - - - - -
    {translate('INDEX.DIRECTION')}{translate('INDEX.CONFIRMATIONS')}{translate('INDEX.AMOUNT')}{translate('INDEX.TIME')}{translate('INDEX.DEST_ADDRESS')}{translate('INDEX.TX_DETAIL')}
    {translate('INDEX.DIRECTION')}{translate('INDEX.CONFIRMATIONS')}{translate('INDEX.AMOUNT')}{translate('INDEX.TIME')}{translate('INDEX.DEST_ADDRESS')}{translate('INDEX.TX_DETAIL')}
    +
    +
    + {this.renderPaginationItemsPerPageSelector()} +
    +
    +
    + +
    +
    +
    +
    + + + + + + + + + + + + + {this.renderTxHistoryList()} + + + + + + + + + + + +
    {translate('INDEX.DIRECTION')}{translate('INDEX.CONFIRMATIONS')}{translate('INDEX.AMOUNT')}{translate('INDEX.TIME')}{translate('INDEX.DEST_ADDRESS')}{translate('INDEX.TX_DETAIL')}
    {translate('INDEX.DIRECTION')}{translate('INDEX.CONFIRMATIONS')}{translate('INDEX.AMOUNT')}{translate('INDEX.TIME')}{translate('INDEX.DEST_ADDRESS')}{translate('INDEX.TX_DETAIL')}
    +
    + {this.renderPagination()}
    diff --git a/react/src/components/dashboard/walletsNativeReceive.js b/react/src/components/dashboard/walletsNativeReceive.js index 0dc76c9..dea9b93 100644 --- a/react/src/components/dashboard/walletsNativeReceive.js +++ b/react/src/components/dashboard/walletsNativeReceive.js @@ -3,7 +3,7 @@ import { translate } from '../../translate/translate'; import { getNewKMDAddresses, copyCoinAddress } from '../../actions/actionCreators'; import Store from '../../store'; -// TODO: add addr balance +// TODO: importaddress, importprivkey(?) class WalletsNativeReceive extends React.Component { constructor(props) { @@ -25,8 +25,7 @@ class WalletsNativeReceive extends React.Component { } renderAddressList(type) { - console.log(this.props.ActiveCoin.addresses[type]); - if (this.props.ActiveCoin.addresses[type] && this.props.ActiveCoin.addresses[type].length) { + if (this.props.ActiveCoin.addresses && this.props.ActiveCoin.addresses[type] && this.props.ActiveCoin.addresses[type].length) { return this.props.ActiveCoin.addresses[type].map((address) => diff --git a/react/src/components/dashboard/walletsNativeSend.js b/react/src/components/dashboard/walletsNativeSend.js index 35eaf53..42b522a 100644 --- a/react/src/components/dashboard/walletsNativeSend.js +++ b/react/src/components/dashboard/walletsNativeSend.js @@ -22,7 +22,7 @@ class WalletsNativeSend extends React.Component { } renderAddressByType(type) { - if (this.props.ActiveCoin.addresses[type] && this.props.ActiveCoin.addresses[type].length) { + if (this.props.ActiveCoin.addresses && this.props.ActiveCoin.addresses[type] && this.props.ActiveCoin.addresses[type].length) { return this.props.ActiveCoin.addresses[type].map((address) =>
  • this.updateAddressSelection(address.address, type, address.amount)}> [ {address.amount} {this.props.ActiveCoin.coin} ]  {address.address} diff --git a/react/src/components/dashboard/walletsNativeTxHistory.js b/react/src/components/dashboard/walletsNativeTxHistory.js index 8c82162..3e3d323 100644 --- a/react/src/components/dashboard/walletsNativeTxHistory.js +++ b/react/src/components/dashboard/walletsNativeTxHistory.js @@ -7,9 +7,16 @@ import Store from '../../store'; class WalletsNativeTxHistory extends React.Component { constructor(props) { super(props); + this.state = { + itemsPerPage: 10, + activePage: 1, + itemsList: null, + }; + this.updateInput = this.updateInput.bind(this); } - // TODO: implement sorting and pagination + // TODO: implement sorting + // implement pagination past X items should call listtransactions to get new chunk of data // z transactions // filter based on addr @@ -17,6 +24,17 @@ class WalletsNativeTxHistory extends React.Component { Store.dispatch(toggleDashboardTxInfoModal(display, txIndex)); } + updateInput(e) { + let historyToSplit = this.props.ActiveCoin.txhistory; + historyToSplit = historyToSplit.slice(0, e.target.value); + + this.setState({ + [e.target.name]: e.target.value, + activePage: 1, + itemsList: historyToSplit, + }); + } + renderTxType(category) { if ( category === 'send' ) { return ( @@ -60,9 +78,92 @@ 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)) { + let historyToSplit = this.props.ActiveCoin.txhistory; + historyToSplit = historyToSplit.slice((this.state.activePage - 1) * this.state.itemsPerPage, this.state.activePage * this.state.itemsPerPage); + + this.setState(Object.assign({}, this.state, { + itemsList: historyToSplit, + })); + } + } + + updateCurrentPage(page) { + let historyToSplit = this.props.ActiveCoin.txhistory; + historyToSplit = historyToSplit.slice((page - 1) * this.state.itemsPerPage, page * this.state.itemsPerPage); + + this.setState(Object.assign({}, this.state, { + activePage: page, + itemsList: historyToSplit, + })); + } + + renderPaginationItems() { + let items = []; + + for (let i=0; i <= Math.floor(this.props.ActiveCoin.txhistory.length / this.state.itemsPerPage); i++) { + items.push( +
  • + this.updateCurrentPage(i + 1) : null}>{i + 1} +
  • + ); + } + + return items; + } + + renderPaginationItemsPerPageSelector() { + if (this.props.ActiveCoin.txhistory.length > 10) { + return ( +
    + +
    + ); + } else { + return null; + } + } + + renderPagination() { + if (this.props.ActiveCoin.txhistory.length > 10) { + return ( +
    +
    +
    Showing {((this.state.activePage - 1) * this.state.itemsPerPage) + 1} to {this.state.activePage * this.state.itemsPerPage} of {this.props.ActiveCoin.txhistory.length} entries
    +
    +
    + +
    +
    + ); + } else { + return null; + } + } + renderTxHistoryList() { - if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length && this.props.ActiveCoin.nativeActiveSection === 'default') { - return this.props.ActiveCoin.txhistory.map((tx, index) => + if (this.state.itemsList && this.state.itemsList.length && this.props.ActiveCoin.nativeActiveSection === 'default') { + return this.state.itemsList.map((tx, index) => @@ -98,33 +199,48 @@ class WalletsNativeTxHistory extends React.Component {

    {translate('INDEX.TRANSACTION_HISTORY')}

    - - - - - - - - - - - - - - {this.renderTxHistoryList()} - - - - - - - - - - - - -
    {translate('INDEX.TYPE')}{translate('INDEX.DIRECTION')}{translate('INDEX.CONFIRMATIONS')}{translate('INDEX.AMOUNT')}{translate('INDEX.TIME')}{translate('INDEX.DEST_ADDRESS')}{translate('INDEX.TX_DETAIL')}
    {translate('INDEX.TYPE')}{translate('INDEX.DIRECTION')}{translate('INDEX.CONFIRMATIONS')}{translate('INDEX.AMOUNT')}{translate('INDEX.TIME')}{translate('INDEX.DEST_ADDRESS')}{translate('INDEX.TX_DETAIL')}
    +
    +
    + {this.renderPaginationItemsPerPageSelector()} +
    +
    +
    + +
    +
    +
    +
    + + + + + + + + + + + + + + {this.renderTxHistoryList()} + + + + + + + + + + + + +
    {translate('INDEX.TYPE')}{translate('INDEX.DIRECTION')}{translate('INDEX.CONFIRMATIONS')}{translate('INDEX.AMOUNT')}{translate('INDEX.TIME')}{translate('INDEX.DEST_ADDRESS')}{translate('INDEX.TX_DETAIL')}
    {translate('INDEX.TYPE')}{translate('INDEX.DIRECTION')}{translate('INDEX.CONFIRMATIONS')}{translate('INDEX.AMOUNT')}{translate('INDEX.TIME')}{translate('INDEX.DEST_ADDRESS')}{translate('INDEX.TX_DETAIL')}
    +
    + {this.renderPagination()}
    diff --git a/react/src/components/dashboard/walletsNav.js b/react/src/components/dashboard/walletsNav.js index b30c428..ab50627 100644 --- a/react/src/components/dashboard/walletsNav.js +++ b/react/src/components/dashboard/walletsNav.js @@ -67,7 +67,7 @@ class WalletsNav extends React.Component { } else { return (
    -
    +
      {translate('INDEX.MY')} {this.props && this.props.ActiveCoin ? this.props.ActiveCoin.coin : '-'} {translate('INDEX.ADDRESS')}: {this.props && this.props.Dashboard && this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : '-'}
    diff --git a/react/src/components/dashboard/walletsProgress.js b/react/src/components/dashboard/walletsProgress.js index 477ae97..c3157ce 100644 --- a/react/src/components/dashboard/walletsProgress.js +++ b/react/src/components/dashboard/walletsProgress.js @@ -2,22 +2,41 @@ import React from 'react'; import { translate } from '../../translate/translate'; class WalletsProgress extends React.Component { + constructor(props) { + super(props); + this.isFullySynced = this.isFullySynced.bind(this); + } + + isFullySynced() { + if ((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) { + return true; + } else { + return false; + } + } + render() { if (this.props && this.props.ActiveCoin && this.props.ActiveCoin.mode === 'full' && this.props.Dashboard.progress) { if (this.props.Dashboard.progress && this.props.Dashboard.progress.error) { return (
    Coin is busy processing
    ); } else { return ( -