Browse Source

claim interest modal

all-modes
pbca26 8 years ago
parent
commit
7b138a9489
  1. 9
      react/src/actions/actionCreators.js
  2. 86
      react/src/actions/actions/interest.js
  3. 1
      react/src/actions/actions/log.js
  4. 43
      react/src/actions/actions/nativeSend.js
  5. 2
      react/src/actions/actions/nativeSyncInfo.js
  6. 3
      react/src/actions/storeType.js
  7. 118
      react/src/components/dashboard/claimInterestModal/claimInterestModal.js
  8. 140
      react/src/components/dashboard/claimInterestModal/claimInterestModal.render.js
  9. 6
      react/src/components/dashboard/navbar/navbar.js
  10. 2
      react/src/components/dashboard/navbar/navbar.render.js
  11. 7
      react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.js
  12. 10
      react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.render.js
  13. 44
      react/src/components/overrides.scss
  14. 13
      react/src/reducers/dashboard.js

9
react/src/actions/actionCreators.js

@ -27,6 +27,7 @@ import {
DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY,
DISPLAY_LOGIN_SETTINGS_MODAL,
DISPLAY_COIND_DOWN_MODAL,
DISPLAY_CLAIM_INTEREST_MODAL,
START_INTERVAL,
STOP_INTERVAL
} from './storeType';
@ -69,6 +70,7 @@ export * from './actions/iguanaHelpers';
export * from './actions/cli';
export * from './actions/update';
export * from './actions/jumblr';
export * from './actions/interest';
export function changeActiveAddress(address) {
return {
@ -367,4 +369,11 @@ export function toggleLoginSettingsModal(display) {
type: DISPLAY_LOGIN_SETTINGS_MODAL,
displayLoginSettingsModal: display,
}
}
export function toggleClaimInterestModal(display) {
return {
type: DISPLAY_CLAIM_INTEREST_MODAL,
displayClaimInterestModal: display,
}
}

86
react/src/actions/actions/interest.js

@ -0,0 +1,86 @@
import {
triggerToaster
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getListUnspent(coin) {
return new Promise((resolve, reject) => {
const payload = {
mode: null,
chain: coin,
cmd: 'listunspent',
};
const _fetchConfig = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'payload': payload }),
};
fetch(
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`,
_fetchConfig
)
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getListUnspent',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
resolve(json.result ? json.result : json);
})
});
}
export function getRawTransaction(coin, txid) {
return new Promise((resolve, reject) => {
const payload = {
mode: null,
chain: coin,
cmd: 'getrawtransaction',
params: [
txid,
1
],
};
const _fetchConfig = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'payload': payload }),
};
fetch(
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`,
_fetchConfig
)
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getTransaction',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
resolve(json.result ? json.result : json);
})
});
}

1
react/src/actions/actions/log.js

@ -41,7 +41,6 @@ export function getAgamaLog(type) {
);
})
.then(response => response.json())
.then()
}
}

43
react/src/actions/actions/nativeSend.js

@ -195,7 +195,7 @@ export function getKMDOPID(opid, coin) {
passthruAgent = getPassthruAgent(coin),
tmpIguanaRPCAuth = `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`;
if (passthruAgent == 'iguana') {
if (passthruAgent === 'iguana') {
payload = {
'userpass': tmpIguanaRPCAuth,
'agent': passthruAgent,
@ -284,4 +284,45 @@ export function getKMDOPID(opid, coin) {
})
})
}
}
export function sendFromPromise(coin, address, amount) {
return new Promise((resolve, reject) => {
const payload = {
mode: null,
chain: coin,
cmd: 'sendfrom',
params: [
address,
amount
]
};
const _fetchConfig = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'payload': payload }),
};
fetch(
`http://127.0.0.1:${Config.agamaPort}/shepherd/cli`,
_fetchConfig
)
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'sendFrom',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
resolve(json.result ? json.result : json);
})
});
}

