Browse Source

Merge pull request #99 from pbca26/redux

Redux
all-modes
pbca26 8 years ago
committed by GitHub
parent
commit
f895efdd80
  1. 204
      react/src/actions/actionCreators.js
  2. 23
      react/src/components/dashboard/coinTileItem.js
  3. 4
      react/src/components/dashboard/dashboard.js
  4. 54
      react/src/components/dashboard/receiveCoin.js
  5. 138
      react/src/components/dashboard/sendCoin.js
  6. 131
      react/src/components/dashboard/walletsData.js
  7. 2
      react/src/components/dashboard/walletsNative.js
  8. 1
      react/src/components/dashboard/walletsNativeReceive.js
  9. 10
      react/src/components/dashboard/walletsNativeSend.js
  10. 6
      react/src/components/dashboard/walletsNativeTxInfo.js
  11. 121
      react/src/components/dashboard/walletsTxInfo.js
  12. 3
      react/src/config.js
  13. 20
      react/src/reducers/activeCoin.js
  14. 3
      react/src/styles/index.scss

204
react/src/actions/actionCreators.js

@ -40,6 +40,16 @@ export const DASHBOARD_ACTIVE_TXINFO_MODAL = 'DASHBOARD_ACTIVE_TXINFO_MODAL';
export const DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE = 'DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE'; export const DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE = 'DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE';
export const DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY = 'DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY'; export const DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY = 'DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY';
export const DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS = 'DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS'; export const DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS = 'DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS';
export const DASHBOARD_ACTIVE_COIN_SENDTO = 'DASHBOARD_ACTIVE_COIN_SENDTO';
export const DASHBOARD_ACTIVE_COIN_GET_CACHE = 'DASHBOARD_ACTIVE_COIN_GET_CACHE';
export const DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR = 'DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR';
export function changeMainBasiliskAddress(address) {
return {
type: DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR,
address,
}
}
export function toggleDashboardActiveSection(name) { export function toggleDashboardActiveSection(name) {
return { return {
@ -661,6 +671,31 @@ export function getFullTransactionsList(coin) {
} }
} }
export function getBasiliskTransactionsList(coin, address) {
const payload = {
'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'),
'agent': 'dex',
'method': 'listtransactions',
'address': address,
'count': 100,
'skip': 0,
'symbol': coin
};
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, 'getBasiliskTransactionsList', 'Error', 'error'));
})
.then(response => response.json())
.then(json => dispatch(getNativeTxHistoryState(json)))
}
}
export function getPeersList(coin) { export function getPeersList(coin) {
const payload = { const payload = {
'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'), 'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'),
@ -862,9 +897,13 @@ function getKMDAddressesNativeState(json) {
} }
} }
export function getKMDAddressesNative(coin) { export function getKMDAddressesNative(coin, mode, currentAddress) {
const type = ['public', 'private']; const type = ['public', 'private'];
if (mode !== 'native') {
type.pop();
}
return dispatch => { return dispatch => {
Promise.all(type.map((_type, index) => { Promise.all(type.map((_type, index) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -903,6 +942,16 @@ export function getKMDAddressesNative(coin) {
}; };
} }
if (mode !== 'native' || mode !== 'basilisk') {
payload = {
'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'),
'coin': coin,
'agent': 'bitcoinrpc',
'method': 'getaddressesbyaccount',
'account': '*'
};
}
fetch('http://127.0.0.1:' + Config.iguanaCorePort, { fetch('http://127.0.0.1:' + Config.iguanaCorePort, {
method: 'POST', method: 'POST',
body: JSON.stringify(payload), body: JSON.stringify(payload),
@ -940,6 +989,29 @@ export function getKMDAddressesNative(coin) {
}; };
} }
if (mode === 'full') {
payload = {
'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'),
'coin': coin,
'method': 'listunspent',
'params': [
1,
9999999,
]
};
}
// if api cache option is off
if (mode === 'basilisk') {
payload = {
'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'),
'agent': 'dex',
'method': 'listunspent',
'address': currentAddress,
'symbol': coin
};
}
fetch('http://127.0.0.1:' + Config.iguanaCorePort, { fetch('http://127.0.0.1:' + Config.iguanaCorePort, {
method: 'POST', method: 'POST',
body: JSON.stringify(payload), body: JSON.stringify(payload),
@ -950,12 +1022,17 @@ export function getKMDAddressesNative(coin) {
}) })
.then(response => response.json()) .then(response => response.json())
.then(function(json) { .then(function(json) {
if (mode === 'full' || mode === 'basilisk') {
result[0] = result[0].result;
}
if (mode !== 'basilisk') {
const allAddrArray = json.map(res => res.address).filter((x, i, a) => a.indexOf(x) == i); const allAddrArray = json.map(res => res.address).filter((x, i, a) => a.indexOf(x) == i);
for (let a=0; a < allAddrArray.length; a++) { for (let a=0; a < allAddrArray.length; a++) {
const filteredArray = json.filter(res => res.address === allAddrArray[a]).map(res => res.amount); const filteredArray = json.filter(res => res.address === allAddrArray[a]).map(res => res.amount);
let isNewAddr = true; let isNewAddr = true;
for (let x=0; x < 2 && isNewAddr; x++) { for (let x=0; x < result.length && isNewAddr; x++) {
for (let y=0; y < result[x].length && isNewAddr; y++) { for (let y=0; y < result[x].length && isNewAddr; y++) {
if (allAddrArray[a] === result[x][y]) { if (allAddrArray[a] === result[x][y]) {
isNewAddr = false; isNewAddr = false;
@ -972,14 +1049,22 @@ export function getKMDAddressesNative(coin) {
console.log('new addr ' + allAddrArray[a] + ' | ' + allAddrArray[a].substring(0, 2)); console.log('new addr ' + allAddrArray[a] + ' | ' + allAddrArray[a].substring(0, 2));
} }
} }
}
let newAddressArray = []; let newAddressArray = [];
for (let a=0; a < 2; a++) { for (let a=0; a < result.length; a++) {
newAddressArray[a] = []; newAddressArray[a] = [];
for (let b=0; b < result[a].length; b++) { for (let b=0; b < result[a].length; b++) {
const filteredArray = json.filter(res => res.address === result[a][b]).map(res => res.amount); var filteredArray;
if (mode === 'basilisk') {
filteredArray = json.map(res => res.amount);
} else {
filteredArray = json.filter(res => res.address === result[a][b]).map(res => res.amount);
}
let sum = 0; let sum = 0;
for (let i=0; i < filteredArray.length; i++) { for (let i=0; i < filteredArray.length; i++) {
@ -988,7 +1073,7 @@ export function getKMDAddressesNative(coin) {
newAddressArray[a][b] = { newAddressArray[a][b] = {
address: result[a][b], address: result[a][b],
amount: sum, amount: currentAddress === result[a][b] ? sum : 'N/A',
}; };
} }
} }
@ -1002,6 +1087,30 @@ export function getKMDAddressesNative(coin) {
} }
} }
function getShepherdCacheState(json) {
return {
type: DASHBOARD_ACTIVE_COIN_GET_CACHE,
cache: json && json.result && json.result.basilisk ? json.result.basilisk : null,
}
}
export function getShepherdCache(pubkey) {
return dispatch => {
return fetch('http://127.0.0.1:' + Config.agamaPort + '/shepherd/cache?pubkey=' + pubkey, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.catch(function(error) {
console.log(error);
dispatch(triggerToaster(true, 'getShepherdCache', 'Error', 'error'));
})
.then(response => response.json())
.then(json => dispatch(getShepherdCacheState(json)))
}
}
function getDebugLogState(json) { function getDebugLogState(json) {
const _data = json.result.replace('\n', '\r\n'); const _data = json.result.replace('\n', '\r\n');
@ -1281,6 +1390,8 @@ export function getNativeTxHistoryState(json) {
json = null; json = null;
} else if (json && json.result) { } else if (json && json.result) {
json = json.result; json = json.result;
} else if (!json.length) {
json = 'no data';
} }
return { return {
@ -1292,6 +1403,7 @@ export function getNativeTxHistoryState(json) {
function handleGetNewKMDAddresses(pubpriv, coin, dispatch) { function handleGetNewKMDAddresses(pubpriv, coin, dispatch) {
dispatch(triggerToaster(true, translate('KMD_NATIVE.NEW_ADDR_GENERATED'), translate('TOASTR.WALLET_NOTIFICATION'), 'success')); dispatch(triggerToaster(true, translate('KMD_NATIVE.NEW_ADDR_GENERATED'), translate('TOASTR.WALLET_NOTIFICATION'), 'success'));
dispatch(getKMDAddressesNative(coin)); dispatch(getKMDAddressesNative(coin));
return {}; return {};
} }
@ -1469,6 +1581,88 @@ export function getKMDOPID(opid, coin) {
} }
} }
function sendToAddressState(json, dispatch) {
if (json && json.error) {
dispatch(triggerToaster(true, json.error, 'Error', 'error'));
return {
type: DASHBOARD_ACTIVE_COIN_SENDTO,
lastSendToResponse: json,
}
} else if (json && json.result && json.complete) {
dispatch(triggerToaster(true, translate('TOASTR.TX_SENT_ALT'), translate('TOASTR.WALLET_NOTIFICATION'), 'success'));
return {
type: DASHBOARD_ACTIVE_COIN_SENDTO,
lastSendToResponse: json,
}
}
}
export function sendToAddress(coin, _payload) {
const payload = {
'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'),
'coin': coin,
'method': 'sendtoaddress',
'params': [
_payload.sendTo,
_payload.amount,
'EasyDEX',
'EasyDEXTransaction'
]
};
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, 'sendToAddress', 'Error', 'error'));
})
.then(response => response.json())
.then(json => dispatch(sendToAddressState(json, dispatch)))
}
}
function checkAddressBasiliskHandle(json) {
if (json && json.error) {
return dispatch => {
dispatch(triggerToaster(true, json.error, translate('TOASTR.WALLET_NOTIFICATION'), 'error'));
}
}
if (json && json.coin && json.randipbits) {
return dispatch => {
dispatch(triggerToaster(true, 'Address already registered', translate('TOASTR.WALLET_NOTIFICATION'), 'warning'));
}
}
}
export function checkAddressBasilisk(coin, address) {
const payload = {
'userpass': 'tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'),
'agent': 'dex',
'method': 'checkaddress',
'address': address,
'symbol': coin
};
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, 'checkAddressBasilisk', 'Error', 'error'));
})
.then(response => response.json())
.then(json => dispatch(checkAddressBasiliskHandle(json)))
}
}
/*function Shepherd_SendPendValue() { /*function Shepherd_SendPendValue() {
Shepherd_SysInfo().then(function(result){ Shepherd_SysInfo().then(function(result){
var ram_data = formatBytes(result.totalmem_bytes) var ram_data = formatBytes(result.totalmem_bytes)

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

@ -13,7 +13,9 @@ import {
getNativeTxHistory, getNativeTxHistory,
getKMDAddressesNative, getKMDAddressesNative,
getKMDOPID, getKMDOPID,
getFullTransactionsList getFullTransactionsList,
getBasiliskTransactionsList,
getShepherdCache
} from '../../actions/actionCreators'; } from '../../actions/actionCreators';
import Store from '../../store'; import Store from '../../store';
@ -24,6 +26,11 @@ class CoinTileItem extends React.Component {
}; };
} }
// TODO: 1) cache native/full node data to file
// 2) limit amount of req per update e.g. list of addresses don't change too often
// 3) limit req in basilisk as much as possible incl. activehandle
// 4) add pending requests store
dashboardChangeActiveCoin(coin, mode) { dashboardChangeActiveCoin(coin, mode) {
if (coin !== this.props.ActiveCoin.coin) { if (coin !== this.props.ActiveCoin.coin) {
Store.dispatch(stopInterval('sync', this.props.Interval.interval)); Store.dispatch(stopInterval('sync', this.props.Interval.interval));
@ -33,7 +40,7 @@ class CoinTileItem extends React.Component {
var _iguanaActiveHandle = setInterval(function() { var _iguanaActiveHandle = setInterval(function() {
Store.dispatch(getSyncInfo(coin)); Store.dispatch(getSyncInfo(coin));
Store.dispatch(iguanaEdexBalance(coin, mode)); Store.dispatch(iguanaEdexBalance(coin, mode));
Store.dispatch(getAddressesByAccount(coin)); Store.dispatch(getKMDAddressesNative(coin, mode)); //getAddressesByAccount(coin));
Store.dispatch(getFullTransactionsList(coin)); Store.dispatch(getFullTransactionsList(coin));
}, 3000); }, 3000);
Store.dispatch(startInterval('sync', _iguanaActiveHandle)); Store.dispatch(startInterval('sync', _iguanaActiveHandle));
@ -50,7 +57,17 @@ class CoinTileItem extends React.Component {
Store.dispatch(startInterval('sync', _iguanaActiveHandle)); Store.dispatch(startInterval('sync', _iguanaActiveHandle));
} }
if (mode === 'basilisk') { if (mode === 'basilisk') {
Store.dispatch(getAddressesByAccount(coin)); var _iguanaActiveHandle = setInterval(function() {
const useAddress = this.props.ActiveCoin.mainBasiliskAddress ? this.props.ActiveCoin.mainBasiliskAddress : this.props.Dashboard.activeHandle[coin];
if (this.props && this.props.Dashboard && this.props.Dashboard.activeHandle && this.props.Dashboard.activeHandle[coin]) {
Store.dispatch(getBasiliskTransactionsList(coin, useAddress));
Store.dispatch(getKMDAddressesNative(coin, mode, useAddress));
Store.dispatch(getShepherdCache(this.props.Dashboard.activeHandle.pubkey));
Store.dispatch(iguanaEdexBalance(coin, mode));
}
}.bind(this), 3000);
Store.dispatch(startInterval('sync', _iguanaActiveHandle));
// basilisk // basilisk
} }
} }

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

@ -17,6 +17,7 @@ import WalletsBasiliskRefresh from './walletsBasiliskRefresh';
import WalletsBasiliskConnection from './walletsBasiliskConnection'; import WalletsBasiliskConnection from './walletsBasiliskConnection';
import WalletsNative from './walletsNative'; import WalletsNative from './walletsNative';
import WalletsNativeTxInfo from './walletsNativeTxInfo'; import WalletsNativeTxInfo from './walletsNativeTxInfo';
import WalletsTxInfo from './walletsTxInfo';
class Dashboard extends React.Component { class Dashboard extends React.Component {
constructor(props) { constructor(props) {
@ -37,11 +38,12 @@ class Dashboard extends React.Component {
<WalletsNav {...this.props} /> <WalletsNav {...this.props} />
<WalletsProgress {...this.props} /> <WalletsProgress {...this.props} />
<WalletsBalance {...this.props.ActiveCoin} /> <WalletsBalance {...this.props.ActiveCoin} />
<SendCoin {...this.props.ActiveCoin} /> <SendCoin {...this.props} />
<ReceiveCoin {...this.props.ActiveCoin} /> <ReceiveCoin {...this.props.ActiveCoin} />
<WalletsData {...this.props} /> <WalletsData {...this.props} />
<WalletsBasiliskRefresh {...this.props} /> <WalletsBasiliskRefresh {...this.props} />
<WalletsBasiliskConnection {...this.props} /> <WalletsBasiliskConnection {...this.props} />
<WalletsTxInfo {...this.props} />
<WalletsNative {...this.props} /> <WalletsNative {...this.props} />
<WalletsNativeTxInfo {...this.props} /> <WalletsNativeTxInfo {...this.props} />
</div> </div>

54
react/src/components/dashboard/receiveCoin.js

@ -1,19 +1,59 @@
import React from 'react'; import React from 'react';
import { translate } from '../../translate/translate'; import { translate } from '../../translate/translate';
import { checkAddressBasilisk, importAddressBasilisk } from '../../actions/actionCreators';
import Store from '../../store';
// TODO: implement sorting
// TODO: add import address ui in basilisk
// TODO: fallback to localstorage/stores data in case iguana is taking too long to respond
class ReceiveCoin extends React.Component { class ReceiveCoin extends React.Component {
renderAddressList() { constructor(props) {
if (this.props.addresses && this.props.addresses.length) { super(props);
return this.props.addresses.map((address) => }
<tr key={address}>
checkAddressBasilisk(address) {
Store.dispatch(checkAddressBasilisk(this.props.coin, address));
}
/*importAddressBasilisk(address) {
Store.dispatch(importAddressBasilisk(this.props.coin, address));
}
<span className="label label-default margin-left-10 action" title="Import" onClick={() => this.importAddressBasilisk(address)}>
<i className="icon fa-upload"></i>
</span>*/
renderAddressActions(address) {
if (this.props.mode === 'basilisk') {
return (
<td> <td>
<span className="label label-default"> <span className="label label-default">
<i className="icon fa-eye"></i> {translate('IAPI.PUBLIC_SM')} <i className="icon fa-eye"></i> {translate('IAPI.PUBLIC_SM')}
</span> </span>
<span className="label label-default margin-left-10 action" title="Check" onClick={() => this.checkAddressBasilisk(address)}>
<i className="icon fa-database"></i>
</span>
</td> </td>
<td>{address}</td> );
<td></td> } else {
<td></td> return (
<td>
<span className="label label-default">
<i className="icon fa-eye"></i> {translate('IAPI.PUBLIC_SM')}
</span>
</td>
);
}
}
renderAddressList() {
if (this.props.addresses && this.props.addresses['public'] && this.props.addresses['public'].length) {
return this.props.addresses['public'].map((address) =>
<tr key={address.address}>
{this.renderAddressActions(address.address)}
<td>{address.address}</td>
<td>{address.amount}</td>
<td>{address.interest ? address.interest : 'N/A'}</td>
</tr> </tr>
); );
} else { } else {

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

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { translate } from '../../translate/translate'; import { translate } from '../../translate/translate';
//import { } from '../../actions/actionCreators'; import { sendToAddress } from '../../actions/actionCreators';
//import Store from '../../store'; import Store from '../../store';
// TODO: implement logic // TODO: implement logic
@ -10,17 +10,111 @@ class SendCoin extends React.Component {
super(props); super(props);
this.state = { this.state = {
currentStep: 0, currentStep: 0,
sendFrom: this.props.Dashboard && this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : null,
sendFromAmount: 0,
sendTo: null,
amount: 0,
fee: 0.0001,
sendSig: false,
}; };
this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.toggleSendSig = this.toggleSendSig.bind(this);
} }
changeSendCoinStep(step) { changeSendCoinStep(step) {
this.setState(Object.assign({}, this.state, { this.setState(Object.assign({}, this.state, {
currentStep: step, currentStep: step,
})); }));
if (step === 2) {
Store.dispatch(sendToAddress(this.props.ActiveCoin.coin, this.state));
}
}
toggleSendSig() {
this.setState(Object.assign({}, this.state, {
sendSig: !this.state.sendSig,
}));
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
console.log(this.state);
}
handleSubmit() {
Store.dispatch(sendNativeTx(this.props.ActiveCoin.coin, this.state));
setTimeout(function() {
Store.dispatch(getKMDOPID(null, this.props.ActiveCoin.coin));
}, 1000);
}
renderSignedTx(signedtx) {
const substrBlocks = 10;
const substrLength = this.props.ActiveCoin.lastSendToResponse['signedtx'].length / substrBlocks;
let out = [];
for (let i = 0; i < substrBlocks; i++) {
out.push(
<div key={i}>{this.props.ActiveCoin.lastSendToResponse['signedtx'].substring(i * substrLength, substrLength * i + substrLength)}</div>
);
}
return out.length ? out : null;
}
renderKey(key) {
if (key === 'signedtx') {
return this.renderSignedTx();
} else if (key === 'complete') {
if (this.props.ActiveCoin.lastSendToResponse[key] === true) {
return (
<span className="label label-success">true</span>
);
} else {
return (
<span className="label label-danger">false</span>
);
}
} else if (key === 'result') {
return (
<span>{this.props.ActiveCoin.lastSendToResponse[key]}</span>
);
} else if (key === 'error') {
return (
<span className="label label-danger">{this.props.ActiveCoin.lastSendToResponse[key]}</span>
);
} else if (key === 'sendrawtransaction') {
if (this.props.ActiveCoin.lastSendToResponse[key] === 'success') {
return (
<span className="label label-success">true</span>
);
} else {
return (
<span className="label label-danger">false</span>
);
}
}
}
renderSendCoinResponse() {
if (this.props.ActiveCoin.lastSendToResponse) {
return Object.keys(this.props.ActiveCoin.lastSendToResponse).map((key, index) =>
<tr key={key}>
<td>{key}</td>
<td>{this.renderKey(key)}</td>
</tr>
);
} else {
return null;
}
} }
render() { render() {
if (this.props && this.props.send && this.props.mode !== 'native') { if (this.props.ActiveCoin && this.props.ActiveCoin.send && this.props.ActiveCoin.mode !== 'native') {
return ( return (
<div className="col-sm-12 padding-top-10" data-edexcoin="COIN" id="edexcoin_send"> <div className="col-sm-12 padding-top-10" data-edexcoin="COIN" id="edexcoin_send">
<div className="col-xlg-12 col-md-12 col-sm-12 col-xs-12"> <div className="col-xlg-12 col-md-12 col-sm-12 col-xs-12">
@ -51,49 +145,44 @@ class SendCoin extends React.Component {
<div className={this.state.currentStep === 0 ? 'panel' : 'panel hide'} id="edexcoin-send-screen"> <div className={this.state.currentStep === 0 ? 'panel' : 'panel hide'} id="edexcoin-send-screen">
<div className="panel-heading"> <div className="panel-heading">
<h3 data-edexcoin="COIN" className="panel-title"> <h3 data-edexcoin="COIN" className="panel-title">
{translate('INDEX.SEND')} <span data-edexcoin="COIN"></span> {translate('INDEX.SEND')} {this.props.ActiveCoin.coin}
</h3> </h3>
<div className="panel-actions">
<a href="javascript:void(0)" className="dropdown-toggle white btn-xs btn-info btn_refresh_edexcoin_send" data-edexcoin="COIN" aria-expanded="false" role="button">
<i className="icon fa-refresh margin-right-10" aria-hidden="true"></i> {translate('INDEX.REFRESH_FUNDS')}
</a>
</div>
</div> </div>
<div className="panel-body container-fluid"> <div className="panel-body container-fluid">
<form className="edexcoin-send-form" data-edexcoin="COIN" method="post" role="form" autoComplete="off"> <form className="edexcoin-send-form" data-edexcoin="COIN" method="post" role="form" autoComplete="off">
<div className="row"> <div className="row">
<div className="col-xlg-12 form-group form-material edexcoin_send_from_for_basilisk"> <div className={this.props.ActiveCoin.mode === 'basilisk' ? 'col-xlg-12 form-group form-material' : 'hide'}>
<label className="control-label" data-edexcoin="COIN" htmlFor="edexcoin_send_from">{translate('INDEX.SEND_FROM')}</label> <label className="control-label" data-edexcoin="COIN" htmlFor="edexcoin_send_from">{translate('INDEX.SEND_FROM')}</label>
<select className="form-control form-material showedexcoinaddrs show-tick" data-edexcoin="COIN" id="edexcoin_send_from" title="Select Transparent or Private Address" data-size="5"></select> <select className="form-control form-material showedexcoinaddrs show-tick" data-edexcoin="COIN" id="edexcoin_send_from" onChange={this.updateInput} title="Select Transparent or Private Address" data-size="5"></select>
</div> </div>
<div className="col-xlg-12 form-group form-material"> <div className="col-xlg-12 form-group form-material">
<label className="control-label" data-edexcoin="COIN" htmlFor="edexcoin_sendto">{translate('INDEX.SEND_TO')}</label> <label className="control-label" data-edexcoin="COIN" htmlFor="edexcoin_sendto">{translate('INDEX.SEND_TO')}</label>
<input type="text" className="form-control" data-edexcoin="COIN" id="edexcoin_sendto" name="edexcoin_sendto" placeholder="Enter address" autoComplete="off" required /> <input type="text" className="form-control" data-edexcoin="COIN" id="edexcoin_sendto" name="sendTo" placeholder="Enter address" autoComplete="off" onChange={this.updateInput} required />
</div> </div>
<div className="col-lg-6 form-group form-material"> <div className="col-lg-6 form-group form-material">
<label className="control-label" htmlFor="edexcoin_amount" data-edexcoin="COIN" id="edexcoin_amount_label"> <label className="control-label" htmlFor="edexcoin_amount" data-edexcoin="COIN" id="edexcoin_amount_label">
<span data-edexcoin="COIN"></span> {this.props.ActiveCoin.coin}
</label> </label>
<input type="text" className="form-control" data-edexcoin="COIN" id="edexcoin_amount" name="edexcoin_amount" placeholder="0.000" autoComplete="off" /> <input type="text" className="form-control" data-edexcoin="COIN" id="edexcoin_amount" name="amount" placeholder="0.000" autoComplete="off" onChange={this.updateInput} />
</div> </div>
<div className="col-lg-6 form-group form-material"> <div className="col-lg-6 form-group form-material">
<label className="control-label" data-edexcoin="COIN" htmlFor="edexcoin_fee">{translate('INDEX.FEE')}</label> <label className="control-label" data-edexcoin="COIN" htmlFor="edexcoin_fee">{translate('INDEX.FEE')}</label>
<input type="text" className="form-control" data-edexcoin="COIN" id="edexcoin_fee" name="edexcoin_fee" placeholder="0.000" autoComplete="off" /> <input type="text" className="form-control" data-edexcoin="COIN" id="edexcoin_fee" name="fee" defaultValue={this.state.fee} placeholder="0.000" autoComplete="off" onChange={this.updateInput} />
</div> </div>
<div className="col-lg-12"> <div className="col-lg-12">
<span data-edexcoin="KMD"> <span data-edexcoin="KMD">
<b>{translate('INDEX.TOTAL')} (<span data-edexcoin="COIN">{translate('INDEX.AMOUNT_SM')}</span> - txfee):</b> <span data-edexcoin="COIN" id="edexcoin_total_value">0.000</span> <span data-edexcoin="COIN" id="edexcoin_total_coinname" data-edexcoin="COIN"></span> <b>{translate('INDEX.TOTAL')} (<span data-edexcoin="COIN">{translate('INDEX.AMOUNT_SM')}</span> - txfee):</b> <span data-edexcoin="COIN" id="edexcoin_total_value">{Number(this.state.amount) - Number(this.state.fee)}</span> {this.props.ActiveCoin.coin}
</span> </span>
</div> </div>
<div className="col-lg-10 margin-top-10"> <div className="col-lg-10 margin-top-10">
<div className="pull-left margin-right-10"> <div className="pull-left margin-right-10">
<input type="checkbox" id="edexcoin_send_sig" name="edexcoin_send_sig" data-plugin="switchery" data-size="small" /> <input type="checkbox" id="edexcoin_send_sig" onClick={this.toggleSendSig} data-plugin="switchery" data-size="small" />
</div> </div>
<label className="padding-top-3" htmlFor="edexcoin_send_sig">{translate('INDEX.DONT_SEND')}</label> <label className="padding-top-3" htmlFor="edexcoin_send_sig" onClick={this.toggleSendSig}>{translate('INDEX.DONT_SEND')}</label>
</div> </div>
<div className="col-lg-2"> <div className="col-lg-2">
<button type="button" className="btn btn-primary waves-effect waves-light pull-right edexcoin_send_coins_btn_step1" onClick={() => this.changeSendCoinStep(1)}> <button type="button" className="btn btn-primary waves-effect waves-light pull-right edexcoin_send_coins_btn_step1" onClick={() => this.changeSendCoinStep(1)}>
{translate('INDEX.SEND')} <span data-edexcoin="COIN"></span> {translate('INDEX.SEND')} {Number(this.state.amount) - Number(this.state.fee)} {this.props.ActiveCoin.coin}
</button> </button>
</div> </div>
</div> </div>
@ -109,13 +198,13 @@ class SendCoin extends React.Component {
<div className="col-xs-12"> <div className="col-xs-12">
<b>{translate('INDEX.TO')}</b> <b>{translate('INDEX.TO')}</b>
</div> </div>
<div className="col-lg-6 col-sm-6 col-xs-12" id="mdl_confirm_currency_sendto_addr">[coin-address-goes-here]</div> <div className="col-lg-6 col-sm-6 col-xs-12" id="mdl_confirm_currency_sendto_addr">{this.state.sendTo}</div>
<div className="col-lg-6 col-sm-6 col-xs-6"> <div className="col-lg-6 col-sm-6 col-xs-6">
<span id="mdl_confirm_currency_send_amount">0.00000000</span> <span id="mdl_confirm_currency_coinname">[COIN]</span> <span id="mdl_confirm_currency_send_amount">{this.state.amount}</span> {this.props.ActiveCoin.coin}
</div> </div>
<div className="col-lg-6 col-sm-6 col-xs-12">{translate('INDEX.TX_FEE_REQ')}</div> <div className="col-lg-6 col-sm-6 col-xs-12">{translate('INDEX.TX_FEE_REQ')}</div>
<div className="col-lg-6 col-sm-6 col-xs-6"> <div className="col-lg-6 col-sm-6 col-xs-6">
<span id="mdl_confirm_currency_send_fee">0.00000000</span> <span id="mdl_confirm_currency_coinname_fee">[COIN]</span> <span id="mdl_confirm_currency_send_fee">{this.state.fee}</span> {this.props.ActiveCoin.coin}
</div> </div>
</div> </div>
<br /> <br />
@ -124,9 +213,9 @@ class SendCoin extends React.Component {
<div className="col-xs-12"> <div className="col-xs-12">
<b>{translate('INDEX.FROM')}</b> <b>{translate('INDEX.FROM')}</b>
</div> </div>
<div className="col-lg-6 col-sm-6 col-xs-12" id="mdl_confirm_currency_sendfrom_addr">[coin-address-goes-here]</div> <div className="col-lg-6 col-sm-6 col-xs-12" id="mdl_confirm_currency_sendfrom_addr">{this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin]}</div>
<div className="col-lg-6 col-sm-6 col-xs-6" style={{color: '#f44336'}}> <div className="col-lg-6 col-sm-6 col-xs-6" style={{color: '#f44336'}}>
<span id="mdl_confirm_currency_sendfrom_total_dedcut">-0.00000000</span> <span id="mdl_confirm_currency_coinname_total">[COIN]</span> <span id="mdl_confirm_currency_sendfrom_total_dedcut">{Number(this.state.amount) - Number(this.state.fee)}</span> {this.props.ActiveCoin.coin}
</div> </div>
</div> </div>
<div className="widget-body-footer"> <div className="widget-body-footer">
@ -151,6 +240,7 @@ class SendCoin extends React.Component {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{this.renderSendCoinResponse()}
</tbody> </tbody>
</table> </table>
<div className="widget-body-footer"> <div className="widget-body-footer">

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

@ -1,7 +1,14 @@
import React from 'react'; import React from 'react';
import { translate } from '../../translate/translate'; import { translate } from '../../translate/translate';
import { secondsToString } from '../../util/time'; import { secondsToString } from '../../util/time';
import { basiliskRefresh, basiliskConnection, getDexNotaries } from '../../actions/actionCreators'; import {
basiliskRefresh,
basiliskConnection,
getDexNotaries,
toggleDashboardTxInfoModal,
getBasiliskTransactionsList,
changeMainBasiliskAddress
} from '../../actions/actionCreators';
import Store from '../../store'; import Store from '../../store';
class WalletsData extends React.Component { class WalletsData extends React.Component {
@ -12,12 +19,16 @@ class WalletsData extends React.Component {
itemsPerPage: 10, itemsPerPage: 10,
activePage: 1, activePage: 1,
itemsList: null, itemsList: null,
currentAddress: null,
addressSelectorOpen: false,
}; };
this.updateInput = this.updateInput.bind(this); this.updateInput = this.updateInput.bind(this);
this.toggleBasiliskActionsMenu = this.toggleBasiliskActionsMenu.bind(this); this.toggleBasiliskActionsMenu = this.toggleBasiliskActionsMenu.bind(this);
this.basiliskRefreshAction = this.basiliskRefreshAction.bind(this); this.basiliskRefreshAction = this.basiliskRefreshAction.bind(this);
this.basiliskConnectionAction = this.basiliskConnectionAction.bind(this); this.basiliskConnectionAction = this.basiliskConnectionAction.bind(this);
this.getDexNotariesAction = this.getDexNotariesAction.bind(this); this.getDexNotariesAction = this.getDexNotariesAction.bind(this);
this.openDropMenu = this.openDropMenu.bind(this);
this.refreshTxList = this.refreshTxList.bind(this);
} }
toggleBasiliskActionsMenu() { toggleBasiliskActionsMenu() {
@ -53,6 +64,10 @@ class WalletsData extends React.Component {
}); });
} }
toggleTxInfoModal(display, txIndex) {
Store.dispatch(toggleDashboardTxInfoModal(display, txIndex));
}
componentWillReceiveProps(props) { componentWillReceiveProps(props) {
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length) { 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)) { if (!this.state.itemsList || (this.state.itemsList && !this.state.itemsList.length) || (props.ActiveCoin.txhistory !== this.props.ActiveCoin.txhistory)) {
@ -64,6 +79,12 @@ class WalletsData extends React.Component {
})); }));
} }
} }
if (this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory === 'no data') {
this.setState(Object.assign({}, this.state, {
itemsList: 'no data',
}));
}
} }
updateCurrentPage(page) { updateCurrentPage(page) {
@ -97,8 +118,8 @@ class WalletsData extends React.Component {
<label> <label>
Show&nbsp; Show&nbsp;
<select name="itemsPerPage" aria-controls="kmd-tx-history-tbl" className="form-control input-sm" onChange={this.updateInput}> <select name="itemsPerPage" aria-controls="kmd-tx-history-tbl" className="form-control input-sm" onChange={this.updateInput}>
<option value="1">10</option> <option value="10">10</option>
<option value="2">25</option> <option value="25">25</option>
<option value="50">50</option> <option value="50">50</option>
<option value="100">100</option> <option value="100">100</option>
</select>&nbsp; </select>&nbsp;
@ -139,14 +160,14 @@ class WalletsData extends React.Component {
} }
renderTxType(category) { renderTxType(category) {
if ( category === 'send' ) { if ( category === 'send' || category === 'sent' ) {
return ( return (
<span> <span>
<i className="icon fa-arrow-circle-left"></i> <span>{translate('DASHBOARD.OUT')}</span> <i className="icon fa-arrow-circle-left"></i> <span>{translate('DASHBOARD.OUT')}</span>
</span> </span>
); );
} }
if ( category === 'receive' ) { if ( category === 'receive' || category === 'received' ) {
return ( return (
<span> <span>
<i className="icon fa-arrow-circle-right"></i> <span>{translate('DASHBOARD.IN')}</span> <i className="icon fa-arrow-circle-right"></i> <span>{translate('DASHBOARD.IN')}</span>
@ -167,22 +188,107 @@ class WalletsData extends React.Component {
</span> </span>
); );
} }
if ( category === 'unknown' ) {
return (
<span>
<i className="icon fa-meh-o"></i> <span>{translate('DASHBOARD.UNKNOWN')}</span>
</span>
);
}
} }
renderTxHistoryList() { renderTxHistoryList() {
if (this.state.itemsList && this.state.itemsList.length) { if (this.state.itemsList && this.state.itemsList.length && this.state.itemsList !== 'no data') {
return this.state.itemsList.map((tx, index) => return this.state.itemsList.map((tx, index) =>
<tr key={tx.txid + tx.amount}> <tr key={tx.txid + tx.amount}>
<td>{this.renderTxType(tx.category)}</td> <td>{this.renderTxType(tx.category || tx.type)}</td>
<td>{tx.confirmations}</td> <td>{tx.confirmations}</td>
<td>{tx.amount}</td> <td>{tx.amount || translate('DASHBOARD.UNKNOWN')}</td>
<td>{secondsToString(tx.blocktime)}</td> <td>{secondsToString(tx.blocktime || tx.timestamp)}</td>
<td>{tx.address}</td> <td>{tx.address}</td>
<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> <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> </td>
</tr> </tr>
); );
}
if (this.state.itemsList === 'no data') {
return (
<span>No data</span>
);
}
if (!this.state.itemsList) {
return null;
}
}
updateAddressSelection(address, type, amount) {
this.setState(Object.assign({}, this.state, {
currentAddress: address,
addressSelectorOpen: false,
}));
setTimeout(function() {
Store.dispatch(changeMainBasiliskAddress(address));
Store.dispatch(getBasiliskTransactionsList(this.props.ActiveCoin.coin, address));
}.bind(this), 100);
}
refreshTxList() {
Store.dispatch(getBasiliskTransactionsList(this.props.ActiveCoin.coin, this.props.ActiveCoin.mainBasiliskAddress));
}
openDropMenu() {
this.setState(Object.assign({}, this.state, {
addressSelectorOpen: !this.state.addressSelectorOpen,
}));
}
renderAddressByType(type) {
if (this.props.ActiveCoin.addresses && this.props.ActiveCoin.addresses[type] && this.props.ActiveCoin.addresses[type].length) {
return this.props.ActiveCoin.addresses[type].map((address) =>
<li key={address.address}>
<a tabIndex="0" onClick={() => this.updateAddressSelection(address.address, type, address.amount)}><i className={type === 'public' ? 'icon fa-eye' : 'icon fa-eye-slash'}></i> <span className="text">[ {address.amount} {this.props.ActiveCoin.coin} ] {address.address}</span><span className="glyphicon glyphicon-ok check-mark"></span></a>
</li>
);
} else {
return null;
}
}
renderSelectorCurrentLabel() {
if (this.state.currentAddress) {
return (
<span>
<i className={this.state.addressType === 'public' ? 'icon fa-eye' : 'icon fa-eye-slash'}></i> <span className="text">[ {this.state.sendFromAmount} {this.props.ActiveCoin.coin} ] {this.state.currentAddress}</span>
</span>
);
} else {
return (
<span>- Select Transparent or Private Address -</span>
);
}
}
renderAddressList() {
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}>
<span className="filter-option pull-left">{this.renderSelectorCurrentLabel()} </span>&nbsp;<span className="bs-caret"><span className="caret"></span></span>
</button>
<div className="dropdown-menu open">
<ul className="dropdown-menu inner" role="menu">
<li data-original-index="1" className="selected">
<a tabIndex="0" data-tokens="null"><span className="text"> - Select Transparent or Private Address - </span><span className="glyphicon glyphicon-ok check-mark"></span></a>
</li>
{this.renderAddressByType('public')}
</ul>
</div>
</div>
);
} else { } else {
return null; return null;
} }
@ -199,7 +305,7 @@ class WalletsData extends React.Component {
<div id="edexcoin_txhistory" className="panel"> <div id="edexcoin_txhistory" className="panel">
<header className="panel-heading" style={{zIndex: '10'}}> <header className="panel-heading" style={{zIndex: '10'}}>
<div className={this.props.ActiveCoin.mode === 'basilisk' ? 'panel-actions' : 'panel-actions hide'}> <div className={this.props.ActiveCoin.mode === 'basilisk' ? 'panel-actions' : 'panel-actions hide'}>
<a href="javascript:void(0)" className="dropdown-toggle white btn-xs btn-info btn_refresh_edexcoin_dashboard" data-edexcoin="COIN" aria-expanded="false" role="button"> <a href="javascript:void(0)" className="dropdown-toggle white btn-xs btn-info btn_refresh_edexcoin_dashboard" data-edexcoin="COIN" aria-expanded="false" role="button" onClick={this.refreshTxList}>
<i className="icon fa-refresh margin-right-10" aria-hidden="true"></i> {translate('INDEX.REFRESH')} <i className="icon fa-refresh margin-right-10" aria-hidden="true"></i> {translate('INDEX.REFRESH')}
</a> </a>
<div className={this.state.basiliskActionsMenu ? 'dropdown open' : 'dropdown'} onClick={this.toggleBasiliskActionsMenu}> <div className={this.state.basiliskActionsMenu ? 'dropdown open' : 'dropdown'} onClick={this.toggleBasiliskActionsMenu}>
@ -235,6 +341,11 @@ class WalletsData extends React.Component {
<h4 className="panel-title">{translate('INDEX.TRANSACTION_HISTORY')}</h4> <h4 className="panel-title">{translate('INDEX.TRANSACTION_HISTORY')}</h4>
</header> </header>
<div className="panel-body"> <div className="panel-body">
<div className="row">
<div className="col-sm-6">
{this.renderAddressList()}
</div>
</div>
<div className="row"> <div className="row">
<div className="col-sm-6"> <div className="col-sm-6">
{this.renderPaginationItemsPerPageSelector()} {this.renderPaginationItemsPerPageSelector()}

2
react/src/components/dashboard/walletsNative.js

@ -13,6 +13,7 @@ class WalletsNative extends React.Component {
super(props); super(props);
} }
// <WalletsNativeAlert {...this.props} />
render() { render() {
if (this.props && this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native') { if (this.props && this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native') {
return ( return (
@ -26,7 +27,6 @@ class WalletsNative extends React.Component {
</ol> </ol>
</div> </div>
<div className="page-content"> <div className="page-content">
<WalletsNativeAlert {...this.props} />
<WalletsNativeSyncProgress {...this.props} /> <WalletsNativeSyncProgress {...this.props} />
<div className="row" data-extcoin="COIN" id="extcoin-wallet" data-plugin="masonry"> <div className="row" data-extcoin="COIN" id="extcoin-wallet" data-plugin="masonry">

1
react/src/components/dashboard/walletsNativeReceive.js

@ -3,6 +3,7 @@ import { translate } from '../../translate/translate';
import { getNewKMDAddresses, copyCoinAddress } from '../../actions/actionCreators'; import { getNewKMDAddresses, copyCoinAddress } from '../../actions/actionCreators';
import Store from '../../store'; import Store from '../../store';
// TODO: implement sorting
// TODO: importaddress, importprivkey(?) // TODO: importaddress, importprivkey(?)
class WalletsNativeReceive extends React.Component { class WalletsNativeReceive extends React.Component {

10
react/src/components/dashboard/walletsNativeSend.js

@ -103,13 +103,13 @@ class WalletsNativeSend extends React.Component {
if (opid.status === 'queued') { if (opid.status === 'queued') {
isWaitingStatus = false; isWaitingStatus = false;
return ( return (
<i>{translate('KMD_NATIVE.PLEASE_REFRESH')}...</i> <i>Awaiting in queue...</i>
); );
} }
if (opid.status === 'executing') { if (opid.status === 'executing') {
isWaitingStatus = false; isWaitingStatus = false;
return ( return (
<i>{translate('KMD_NATIVE.PLEASE_REFRESH')}...</i> <i>Processing...</i>
); );
} }
if (opid.status === 'failed') { if (opid.status === 'failed') {
@ -176,7 +176,6 @@ class WalletsNativeSend extends React.Component {
} }
handleSubmit() { handleSubmit() {
console.log(this.state);
Store.dispatch(sendNativeTx(this.props.ActiveCoin.coin, this.state)); Store.dispatch(sendNativeTx(this.props.ActiveCoin.coin, this.state));
setTimeout(function() { setTimeout(function() {
Store.dispatch(getKMDOPID(null, this.props.ActiveCoin.coin)); Store.dispatch(getKMDOPID(null, this.props.ActiveCoin.coin));
@ -238,11 +237,6 @@ class WalletsNativeSend extends React.Component {
<div className="col-xlg-12 col-lg-12 col-sm-12 col-xs-12"> <div className="col-xlg-12 col-lg-12 col-sm-12 col-xs-12">
<div className="panel"> <div className="panel">
<header className="panel-heading"> <header className="panel-heading">
<div className="panel-actions">
<button className="btn btn-info btn-block" id="kmd_opids_status_btn" type="button">
<i className="icon fa-repeat" aria-hidden="true"></i> {translate('INDEX.REFRESH')}
</button>
</div>
<h3 className="panel-title">{translate('INDEX.OPERATIONS_STATUSES')}</h3> <h3 className="panel-title">{translate('INDEX.OPERATIONS_STATUSES')}</h3>
</header> </header>
<div className="panel-body"> <div className="panel-body">

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

@ -24,7 +24,7 @@ class WalletsNativeTxInfo extends React.Component {
} }
render() { render() {
if (this.props && this.props.ActiveCoin.showTransactionInfo && this.props.ActiveCoin.nativeActiveSection === 'default') { if (this.props && this.props.ActiveCoin.showTransactionInfo && this.props.ActiveCoin.nativeActiveSection === 'default' && this.props.ActiveCoin.mode === 'native') {
const txInfo = this.props.ActiveCoin.txhistory[this.props.ActiveCoin.showTransactionInfoTxIndex]; const txInfo = this.props.ActiveCoin.txhistory[this.props.ActiveCoin.showTransactionInfoTxIndex];
return ( return (
@ -143,10 +143,10 @@ class WalletsNativeTxInfo extends React.Component {
</table> </table>
</div> </div>
<div className={this.state.activeTab === 2 ? 'tab-pane active' : 'tab-pane'} id="KmdTxIDInfotab3" data-extcoin="COIN" role="tabpanel"> <div className={this.state.activeTab === 2 ? 'tab-pane active' : 'tab-pane'} id="KmdTxIDInfotab3" data-extcoin="COIN" role="tabpanel">
<textarea id="kmd_txid_info_hex" data-extcoin="COIN" style={{width: '100%', height: '170px'}} rows="10" cols="80" disabled>{txInfo.hex}</textarea> <textarea id="kmd_txid_info_hex" data-extcoin="COIN" style={{width: '100%', height: '170px'}} rows="10" cols="80" defaultValue={txInfo.hex} disabled></textarea>
</div> </div>
<div className={this.state.activeTab === 3 ? 'tab-pane active' : 'tab-pane'} id="KmdTxIDInfotab4" data-extcoin="COIN" role="tabpanel"> <div className={this.state.activeTab === 3 ? 'tab-pane active' : 'tab-pane'} id="KmdTxIDInfotab4" data-extcoin="COIN" role="tabpanel">
<textarea id="kmd_txid_info_hex" data-extcoin="COIN" style={{width: '100%', height: '400px'}} rows="40" cols="80" disabled>{JSON.stringify(txInfo, null, '\t')}</textarea> <textarea id="kmd_txid_info_hex" data-extcoin="COIN" style={{width: '100%', height: '400px'}} rows="40" cols="80" defaultValue={JSON.stringify(txInfo, null, '\t')} disabled></textarea>
</div> </div>
</div> </div>
</div> </div>

121
react/src/components/dashboard/walletsTxInfo.js

@ -0,0 +1,121 @@
import React from 'react';
import { translate } from '../../translate/translate';
import { secondsToString } from '../../util/time';
import { toggleDashboardTxInfoModal } from '../../actions/actionCreators';
import Store from '../../store';
class WalletsTxInfo extends React.Component {
constructor(props) {
super(props);
this.state = {
activeTab: 0,
};
this.toggleTxInfoModal = this.toggleTxInfoModal.bind(this);
}
toggleTxInfoModal() {
Store.dispatch(toggleDashboardTxInfoModal(false));
}
openTab(tab) {
this.setState(Object.assign({}, this.state, {
activeTab: tab,
}));
}
render() {
if (this.props && this.props.ActiveCoin.showTransactionInfo && this.props.ActiveCoin.mode !== 'native') {
const txInfo = this.props.ActiveCoin.txhistory[this.props.ActiveCoin.showTransactionInfoTxIndex];
return (
<div>
<div className="modal show" data-extcoin="COIN" id="kmd_txid_info_mdl" aria-hidden="false" role="dialog">
<div className="modal-dialog modal-center modal-lg">
<div className="modal-content">
<div className="modal-body" style={{height: '590px'}}>
<div className="panel nav-tabs-horizontal">
<ul className="nav nav-tabs nav-tabs-line" data-plugin="nav-tabs" role="tablist">
<li className={this.state.activeTab === 0 ? 'active' : ''} role="presentation">
<a data-toggle="tab" data-extcoin="COIN" aria-controls="KmdTxIDInfotab1" role="tab" onClick={() => this.openTab(0)}>
<i className="icon md-balance-wallet" aria-hidden="true"></i>TxID Info
</a>
</li>
<li className={this.state.activeTab === 1 ? 'active' : ''} role="presentation">
<a data-toggle="tab" data-extcoin="COIN" aria-controls="KmdTxIDInfotab4" role="tab" onClick={() => this.openTab(1)}>
<i className="icon wb-file" aria-hidden="true"></i>Raw info
</a>
</li>
</ul>
<div className="panel-body">
<div className="tab-content">
<div className={this.state.activeTab === 0 ? 'tab-pane active' : 'tab-pane'} id="KmdTxIDInfotab1" data-extcoin="COIN" role="tabpanel">
<table className="table table-striped">
<tbody>
<tr>
<td>address</td>
<td>
{txInfo.address}
</td>
</tr>
<tr>
<td>amount</td>
<td>
{txInfo.amount}
</td>
</tr>
<tr>
<td>category</td>
<td>
{txInfo.category || txInfo.type}
</td>
</tr>
<tr>
<td>confirmations</td>
<td>
{txInfo.confirmations}
</td>
</tr>
<tr>
<td>blockhash</td>
<td>
{txInfo.blockhash}
</td>
</tr>
<tr>
<td>blocktime</td>
<td>
{secondsToString(txInfo.blocktime || txInfo.timestamp)}
</td>
</tr>
<tr>
<td>txid</td>
<td>
{txInfo.txid}
</td>
</tr>
</tbody>
</table>
</div>
<div className={this.state.activeTab === 1 ? 'tab-pane active' : 'tab-pane'} id="KmdTxIDInfotab4" data-extcoin="COIN" role="tabpanel">
<textarea id="kmd_txid_info_hex" data-extcoin="COIN" style={{width: '100%', height: '400px'}} rows="40" cols="80" defaultValue={JSON.stringify(txInfo, null, '\t')} disabled></textarea>
</div>
</div>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal" onClick={this.toggleTxInfoModal}>Close</button>
</div>
</div>
</div>
</div>
<div className="modal-backdrop show in"></div>
</div>
);
} else {
return null;
}
}
}
export default WalletsTxInfo;

3
react/src/config.js

@ -1,4 +1,5 @@
module.exports = { module.exports = {
iguanaCorePort: 7778, iguanaCorePort: 7778,
agamaPort: 17777 agamaPort: 17777,
enableCacheApi: false,
}; };

20
react/src/reducers/activeCoin.js

@ -9,7 +9,10 @@ import {
ACTIVE_COIN_GET_ADDRESSES, ACTIVE_COIN_GET_ADDRESSES,
DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE, DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE,
DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY, DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY,
DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS,
DASHBOARD_ACTIVE_COIN_SENDTO,
DASHBOARD_ACTIVE_COIN_GET_CACHE,
DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR
} from '../actions/actionCreators'; } from '../actions/actionCreators';
// TODO: keep all coin data in array of objects instead of single object // TODO: keep all coin data in array of objects instead of single object
@ -25,6 +28,9 @@ export function ActiveCoin(state = {
showTransactionInfoTxIndex: null, showTransactionInfoTxIndex: null,
txhistory: [], txhistory: [],
opids: null, opids: null,
lastSendToResponse: null,
cache: null,
mainBasiliskAddress: null,
}, action) { }, action) {
switch (action.type) { switch (action.type) {
case DASHBOARD_ACTIVE_COIN_CHANGE: case DASHBOARD_ACTIVE_COIN_CHANGE:
@ -83,6 +89,18 @@ export function ActiveCoin(state = {
return Object.assign({}, state, { return Object.assign({}, state, {
opids: action.opids, opids: action.opids,
}); });
case DASHBOARD_ACTIVE_COIN_SENDTO:
return Object.assign({}, state, {
lastSendToResponse: action.lastSendToResponse,
});
case DASHBOARD_ACTIVE_COIN_GET_CACHE:
return Object.assign({}, state, {
cache: action.cache,
});
case DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR:
return Object.assign({}, state, {
mainBasiliskAddress: action.address,
});
default: default:
return state; return state;
} }

3
react/src/styles/index.scss

@ -79,7 +79,8 @@ body {
#edexcoin_dashboardinfo a, #edexcoin_dashboardinfo a,
.nav-top-menu, .nav-top-menu,
#kmd_txid_info_mdl .nav-tabs li, #kmd_txid_info_mdl .nav-tabs li,
.pagination a { .pagination a,
.action {
cursor: pointer; cursor: pointer;
cursor: hand; cursor: hand;
} }

Loading…
Cancel
Save