2
react/src/actions/actions/nativeSyncInfo.js

@ -13,7 +13,7 @@ import Config from '../../config';
export function getSyncInfoNativeKMD(skipDebug, json) {
const coin = 'KMD';
// https://www.kmd.host/
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {

3
react/src/actions/storeType.js

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

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

@ -0,0 +1,118 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Store from '../../../store';
import {
toggleClaimInterestModal,
getListUnspent,
getRawTransaction,
copyString,
sendFromPromise
} from '../../../actions/actionCreators';
import { translate } from '../../../translate/translate';
import {
ClaimInterestModalRender,
_ClaimInterestTableRender
} from './claimInterestModal.render';
class ClaimInterestModal extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
isLoading: true,
transactionsList: [],
showZeroInterest: true,
};
this.claimInterestTableRender = this.claimInterestTableRender.bind(this);
this.toggleZeroInterest = this.toggleZeroInterest.bind(this);
this.loadListUnspent = this.loadListUnspent.bind(this);
this.checkTransactionsListLength = this.checkTransactionsListLength.bind(this);
}
componentWillMount() {
this.loadListUnspent();
}
loadListUnspent() {
let _transactionsList = [];
getListUnspent('KMD')
.then((json) => {
if (json &&
json.length) {
for (let i = 0; i < json.length; i++) {
getRawTransaction('KMD', json[i].txid)
.then((_json) => {
_transactionsList.push({
address: json[i].address,
locktime: _json.locktime,
amount: json[i].amount,
interest: json[i].interest,
txid: json[i].txid,
});
if (i === json.length - 1) {
this.setState({
transactionsList: _transactionsList,
isLoading: false,
});
}
});
}
}
});
}
claimInterest(address, amount) {
console.warn('claim interest', `${address} ${amount}`);
/*sendFromPromise(address, amount)
.then((json) => {
console.warn(json);
});*/
}
checkTransactionsListLength() {
if (this.state.transactionsList && this.state.transactionsList.length) {
return true;
} else if (!this.state.transactionsList || !this.state.transactionsList.length) {
return false;
}
}
toggleZeroInterest() {
this.setState({
showZeroInterest: !this.state.showZeroInterest,
});
}
copyTxId(txid) {
Store.dispatch(copyString(txid, 'Transaction ID copied'));
}
claimInterestTableRender() {
return _ClaimInterestTableRender.call(this);
}
componentWillReceiveProps(props) {
if (props.Dashboard.displayClaimInterestModal !== this.state.open) {
this.setState({
open: props.Dashboard.displayClaimInterestModal,
});
}
if (!this.state.open &&
props.Dashboard.displayClaimInterestModal) {
this.loadListUnspent();
}
}
closeModal() {
Store.dispatch(toggleClaimInterestModal(false));
}
render() {
return ClaimInterestModalRender.call(this);
}
}
export default ClaimInterestModal;

140
react/src/components/dashboard/claimInterestModal/claimInterestModal.render.js

@ -0,0 +1,140 @@
import React from 'react';
import { translate } from '../../../translate/translate';
const MIN_INTEREST_THRESHOLD = 0.001;
export const _ClaimInterestTableRender = function() {
const _transactionsList = this.state.transactionsList;
let _items = [];
for (let i = 0; i < _transactionsList.length; i++) {
if ((_transactionsList[i].interest === 0 && this.state.showZeroInterest) || (_transactionsList[i].amount > 0 && _transactionsList[i].interest > 0)) {
_items.push(
<tr key={ `${_transactionsList[i].txid}${_transactionsList[i].address}` }>
<td>
<button
className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this.copyTxId(_transactionsList[i].txid) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</td>
<td>{ _transactionsList[i].address }</td>
<td className={ _transactionsList[i].amount > 10 ? 'green bold' : '' }>{ _transactionsList[i].amount }</td>
<td>{ _transactionsList[i].interest }</td>
<td className="locktime center">
{ _transactionsList[i].locktime &&
<i className="fa-check-circle green"></i>
}
{ !_transactionsList[i].locktime &&
<i className="fa-exclamation-circle red"></i>
}
</td>
<td>
<button
type="button"
className={ 'btn btn-success waves-effect waves-light' + (_transactionsList[i].interest < MIN_INTEREST_THRESHOLD ? ' show' : '') }
onClick={ () => this.claimInterest(_transactionsList[i].address, _transactionsList[i].amount) }>
<i className="icon fa-dollar"></i> Claim
</button>
</td>
</tr>
);
}
}
return (
<span>
<div className="padding-bottom-20">
<strong>Requirements to accure interest:</strong> locktime field is set and amount is greater than 10 KMD
</div>
<div className="text-left padding-top-10 padding-bottom-10">
<label className="switch">
<input
type="checkbox"
checked={ this.state.showZeroInterest } />
<div
className="slider"
onClick={ this.toggleZeroInterest }></div>
</label>
<div
className="toggle-label margin-right-15 pointer"
onClick={ this.toggleZeroInterest }>
Show zero interest
</div>
</div>
<div className="table-scroll">
<table className="table table-hover dataTable table-striped">
<thead>
<tr>
<th></th>
<th>Address</th>
<th>Amount</th>
<th>Interest</th>
<th>Locktime</th>
<th></th>
</tr>
</thead>
<tbody>
{ _items }
</tbody>
<tfoot>
<tr>
<th></th>
<th>Address</th>
<th>Amount</th>
<th>Interest</th>
<th>Locktime</th>
<th></th>
</tr>
</tfoot>
</table>
</div>
</span>
);
};
//{ this.renderAddressList('public') }
//{ this.isNativeMode() && this.renderAddressList('private') }
export const ClaimInterestModalRender = function() {
return (
<span>
<div className={ 'modal modal-claim-interest modal-3d-sign ' + (this.state.open ? 'show in' : 'fade hide') }>
<div className="modal-dialog modal-center modal-sm">
<div className="modal-content">
<div className="modal-header bg-orange-a400 wallet-send-header">
<button
type="button"
className="close white"
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">Claim interest</h4>
</div>
<div className="modal-body">
<i
className="icon fa-refresh pointer refresh-icon"
onClick={ this.loadListUnspent }></i>
<div className="animsition vertical-align fade-in">
<div className="page-content vertical-align-middle full-width">
{ this.state.isLoading &&
<span>Loading interest data...</span>
}
{ !this.state.isLoading && this.checkTransactionsListLength() &&
<div>{ this.claimInterestTableRender() }</div>
}
{ !this.state.isLoading && !this.checkTransactionsListLength() &&
<div>No data</div>
}
</div>
</div>
</div>
</div>
</div>
</div>
<div className={ 'modal-backdrop ' + (this.state.open ? 'show in' : 'fade hide') }></div>
</span>
);
};

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

@ -10,6 +10,7 @@ import {
} from '../../../actions/actionCreators';
import Store from '../../../store';
import Config from '../../../config';
import { checkAC } from '../../addcoin/payload';
import NavbarRender from './navbar.render';
@ -23,6 +24,7 @@ class Navbar extends React.Component {
this.openDropMenu = this.openDropMenu.bind(this);
this.logout = this.logout.bind(this);
this.handleClickOutside = this.handleClickOutside.bind(this);
this._checkAC = this._checkAC.bind(this);
}
componentWillMount() {
@ -67,6 +69,10 @@ class Navbar extends React.Component {
Store.dispatch(dashboardChangeSection(sectionName));
}
_checkAC() {
return checkAC(this.props.ActiveCoin.coin);
}
logout() {
Store.dispatch(
stopInterval(

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

@ -57,7 +57,7 @@ const NavbarRender = function() {
<i className="site-menu-icon"></i> BarterDEX
</a>
</li>
{ this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native' &&
{ this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native' && (this._checkAC() || this.props.ActiveCoin.coin === 'KMD') &&
<li className={ this.isSectionActive('jumblr') ? 'active nav-top-menu' : 'nav-top-menu' }>
<a onClick={ () => this.dashboardChangeSection('jumblr') }>
<i className="site-menu-icon"></i> Jumblr

7
react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.js

@ -1,9 +1,16 @@
import React from 'react';
import { toggleClaimInterestModal } from '../../../actions/actionCreators';
import Store from '../../../store';
import WalletsNativeInfoRender from './walletsNativeInfo.render';
class WalletsNativeInfo extends React.Component {
constructor(props) {
super(props);
this.openClaimInterestModal = this.openClaimInterestModal.bind(this);
}
openClaimInterestModal() {
Store.dispatch(toggleClaimInterestModal(true));
}
render() {

10
react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.render.js

@ -1,5 +1,6 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import ClaimInterestModal from '../claimInterestModal/claimInterestModal';
const WalletsNativeInfoRender = function() {
return (
@ -40,6 +41,15 @@ const WalletsNativeInfoRender = function() {
</table>
</div>
</div>
{ this.props.ActiveCoin.coin === 'KMD' &&
<div>
<button
type="button"
className="btn btn-success waves-effect waves-light margin-top-20 btn-next"
onClick={ () => this.openClaimInterestModal() }>Claim interest</button>
<ClaimInterestModal {...this.props} />
</div>
}
</div>
<div className="col-xlg-6 col-md-8">

44
react/src/components/overrides.scss

@ -836,4 +836,48 @@ select{
padding: 0;
}
}
}
.modal-claim-interest {
.modal-dialog {
width: 70%;
.table > tbody > tr > td,
.table > tbody > tr > th,
.table > tfoot > tr > td,
.table > tfoot > tr > th,
.table > thead > tr > td,
.table > thead > tr > th {
padding: 8px 30px 8px 0;
}
.table-scroll {
height: 366px;
overflow-y: auto;
overflow-x: hidden;
width: 100%;
}
.bold {
font-weight: bold;
}
.green {
color: #66bb6a;
}
.red {
color: #f96868;
}
.locktime {
i {
font-size: 20px;
line-height: 1.1;
}
}
.refresh-icon {
position: absolute;
right: 20px;
font-size: 20px;
z-index: 100;
}
}
}

13
react/src/reducers/dashboard.js

@ -9,14 +9,15 @@ import {
VIEW_CACHE_DATA,
LOG_GUI_HTTP,
TOGGLE_NOTIFICATIONS_MODAL,
DISPLAY_COIND_DOWN_MODAL
DISPLAY_COIND_DOWN_MODAL,
DISPLAY_CLAIM_INTEREST_MODAL
} from '../actions/storeType';
const HTTP_STACK_MAX_ENTRIES = 150; // limit stack mem length to N records per type
const trimHTTPLogs = (logObject) => {
const logObjectArray = Object.keys(logObject);
if (logObjectArray.length - HTTP_STACK_MAX_ENTRIES === 1) {
delete logObject[logObjectArray.shift()];
}
@ -38,6 +39,7 @@ export function Dashboard(state = {
},
guiLog: {},
displayCoindDownModal: false,
displayClaimInterestModal: false,
}, action) {
switch (action.type) {
case DASHBOARD_SECTION_CHANGE:
@ -95,7 +97,7 @@ export function Dashboard(state = {
const logItem = { [actionTS]: action.log };
newLogState = trimHTTPLogs(Object.assign({}, logState, logItem));
}
return Object.assign({}, state, {
guiLog: newLogState,
});
@ -104,6 +106,11 @@ export function Dashboard(state = {
displayCoindDownModal: action.displayCoindDownModal,
});
break;
case DISPLAY_CLAIM_INTEREST_MODAL:
return Object.assign({}, state, {
displayClaimInterestModal: action.displayClaimInterestModal,
});
break;
default:
return state;
}

Loading…
Cancel
Save