diff --git a/react/src/actions/actions/nativeSend.js b/react/src/actions/actions/nativeSend.js
index d68692d..3f96919 100644
--- a/react/src/actions/actions/nativeSend.js
+++ b/react/src/actions/actions/nativeSend.js
@@ -1,4 +1,7 @@
-import { DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS } from '../storeType';
+import {
+ DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS,
+ DASHBOARD_ACTIVE_COIN_SENDTO
+} from '../storeType';
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
@@ -106,6 +109,7 @@ export function sendNativeTx(coin, _payload) {
);
}
} else {
+ dispatch(sendToAddressState(JSON.parse(json).result));
dispatch(
triggerToaster(
translate('TOASTR.TX_SENT_ALT'),
@@ -127,88 +131,41 @@ export function getKMDOPIDState(json) {
// remove
export function getKMDOPID(opid, coin) {
- let tmpopidOutput = '';
- let ajaxDataToHex;
-
- if (opid === undefined) {
- ajaxDataToHex = null;
- } else {
- ajaxDataToHex = `["${opid}"]`;
- }
-
return dispatch => {
- return iguanaHashHex(ajaxDataToHex, dispatch).then((hashHexJson) => {
- if (hashHexJson === '5b226e756c6c225d00') {
- hashHexJson = '';
- }
-
- let payload;
- let passthruAgent = getPassthruAgent(coin);
- let tmpIguanaRPCAuth = `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`;
-
- if (passthruAgent === 'iguana') {
- payload = {
- userpass: tmpIguanaRPCAuth,
- agent: passthruAgent,
- method: 'passthru',
- asset: coin,
- function: 'z_getoperationstatus',
- hex: hashHexJson,
- };
- } else {
- payload = {
- userpass: tmpIguanaRPCAuth,
- agent: passthruAgent,
- method: 'passthru',
- function: 'z_getoperationstatus',
- hex: hashHexJson,
- };
- }
-
- let _fetchConfig = {
- method: 'POST',
- body: JSON.stringify(payload),
- };
-
- if (Config.cli.default) {
- payload = {
- mode: null,
- chain: coin,
- cmd: 'z_getoperationstatus',
- };
+ const payload = {
+ mode: null,
+ chain: coin,
+ cmd: 'z_getoperationstatus',
+ };
- _fetchConfig = {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ payload: payload }),
- };
- }
+ const _fetchConfig = {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ payload: payload }),
+ };
- fetch(
- Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
- _fetchConfig
- )
- .catch(function(error) {
- console.log(error);
- dispatch(
- triggerToaster(
- 'getKMDOPID',
- 'Error',
- 'error'
- )
- );
- })
- .then(response => response.json())
- .then(json => {
- if (Config.cli.default) {
- json = json.result;
- }
- dispatch(getKMDOPIDState(json));
- })
+ fetch(
+ `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`,
+ _fetchConfig
+ )
+ .catch(function(error) {
+ console.log(error);
+ dispatch(
+ triggerToaster(
+ 'getKMDOPID',
+ 'Error',
+ 'error'
+ )
+ );
})
- }
+ .then(response => response.json())
+ .then(json => {
+ json = json.result;
+ dispatch(getKMDOPIDState(json));
+ })
+ };
}
export function sendToAddressPromise(coin, address, amount) {
@@ -253,4 +210,18 @@ export function sendToAddressPromise(coin, address, amount) {
resolve(json);
});
});
+}
+
+export function sendToAddressState(json) {
+ return {
+ type: DASHBOARD_ACTIVE_COIN_SENDTO,
+ lastSendToResponse: json,
+ }
+}
+
+export function clearLastSendToResponseState() {
+ return {
+ type: DASHBOARD_ACTIVE_COIN_SENDTO,
+ lastSendToResponse: null,
+ }
}
\ No newline at end of file
diff --git a/react/src/components/dashboard/_sendCoin/sendCoin.js b/react/src/components/dashboard/_sendCoin/sendCoin.js
new file mode 100644
index 0000000..d7cf602
--- /dev/null
+++ b/react/src/components/dashboard/_sendCoin/sendCoin.js
@@ -0,0 +1,917 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import Config from '../../../config';
+import { translate } from '../../../translate/translate';
+import { checkTimestamp } from '../../../util/time';
+import {
+ edexGetTxIDList,
+ edexRemoveTXID
+} from '../../../util/cacheFormat';
+import {
+ resolveOpenAliasAddress,
+ triggerToaster,
+ shepherdGroomPostPromise,
+ edexGetTransaction,
+ getCacheFile,
+ fetchUtxoCache,
+ sendToAddress,
+ iguanaUTXORawTX,
+ clearLastSendToResponseState,
+ sendToAddressStateAlt,
+ dexSendRawTX
+} from '../../../actions/actionCreators';
+import Store from '../../../store';
+import {
+ UTXOCacheInfoRender,
+ SendCoinResponseRender,
+ OASendUIRender,
+ SendApiTypeSelectorRender,
+ SendCoinRender
+} from './sendCoin.render';
+
+import io from 'socket.io-client';
+import { isPositiveNumber } from '../../../util/number';
+const socket = io.connect(`http://127.0.0.1:${Config.agamaPort}`);
+
+// TODO: prevent any cache updates rather than utxo while on send coin form
+// fix a bug - total amount is incorrect when switching between steps
+
+class SendCoin extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ currentStep: 0,
+ sendFrom: this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : null,
+ sendFromAmount: 0,
+ sendTo: '',
+ sendToOA: null,
+ amount: 0,
+ fee: 0.0001,
+ sendSig: false,
+ sendApiType: true,
+ addressSelectorOpen: false,
+ currentStackLength: 0,
+ totalStackLength: 0,
+ utxoMethodInProgress: false,
+ };
+ this.updateInput = this.updateInput.bind(this);
+ this.handleBasiliskSend = this.handleBasiliskSend.bind(this);
+ this.openDropMenu = this.openDropMenu.bind(this);
+ this.toggleSendSig = this.toggleSendSig.bind(this);
+ this.getOAdress = this.getOAdress.bind(this);
+ this.toggleSendAPIType = this.toggleSendAPIType.bind(this);
+ this._fetchNewUTXOData = this._fetchNewUTXOData.bind(this);
+ this.handleClickOutside = this.handleClickOutside.bind(this);
+ this.setRecieverFromScan = this.setRecieverFromScan.bind(this);
+ socket.on('messages', msg => this.updateSocketsData(msg));
+ }
+
+ setRecieverFromScan(receiver) {
+ try {
+ const recObj = JSON.parse(receiver);
+
+ if (recObj &&
+ typeof recObj === 'object') {
+ if (recObj.coin === this.props.ActiveCoin.coin) {
+ if (recObj.amount) {
+ this.setState({
+ amount: recObj.amount,
+ });
+ }
+ if (recObj.address) {
+ this.setState({
+ sendTo: recObj.address,
+ });
+ }
+ } else {
+ Store.dispatch(
+ triggerToaster(
+ translate('SEND.QR_COIN_MISMATCH_MESSAGE_IMPORT_COIN') +
+ recObj.coin +
+ translate('SEND.QR_COIN_MISMATCH_MESSAGE_ACTIVE_COIN') +
+ this.props.ActiveCoin.coin +
+ translate('SEND.QR_COIN_MISMATCH_MESSAGE_END'),
+ translate('SEND.QR_COIN_MISMATCH_TITLE'),
+ 'warning'
+ )
+ );
+ }
+ }
+ } catch (e) {
+ this.setState({
+ sendTo: receiver,
+ });
+ }
+
+ document.getElementById('edexcoinSendTo').focus();
+ }
+
+ componentWillMount() {
+ document.addEventListener(
+ 'click',
+ this.handleClickOutside,
+ false
+ );
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener(
+ 'click',
+ this.handleClickOutside,
+ false
+ );
+ }
+
+ handleClickOutside(e) {
+ if (e.srcElement.className !== 'btn dropdown-toggle btn-info' &&
+ (e.srcElement.offsetParent && e.srcElement.offsetParent.className !== 'btn dropdown-toggle btn-info') &&
+ (e.path && e.path[4] && e.path[4].className.indexOf('showkmdwalletaddrs') === -1)) {
+ this.setState({
+ addressSelectorOpen: false,
+ });
+ }
+ }
+
+ componentWillReceiveProps(props) {
+ if (this.state &&
+ !this.state.sendFrom &&
+ this.props.ActiveCoin.activeAddress) {
+ this.setState(Object.assign({}, this.state, {
+ sendFrom: this.props.ActiveCoin.activeAddress,
+ }));
+ }
+ }
+
+ updateSocketsData(data) {
+ if (data &&
+ data.message &&
+ data.message.shepherd.iguanaAPI &&
+ data.message.shepherd.iguanaAPI.totalStackLength) {
+ this.setState(Object.assign({}, this.state, {
+ totalStackLength: data.message.shepherd.iguanaAPI.totalStackLength,
+ }));
+ }
+ if (data &&
+ data.message &&
+ data.message.shepherd.iguanaAPI &&
+ data.message.shepherd.iguanaAPI.currentStackLength) {
+ this.setState(Object.assign({}, this.state, {
+ currentStackLength: data.message.shepherd.iguanaAPI.currentStackLength,
+ }));
+ }
+ }
+
+ _fetchNewUTXOData() {
+ Store.dispatch(fetchUtxoCache({
+ pubkey: this.props.Dashboard.activeHandle.pubkey,
+ allcoins: false,
+ coin: this.props.ActiveCoin.coin,
+ calls: 'refresh',
+ address: this.state.sendFrom,
+ }));
+ }
+
+ renderUTXOCacheInfo() {
+ if (this.props.ActiveCoin.mode === 'basilisk' &&
+ this.state.sendFrom &&
+ !this.state.sendApiType &&
+ this.props.ActiveCoin.cache &&
+ this.props.ActiveCoin.cache[this.props.ActiveCoin.coin][this.state.sendFrom]) {
+ let refreshCacheData;
+ let timestamp;
+ let isReadyToUpdate;
+ let waitUntilCallIsFinished = this.state.currentStackLength > 1 ? true : false;
+ const _cache = this.props.ActiveCoin.cache;
+ const _coin = this.props.ActiveCoin.coin;
+ const _sendFrom = this.state.sendFrom;
+
+ if (_cache[_coin][_sendFrom].refresh ||
+ _cache[_coin][_sendFrom].listunspent) {
+ refreshCacheData = _cache[_coin][_sendFrom].refresh || _cache[_coin][_sendFrom].listunspent;
+ timestamp = checkTimestamp(refreshCacheData.timestamp);
+ isReadyToUpdate = timestamp > 600 ? true : false;
+ } else {
+ isReadyToUpdate = true;
+ }
+
+ if (_cache[_coin][_sendFrom].refresh &&
+ _cache[_coin][_sendFrom].refresh.data &&
+ _cache[_coin][_sendFrom].refresh.data.error &&
+ _cache[_coin][_sendFrom].refresh.data.error === 'request failed') {
+ timestamp = null;
+ }
+
+ return UTXOCacheInfoRender.call(
+ this,
+ refreshCacheData,
+ isReadyToUpdate,
+ waitUntilCallIsFinished,
+ timestamp
+ );
+ }
+
+ return null;
+ }
+
+ renderAddressAmount(address) {
+ const _addresses = this.props.ActiveCoin.addresses;
+
+ if (_addresses &&
+ _addresses.public &&
+ _addresses.public.length) {
+ for (let i = 0; i < _addresses.public.length; i++) {
+ if (_addresses.public[i].address === address) {
+ if (_addresses.public[i].amount !== 'N/A') {
+ return _addresses.public[i].amount;
+ }
+ }
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ renderAddressByType(type) {
+ const _addresses = this.props.ActiveCoin.addresses;
+
+ if (_addresses &&
+ _addresses[type] &&
+ _addresses[type].length) {
+ if (this.state.sendApiType) {
+ const mainAddress = this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin];
+ const mainAddressAmount = this.renderAddressAmount(mainAddress);
+
+ return(
+
+ this.updateAddressSelection(mainAddress, type, mainAddressAmount) }>
+
+
+ [ { mainAddressAmount } { this.props.ActiveCoin.coin } ]
+ { mainAddress }
+
+
+
+
+ );
+ } else {
+ let items = [];
+ const _addresses = this.props.ActiveCoin.addresses;
+ const _cache = this.props.ActiveCoin.cache;
+ const _coin = this.props.ActiveCoin.coin;
+
+ for (let i = 0; i < _addresses[type].length; i++) {
+ const address = _addresses[type][i].address;
+ let _amount = address.amount;
+
+ if (this.props.ActiveCoin.mode === 'basilisk' &&
+ _cache) {
+ _amount = _cache[_coin][address] && _cache[_coin][address].getbalance.data && _cache[_coin][address].getbalance.data.balance ? _cache[_coin][address].getbalance.data.balance : 'N/A';
+ }
+
+ if (_amount !== 'N/A') {
+ items.push(
+
+ this.updateAddressSelection(address, type, _amount) }>
+
+ [ { _amount } { _coin } ] { address }
+
+
+
+ );
+ }
+ }
+
+ return items;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ renderSelectorCurrentLabel() {
+ if (this.state.sendFrom) {
+ let _amount;
+ const _cache = this.props.ActiveCoin.cache;
+ const _coin = this.props.ActiveCoin.coin;
+ const _sendFrom = this.state.sendFrom;
+
+ if (this.state.sendFromAmount === 0 &&
+ this.props.ActiveCoin.mode === 'basilisk' &&
+ _cache) {
+ _amount = _cache[_coin][_sendFrom].getbalance.data && _cache[_coin][_sendFrom].getbalance.data.balance ? _cache[_coin][_sendFrom].getbalance.data.balance : 'N/A';
+ } else {
+ _amount = this.state.sendFromAmount;
+ }
+
+ return (
+
+
+ [ { _amount } { _coin } ] { _sendFrom }
+
+ );
+ } else if (this.state.sendApiType) {
+ const mainAddress = this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin];
+ const mainAddressAmount = this.renderAddressAmount(mainAddress);
+
+ return (
+
+
+ [ { mainAddressAmount } { this.props.ActiveCoin.coin } ] { mainAddress }
+
+ );
+ } else {
+ return (
+ { translate('SEND.SELECT_T_OR_Z_ADDR') }
+ );
+ }
+ }
+
+ renderAddressList() {
+ return (
+
+
+
+
+ );
+ }
+
+ openDropMenu() {
+ this.setState(Object.assign({}, this.state, {
+ addressSelectorOpen: !this.state.addressSelectorOpen,
+ }));
+ }
+
+ updateAddressSelection(address, type, amount) {
+ let _sendFromAmount = amount ? amount : this.props.ActiveCoin.addresses[type][address].amount;
+ const _cache = this.props.ActiveCoin.cache;
+ const _coin = this.props.ActiveCoin.coin;
+
+ if (this.props.ActiveCoin.mode === 'basilisk' &&
+ this.props.ActiveCoin.cache) {
+ _sendFromAmount = _cache[_coin][address].getbalance.data && _cache[_coin][address].getbalance.data.balance ? _cache[_coin][address].getbalance.data.balance : 'N/A';
+ }
+
+ this.setState(Object.assign({}, this.state, {
+ sendFrom: address,
+ addressType: type,
+ sendFromAmount: _sendFromAmount,
+ addressSelectorOpen: !this.state.addressSelectorOpen,
+ }));
+ }
+
+ changeSendCoinStep(step) {
+ if (step === 0) {
+ Store.dispatch(clearLastSendToResponseState());
+
+ this.setState({
+ currentStep: 0,
+ sendFrom: this.props.Dashboard && this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : null,
+ sendFromAmount: 0,
+ sendTo: '',
+ sendToOA: null,
+ amount: 0,
+ fee: 0.0001,
+ sendSig: false,
+ sendApiType: true,
+ addressSelectorOpen: false,
+ currentStackLength: 0,
+ totalStackLength: 0,
+ utxoMethodInProgress: false,
+ });
+ }
+
+ if (step === 1) {
+ if (!this.validateSendFormData()) {
+ return;
+ }
+ }
+
+ if (step === 1 ||
+ step === 2) {
+ this.setState(Object.assign({}, this.state, {
+ currentStep: step,
+ utxoMethodInProgress: !this.state.sendApiType && this.props.ActiveCoin.mode === 'basilisk' ? true : false,
+ }));
+ }
+
+ if (step === 2) {
+ if (!this.state.sendApiType &&
+ this.props.ActiveCoin.mode === 'basilisk') {
+ this.handleBasiliskSend();
+ } else {
+ Store.dispatch(
+ sendToAddress(
+ this.props.ActiveCoin.coin,
+ this.state
+ )
+ );
+ }
+ }
+ }
+
+ toggleSendSig() {
+ this.setState(Object.assign({}, this.state, {
+ sendSig: !this.state.sendSig,
+ }));
+ }
+
+ toggleSendAPIType() {
+ this.setState(Object.assign({}, this.state, {
+ sendApiType: !this.state.sendApiType,
+ fee: !this.state.sendApiType ? 0 : 0.0001,
+ sendFrom: this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin],
+ }));
+ }
+
+ updateInput(e) {
+ this.setState({
+ [e.target.name]: e.target.value,
+ });
+ }
+
+ // TODO: move to action creators
+ handleBasiliskSend() {
+ const refreshData = this.props.ActiveCoin.cache[this.props.ActiveCoin.coin][this.state.sendFrom].refresh;
+ const listunspentData = this.props.ActiveCoin.cache[this.props.ActiveCoin.coin][this.state.sendFrom].listunspent;
+ const utxoSet = (refreshData && refreshData.data) || (listunspentData && listunspentData.data);
+ const _pubkey = this.props.Dashboard.activeHandle.pubkey;
+ const forceUpdateCache = this._fetchNewUTXOData;
+ const _sendFrom = this.state.sendFrom;
+ const sendData = {
+ coin: this.props.ActiveCoin.coin,
+ sendfrom: this.state.sendFrom,
+ sendtoaddr: this.state.sendTo,
+ amount: this.state.amount,
+ txfee: this.state.fee,
+ sendsig: this.state.sendSig === true ? 0 : 1,
+ utxos: utxoSet,
+ };
+
+ // TODO: es arrows
+ iguanaUTXORawTX(sendData, Store.dispatch)
+ .then(function(json) {
+ if (json.result === 'success' &&
+ json.completed === true) {
+ Store.dispatch(
+ triggerToaster(
+ translate('TOASTR.SIGNED_TX_GENERATED'),
+ translate('TOASTR.WALLET_NOTIFICATION'),
+ 'success'
+ )
+ );
+
+ if (sendData.sendsig === 1) {
+ const dexrawtxData = {
+ signedtx: json.signedtx,
+ coin: sendData.coin,
+ };
+ dexSendRawTX(
+ dexrawtxData,
+ Store.dispatch
+ ).then(function(dexRawTxJSON) {
+ if (dexRawTxJSON.indexOf('"error":{"code"') > -1) {
+ Store.dispatch(
+ triggerToaster(
+ translate('TOASTR.TRANSACTION_FAILED'),
+ translate('TOASTR.WALLET_NOTIFICATION'),
+ 'error'
+ )
+ );
+ Store.dispatch(sendToAddressStateAlt(JSON.parse(dexRawTxJSON)));
+
+ this.setState(Object.assign({}, this.state, {
+ utxoMethodInProgress: false,
+ }));
+ } else {
+ Store.dispatch(
+ triggerToaster(
+ translate('TOASTR.SIGNED_TX_SENT'),
+ translate('TOASTR.WALLET_NOTIFICATION'),
+ 'success'
+ )
+ );
+ Store.dispatch(sendToAddressStateAlt(json));
+
+ let getTxidData = function() {
+ return new Promise(function(resolve, reject) {
+ Store.dispatch(
+ triggerToaster(
+ translate('TOASTR.GETTING_TXID_INFO'),
+ translate('TOASTR.WALLET_NOTIFICATION'),
+ 'info'
+ )
+ );
+
+ edexGetTransaction({
+ coin: sendData.coin,
+ txid: dexRawTxJSON.txid ? dexRawTxJSON.txid : dexRawTxJSON,
+ }, Store.dispatch)
+ .then(function(json) {
+ resolve(json);
+ });
+ });
+ }
+
+ let processRefreshUTXOs = function(vinData) {
+ return new Promise(function(resolve, reject) {
+ let edexGetTxIDListRes = edexGetTxIDList(vinData);
+ resolve(edexGetTxIDListRes);
+ });
+ }
+
+ let getDataCacheContents = function(txidListToRemove) {
+ return new Promise(function(resolve, reject) {
+ getCacheFile(_pubkey)
+ .then(function(result) {
+ let saveThisData = edexRemoveTXID(result.result, _sendFrom, txidListToRemove);
+ resolve(saveThisData);
+ });
+ });
+ }
+
+ let saveNewCacheData = function(saveThisData) {
+ return new Promise(function(resolve, reject) {
+ shepherdGroomPostPromise(
+ _pubkey,
+ saveThisData
+ ).then(function(result) {
+ resolve(result);
+ forceUpdateCache();
+ Store.dispatch(
+ triggerToaster(
+ translate('TOASTR.LOCAL_UTXO_UPDATED'),
+ translate('TOASTR.WALLET_NOTIFICATION'),
+ 'info'
+ )
+ );
+
+ this.setState(Object.assign({}, this.state, {
+ utxoMethodInProgress: false,
+ }));
+ }.bind(this));
+ }.bind(this));
+ }.bind(this);
+
+ Store.dispatch(
+ triggerToaster(
+ `${translate('TOASTR.AWAITING_TX_RESP')}...`,
+ translate('TOASTR.WALLET_NOTIFICATION'),
+ 'info'
+ )
+ );
+
+ function waterfallUTXOProcess() {
+ Store.dispatch(
+ triggerToaster(
+ `${translate('TOASTR.PROCESSING_UTXO')}...`,
+ translate('TOASTR.WALLET_NOTIFICATION'),
+ 'info'
+ )
+ );
+
+ getTxidData()
+ .then(function(gettxdata) {
+ return processRefreshUTXOs(gettxdata.vin);
+ })
+ .then(function(new_utxos_set) {
+ return getDataCacheContents(new_utxos_set);
+ })
+ .then(function(save_this_data) {
+ return saveNewCacheData(save_this_data);
+ });
+ }
+
+ let sentTxData = setInterval(function() {
+ getTxidData()
+ .then(function(gettxdata) {
+ if (gettxdata.vin &&
+ gettxdata.vin.length) {
+ clearInterval(sentTxData);
+ waterfallUTXOProcess();
+ }
+ })
+ }, 1000);
+ }
+ }.bind(this));
+ } else {
+ Store.dispatch(sendToAddressStateAlt(json));
+
+ this.setState(Object.assign({}, this.state, {
+ utxoMethodInProgress: false,
+ }));
+ }
+ } else {
+ Store.dispatch(sendToAddressStateAlt(json));
+ Store.dispatch(
+ triggerToaster(
+ `${translate('TOASTR.SIGNED_TX_GENERATED_FAIL')}`,
+ translate('TOASTR.WALLET_NOTIFICATION'),
+ 'error'
+ )
+ );
+
+ this.setState(Object.assign({}, this.state, {
+ utxoMethodInProgress: false,
+ }));
+ }
+
+ // console.log(json);
+ }.bind(this));
+ }
+
+ renderSignedTx(isRawTx) {
+ let substrBlocks;
+
+ if (this.props.ActiveCoin.mode === 'basilisk') {
+ substrBlocks = isRawTx ? 3 : 8;
+ } else {
+ substrBlocks = 10;
+ }
+
+ const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse[isRawTx ? 'rawtx' : 'signedtx'];
+ const substrLength = _lastSendToResponse.length / substrBlocks;
+ let out = [];
+
+ for (let i = 0; i < substrBlocks; i++) {
+ out.push(
+ { _lastSendToResponse.substring(i * substrLength, substrLength * i + substrLength) }
+ );
+ }
+
+ return out.length ? out : null;
+ }
+
+ renderKey(key) {
+ if (key === 'signedtx') {
+ return this.renderSignedTx();
+ } else if (key === 'rawtx') {
+ return this.renderSignedTx(true);
+ } else if (key === 'complete' || key === 'completed' || key === 'result') {
+ const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse;
+
+ if (_lastSendToResponse[key] === true ||
+ _lastSendToResponse[key] === 'success') {
+ return (
+ { _lastSendToResponse[key] === true ? 'true' : 'success' }
+ );
+ } else {
+ if (key === 'result' &&
+ _lastSendToResponse.result &&
+ typeof _lastSendToResponse.result !== 'object') {
+ return (
+ { _lastSendToResponse.result }
+ );
+ } else {
+ return (
+ false
+ );
+ }
+ }
+ } else if (key === 'error') {
+ const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse;
+
+ if (Object.keys(_lastSendToResponse[key]).length) {
+ return (
+ { JSON.stringify(_lastSendToResponse[key], null, '\t') }
+ );
+ } else {
+ return (
+ { _lastSendToResponse[key] }
+ );
+ }
+ } else if (key === 'sendrawtransaction') {
+ const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse;
+
+ if (_lastSendToResponse[key] === 'success') {
+ return (
+ true
+ );
+ } else {
+ return (
+ false
+ );
+ }
+ } else if (key === 'txid' || key === 'sent') {
+ const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse;
+
+ return (
+ { _lastSendToResponse[key] }
+ );
+ } else if (key === 'tag') {
+ return null;
+ }
+ }
+
+ renderSendCoinResponse() {
+ return SendCoinResponseRender.call(this);
+ }
+
+ // experimental, ask @kolo for details if required
+ getOAdress() {
+ resolveOpenAliasAddress(this.state.sendToOA)
+ .then(function(json) {
+ const reply = json.Answer;
+
+ if (reply &&
+ reply.length) {
+ for (let i = 0; i < reply.length; i++) {
+ const _address = reply[i].data.split(' ');
+ const coin = _address[0].replace('"oa1:', '');
+ const coinAddress = _address[1].replace('recipient_address=', '').replace(';', '');
+
+ if (coin.toUpperCase() === this.props.ActiveCoin.coin) {
+ this.setState(Object.assign({}, this.state, {
+ sendTo: coinAddress,
+ }));
+ }
+ }
+
+ if (this.state.sendTo === '') {
+ Store.dispatch(
+ triggerToaster(
+ 'Couldn\'t find any ' + this.props.ActiveCoin.coin + ' addresses',
+ 'OpenAlias',
+ 'error'
+ )
+ );
+ }
+ } else {
+ Store.dispatch(
+ triggerToaster(
+ 'Couldn\'t find any addresses',
+ 'OpenAlias',
+ 'error'
+ )
+ );
+ }
+ }.bind(this));
+ }
+
+ renderOASendUI() {
+ if (Config.openAlias) {
+ return OASendUIRender.call(this);
+ }
+
+ return null;
+ }
+
+ renderSendApiTypeSelector() {
+ if (this.props.ActiveCoin.mode === 'basilisk') {
+ return SendApiTypeSelectorRender.call(this);
+ }
+
+ return null;
+ }
+
+ // TODO same as in walletsNav and receiveCoin, find a way to reuse it?
+ checkBalance() {
+ let _balance = '0';
+ const _mode = this.props.ActiveCoin.mode;
+
+ if (_mode === 'full') {
+ _balance = this.props.ActiveCoin.balance || 0;
+ } else if (_mode === 'basilisk') {
+ if (this.props.ActiveCoin.cache) {
+ const _cache = this.props.ActiveCoin.cache;
+ const _coin = this.props.ActiveCoin.coin;
+ const _address = this.props.ActiveCoin.activeAddress;
+
+ if (_address &&
+ _cache[_coin] &&
+ _cache[_coin][_address] &&
+ _cache[_coin][_address].getbalance &&
+ _cache[_coin][_address].getbalance.data &&
+ (_cache[_coin][_address].getbalance.data.balance ||
+ _cache[_coin][_address].getbalance.data.interest)) {
+ const _regBalance = _cache[_coin][_address].getbalance.data.balance ? _cache[_coin][_address].getbalance.data.balance : 0;
+
+ _balance = _regBalance;
+ }
+ }
+ }
+
+ return _balance;
+ }
+
+ // TODO: reduce to a single toast
+ validateSendFormData() {
+ let valid = true;
+ if (!this.state.sendTo || this.state.sendTo.length < 34) {
+ Store.dispatch(
+ triggerToaster(
+ translate('SEND.SEND_TO_ADDRESS_MIN_LENGTH'),
+ '',
+ 'error'
+ )
+ );
+ valid = false;
+ }
+
+ if (!isPositiveNumber(this.state.amount)) {
+ Store.dispatch(
+ triggerToaster(
+ translate('SEND.AMOUNT_POSITIVE_NUMBER'),
+ '',
+ 'error'
+ )
+ );
+ valid = false;
+ }
+
+ if (!isPositiveNumber(this.state.fee)) {
+ Store.dispatch(
+ triggerToaster(
+ translate('SEND.FEE_POSITIVE_NUMBER'),
+ '',
+ 'error'
+ )
+ );
+ valid = false;
+ }
+
+ if (!isPositiveNumber(this.getTotalAmount())) {
+ Store.dispatch(
+ triggerToaster(
+ translate('SEND.TOTAL_AMOUNT_POSITIVE_NUMBER'),
+ '',
+ 'error'
+ )
+ );
+ valid = false;
+ }
+
+ /*if ((this.props.ActiveCoin.mode === 'basilisk' && Number(this.state.amount) > Number(this.state.sendFromAmount)) ||
+ (this.props.ActiveCoin.mode === 'full' && Number(this.state.amount) > Number(this.checkBalance()))) {
+ Store.dispatch(
+ triggerToaster(
+ translate('SEND.INSUFFICIENT_FUNDS'),
+ '',
+ 'error'
+ )
+ );
+ valid = false;
+ }*/
+
+ return valid;
+ }
+
+ getTotalAmount() {
+ return Number(this.state.amount) - Number(this.state.fee);
+ }
+
+ render() {
+ if (this.props.ActiveCoin &&
+ this.props.ActiveCoin.send &&
+ this.props.ActiveCoin.mode !== 'native') {
+ return SendCoinRender.call(this);
+ }
+
+ return null;
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ ActiveCoin: {
+ coin: state.ActiveCoin.coin,
+ mode: state.ActiveCoin.mode,
+ send: state.ActiveCoin.send,
+ receive: state.ActiveCoin.receive,
+ balance: state.ActiveCoin.balance,
+ cache: state.ActiveCoin.cache,
+ activeAddress: state.ActiveCoin.activeAddress,
+ lastSendToResponse: state.ActiveCoin.lastSendToResponse,
+ addresses: state.ActiveCoin.addresses,
+ },
+ Dashboard: {
+ activeHandle: state.Dashboard.activeHandle,
+ },
+ };
+};
+
+export default connect(mapStateToProps)(SendCoin);
\ No newline at end of file
diff --git a/react/src/components/dashboard/_sendCoin/sendCoin.render.js b/react/src/components/dashboard/_sendCoin/sendCoin.render.js
new file mode 100644
index 0000000..4ca3d8d
--- /dev/null
+++ b/react/src/components/dashboard/_sendCoin/sendCoin.render.js
@@ -0,0 +1,402 @@
+import React from 'react';
+import { translate } from '../../../translate/translate';
+import {
+ secondsElapsedToString,
+ secondsToString
+} from '../../../util/time';
+
+import QRModal from '../qrModal/qrModal';
+
+export const UTXOCacheInfoRender = function(refreshCacheData, isReadyToUpdate, waitUntilCallIsFinished, timestamp) {
+ const _progress = 100 - this.state.currentStackLength * 100 / this.state.totalStackLength;
+
+ return (
+
+
+ { translate('SEND.TOTAL_UTXO_AVAILABLE') }:
+ { refreshCacheData ? refreshCacheData.data && refreshCacheData.data.length : translate('SEND.PRESS_UPDATE_BTN') }
+
+ { translate('SEND.LAST_UPDATED') } @
+ { secondsToString(refreshCacheData ? refreshCacheData.timestamp : 0, true) } |
+ { secondsElapsedToString(timestamp || 0) }&nbps;
+ { translate('SEND.AGO') }
+
+
+ { translate('SEND.NEXT_UPDATE_IN') } { secondsElapsedToString(600 - timestamp) }s
+
+
+
+ { translate('SEND.PROCESSING_REQ') }: { this.state.currentStackLength } / { this.state.totalStackLength }
+
+
+
+
+ );
+};
+
+export const SendCoinResponseRender = function() {
+ if (this.props.ActiveCoin.lastSendToResponse) {
+ let items = [];
+ const _response = this.props.ActiveCoin.lastSendToResponse;
+
+ for (let key in _response) {
+ if (key !== 'tag') {
+ items.push(
+
+ { key } |
+ { this.renderKey(key) } |
+
+ );
+ }
+ }
+
+ return items;
+ } else {
+ return (
+
+
+
+
+ { translate('SEND.PROCESSING_TRANSACTION') }...
+ { translate('SEND.NOTE_IT_WILL_TAKE') }.
+
+
+
+ |
+
+ );
+ }
+}
+
+export const OASendUIRender = function() {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export const SendApiTypeSelectorRender = function() {
+ return (
+
+
+
+
+
+ { translate('SEND.SEND_VIA') } (sendtoaddress API)
+
+
+
+
+
+
+
+ );
+};
+
+export const SendCoinRender = function() {
+ return (
+
+
+
+
+
1
+
+
{ translate('INDEX.FILL_SEND_FORM') }
+
{ translate('INDEX.FILL_SEND_DETAILS') }
+
+
+
+
2
+
+
{ translate('INDEX.CONFIRMING') }
+
{ translate('INDEX.CONFIRM_DETAILS') }
+
+
+
+
3
+
+
{ translate('INDEX.PROCESSING_TX') }
+
{ translate('INDEX.PROCESSING_DETAILS') }
+
+
+
+
+
+
+
+ { translate('INDEX.SEND') } { this.props.ActiveCoin.coin }
+
+
+
+
+
+
+
+
+
+
+
+ { translate('INDEX.TO') }
+
+
{ this.state.sendTo }
+
+ { this.state.amount } { this.props.ActiveCoin.coin }
+
+
{ translate('INDEX.TX_FEE_REQ') }
+
+ { this.state.fee } { this.props.ActiveCoin.coin }
+
+
+
+
+
+
+ { translate('INDEX.FROM') }
+
+
+ { this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] }
+
+
+ { Number(this.state.amount) - Number(this.state.fee) } { this.props.ActiveCoin.coin }
+
+
+
+
+
+
+
+
+
+
+
+ { translate('INDEX.TRANSACTION_RESULT') }
+
+
+ { translate('SEND.YOU_PICKED_OPT') }
+
+
+
+
+ { translate('INDEX.KEY') } |
+ { translate('INDEX.INFO') } |
+
+
+
+ { this.renderSendCoinResponse() }
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/react/src/components/dashboard/jumblr/jumblr.render.js b/react/src/components/dashboard/jumblr/jumblr.render.js
index 0a988cd..f2c919d 100644
--- a/react/src/components/dashboard/jumblr/jumblr.render.js
+++ b/react/src/components/dashboard/jumblr/jumblr.render.js
@@ -2,7 +2,7 @@ import React from 'react';
import { translate } from '../../../translate/translate';
import WalletsHeader from '../walletsHeader/walletsHeader';
-import WalletsNativeSend from '../walletsNativeSend/walletsNativeSend';
+import SendCoin from '../sendCoin/sendCoin';
import ReceiveCoin from '../receiveCoin/receiveCoin';
export const JumblrRenderSecretAddressList = function(type) {
@@ -338,7 +338,7 @@ export const JumblrRender = function() {
{ translate('JUMBLR.DEPOSIT_FORM_P1') }
{ translate('JUMBLR.DEPOSIT_FORM_P2') }
-
diff --git a/react/src/components/dashboard/sendCoin/sendCoin.js b/react/src/components/dashboard/sendCoin/sendCoin.js
index c97cd2b..135454a 100644
--- a/react/src/components/dashboard/sendCoin/sendCoin.js
+++ b/react/src/components/dashboard/sendCoin/sendCoin.js
@@ -2,68 +2,82 @@ import React from 'react';
import { connect } from 'react-redux';
import Config from '../../../config';
import { translate } from '../../../translate/translate';
-import { checkTimestamp } from '../../../util/time';
+import { secondsToString } from '../../../util/time';
import {
- edexGetTxIDList,
- edexRemoveTXID
-} from '../../../util/cacheFormat';
-import {
- resolveOpenAliasAddress,
triggerToaster,
- shepherdGroomPostPromise,
- edexGetTransaction,
- getCacheFile,
- fetchUtxoCache,
- sendToAddress,
- iguanaUTXORawTX,
- clearLastSendToResponseState,
- sendToAddressStateAlt,
- dexSendRawTX
+ sendNativeTx,
+ getKMDOPID,
+ clearLastSendToResponseState
} from '../../../actions/actionCreators';
import Store from '../../../store';
import {
- UTXOCacheInfoRender,
- SendCoinResponseRender,
- OASendUIRender,
- SendApiTypeSelectorRender,
- SendCoinRender
+ AddressListRender,
+ SendRender,
+ SendFormRender,
+ _SendFormRender
} from './sendCoin.render';
-
-import io from 'socket.io-client';
import { isPositiveNumber } from '../../../util/number';
-const socket = io.connect(`http://127.0.0.1:${Config.agamaPort}`);
-// TODO: prevent any cache updates rather than utxo while on send coin form
-// fix a bug - total amount is incorrect when switching between steps
+// TODO: - add links to explorers
+// - render z address trim
class SendCoin extends React.Component {
constructor(props) {
super(props);
this.state = {
currentStep: 0,
- sendFrom: this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : null,
+ addressType: null,
+ sendFrom: null,
sendFromAmount: 0,
sendTo: '',
- sendToOA: null,
amount: 0,
- fee: 0.0001,
- sendSig: false,
- sendApiType: true,
+ fee: 0,
addressSelectorOpen: false,
- currentStackLength: 0,
- totalStackLength: 0,
- utxoMethodInProgress: false,
+ renderAddressDropdown: true,
+ substractFee: false,
+ lastSendToResponse: null,
+ coin: null,
};
this.updateInput = this.updateInput.bind(this);
- this.handleBasiliskSend = this.handleBasiliskSend.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
this.openDropMenu = this.openDropMenu.bind(this);
- this.toggleSendSig = this.toggleSendSig.bind(this);
- this.getOAdress = this.getOAdress.bind(this);
- this.toggleSendAPIType = this.toggleSendAPIType.bind(this);
- this._fetchNewUTXOData = this._fetchNewUTXOData.bind(this);
this.handleClickOutside = this.handleClickOutside.bind(this);
+ this.checkZAddressCount = this.checkZAddressCount.bind(this);
this.setRecieverFromScan = this.setRecieverFromScan.bind(this);
- socket.on('messages', msg => this.updateSocketsData(msg));
+ this.renderOPIDListCheck = this.renderOPIDListCheck.bind(this);
+ this.SendFormRender = _SendFormRender.bind(this);
+ this.isTransparentTx = this.isTransparentTx.bind(this);
+ this.toggleSubstractFee = this.toggleSubstractFee.bind(this);
+ }
+
+ SendFormRender() {
+ return _SendFormRender.call(this);
+ }
+
+ toggleSubstractFee() {
+ this.setState({
+ substractFee: !this.state.substractFee,
+ });
+ }
+
+ componentWillMount() {
+ document.addEventListener(
+ 'click',
+ this.handleClickOutside,
+ false
+ );
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener(
+ 'click',
+ this.handleClickOutside,
+ false
+ );
+ }
+
+ componentWillReceiveProps(props) {
+ this.checkZAddressCount(props);
}
setRecieverFromScan(receiver) {
@@ -86,10 +100,10 @@ class SendCoin extends React.Component {
} else {
Store.dispatch(
triggerToaster(
- translate('SEND.QR_COIN_MISMATCH_MESSAGE_IMPORT_COIN') +
- recObj.coin +
- translate('SEND.QR_COIN_MISMATCH_MESSAGE_ACTIVE_COIN') +
- this.props.ActiveCoin.coin +
+ translate('SEND.QR_COIN_MISMATCH_MESSAGE_IMPORT_COIN') +
+ recObj.coin +
+ translate('SEND.QR_COIN_MISMATCH_MESSAGE_ACTIVE_COIN') +
+ this.props.ActiveCoin.coin +
translate('SEND.QR_COIN_MISMATCH_MESSAGE_END'),
translate('SEND.QR_COIN_MISMATCH_TITLE'),
'warning'
@@ -103,23 +117,7 @@ class SendCoin extends React.Component {
});
}
- document.getElementById('edexcoinSendTo').focus();
- }
-
- componentWillMount() {
- document.addEventListener(
- 'click',
- this.handleClickOutside,
- false
- );
- }
-
- componentWillUnmount() {
- document.removeEventListener(
- 'click',
- this.handleClickOutside,
- false
- );
+ document.getElementById('kmdWalletSendTo').focus();
}
handleClickOutside(e) {
@@ -132,232 +130,193 @@ class SendCoin extends React.Component {
}
}
- componentWillReceiveProps(props) {
- if (this.state &&
- !this.state.sendFrom &&
- this.props.ActiveCoin.activeAddress) {
- this.setState(Object.assign({}, this.state, {
- sendFrom: this.props.ActiveCoin.activeAddress,
- }));
- }
- }
+ checkZAddressCount(props) {
+ const _addresses = this.props.ActiveCoin.addresses;
+ const _defaultState = {
+ currentStep: 0,
+ addressType: null,
+ sendFrom: null,
+ sendFromAmount: 0,
+ sendTo: '',
+ amount: 0,
+ fee: 0,
+ addressSelectorOpen: false,
+ renderAddressDropdown: true,
+ substractFee: false,
+ lastSendToResponse: null,
+ };
+ let updatedState;
- updateSocketsData(data) {
- if (data &&
- data.message &&
- data.message.shepherd.iguanaAPI &&
- data.message.shepherd.iguanaAPI.totalStackLength) {
- this.setState(Object.assign({}, this.state, {
- totalStackLength: data.message.shepherd.iguanaAPI.totalStackLength,
- }));
- }
- if (data &&
- data.message &&
- data.message.shepherd.iguanaAPI &&
- data.message.shepherd.iguanaAPI.currentStackLength) {
- this.setState(Object.assign({}, this.state, {
- currentStackLength: data.message.shepherd.iguanaAPI.currentStackLength,
- }));
+ if (_addresses &&
+ (!_addresses.private ||
+ _addresses.private.length === 0)) {
+ updatedState = {
+ renderAddressDropdown: false,
+ lastSendToResponse: props.ActiveCoin.lastSendToResponse,
+ coin: props.ActiveCoin.coin,
+ };
+ } else {
+ updatedState = {
+ renderAddressDropdown: true,
+ lastSendToResponse: props.ActiveCoin.lastSendToResponse,
+ coin: props.ActiveCoin.coin,
+ };
}
- }
- _fetchNewUTXOData() {
- Store.dispatch(fetchUtxoCache({
- pubkey: this.props.Dashboard.activeHandle.pubkey,
- allcoins: false,
- coin: this.props.ActiveCoin.coin,
- calls: 'refresh',
- address: this.state.sendFrom,
- }));
+ if (this.state.coin !== props.ActiveCoin.coin) {
+ this.setState(Object.assign({}, _defaultState, updatedState));
+ } else {
+ this.setState(updatedState);
+ }
}
- renderUTXOCacheInfo() {
- if (this.props.ActiveCoin.mode === 'basilisk' &&
- this.state.sendFrom &&
- !this.state.sendApiType &&
- this.props.ActiveCoin.cache &&
- this.props.ActiveCoin.cache[this.props.ActiveCoin.coin][this.state.sendFrom]) {
- let refreshCacheData;
- let timestamp;
- let isReadyToUpdate;
- let waitUntilCallIsFinished = this.state.currentStackLength > 1 ? true : false;
- const _cache = this.props.ActiveCoin.cache;
- const _coin = this.props.ActiveCoin.coin;
- const _sendFrom = this.state.sendFrom;
-
- if (_cache[_coin][_sendFrom].refresh ||
- _cache[_coin][_sendFrom].listunspent) {
- refreshCacheData = _cache[_coin][_sendFrom].refresh || _cache[_coin][_sendFrom].listunspent;
- timestamp = checkTimestamp(refreshCacheData.timestamp);
- isReadyToUpdate = timestamp > 600 ? true : false;
- } else {
- isReadyToUpdate = true;
- }
-
- if (_cache[_coin][_sendFrom].refresh &&
- _cache[_coin][_sendFrom].refresh.data &&
- _cache[_coin][_sendFrom].refresh.data.error &&
- _cache[_coin][_sendFrom].refresh.data.error === 'request failed') {
- timestamp = null;
- }
+ renderAddressByType(type) {
+ let _items = [];
+
+ if (this.props.ActiveCoin.addresses &&
+ this.props.ActiveCoin.addresses[type] &&
+ this.props.ActiveCoin.addresses[type].length) {
+ this.props.ActiveCoin.addresses[type].map((address) => {
+ if (address.amount > 0) {
+ _items.push(
+
+ this.updateAddressSelection(address.address, type, address.amount) }>
+
+
+ [ { address.amount } { this.props.ActiveCoin.coin } ]
+ { type === 'public' ? address.address : address.address.substring(0, 34) + '...' }
+
+
+
+
+ );
+ }
+ });
- return UTXOCacheInfoRender.call(
- this,
- refreshCacheData,
- isReadyToUpdate,
- waitUntilCallIsFinished,
- timestamp
- );
+ return _items;
+ } else {
+ return null;
}
-
- return null;
}
- renderAddressAmount(address) {
- const _addresses = this.props.ActiveCoin.addresses;
+ renderOPIDListCheck() {
+ if (this.state.renderAddressDropdown &&
+ this.props.ActiveCoin.opids &&
+ this.props.ActiveCoin.opids.length) {
+ return true;
+ }
+ }
- if (_addresses &&
- _addresses.public &&
- _addresses.public.length) {
- for (let i = 0; i < _addresses.public.length; i++) {
- if (_addresses.public[i].address === address) {
- if (_addresses.public[i].amount !== 'N/A') {
- return _addresses.public[i].amount;
- }
- }
- }
+ renderSelectorCurrentLabel() {
+ if (this.state.sendFrom) {
+ return (
+
+
+
+ [ { this.state.sendFromAmount } { this.props.ActiveCoin.coin } ]
+ { this.state.addressType === 'public' ? this.state.sendFrom : this.state.sendFrom.substring(0, 34) + '...' }
+
+
+ );
} else {
- return 0;
+ return (
+ { translate('INDEX.T_FUNDS') }
+ );
}
}
- renderAddressByType(type) {
- const _addresses = this.props.ActiveCoin.addresses;
-
- if (_addresses &&
- _addresses[type] &&
- _addresses[type].length) {
- if (this.state.sendApiType) {
- const mainAddress = this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin];
- const mainAddressAmount = this.renderAddressAmount(mainAddress);
-
- return(
-
- this.updateAddressSelection(mainAddress, type, mainAddressAmount) }>
-
-
- [ { mainAddressAmount } { this.props.ActiveCoin.coin } ]
- { mainAddress }
-
-
-
-
- );
- } else {
- let items = [];
- const _addresses = this.props.ActiveCoin.addresses;
- const _cache = this.props.ActiveCoin.cache;
- const _coin = this.props.ActiveCoin.coin;
-
- for (let i = 0; i < _addresses[type].length; i++) {
- const address = _addresses[type][i].address;
- let _amount = address.amount;
-
- if (this.props.ActiveCoin.mode === 'basilisk' &&
- _cache) {
- _amount = _cache[_coin][address] && _cache[_coin][address].getbalance.data && _cache[_coin][address].getbalance.data.balance ? _cache[_coin][address].getbalance.data.balance : 'N/A';
- }
+ renderAddressList() {
+ return AddressListRender.call(this);
+ }
- if (_amount !== 'N/A') {
- items.push(
-
- this.updateAddressSelection(address, type, _amount) }>
-
- [ { _amount } { _coin } ] { address }
-
-
-
- );
- }
- }
+ renderOPIDLabel(opid) {
+ const _satatusDef = {
+ queued: {
+ icon: 'warning',
+ label: 'QUEUED',
+ },
+ executing: {
+ icon: 'info',
+ label: 'EXECUTING',
+ },
+ failed: {
+ icon: 'danger',
+ label: 'FAILED',
+ },
+ success: {
+ icon: 'success',
+ label: 'SUCCESS',
+ },
+ };
- return items;
- }
- } else {
- return null;
- }
+ return (
+
+
+ { translate(`KMD_NATIVE.${_satatusDef[opid.status].label}`) }
+
+ );
}
- renderSelectorCurrentLabel() {
- if (this.state.sendFrom) {
- let _amount;
- const _cache = this.props.ActiveCoin.cache;
- const _coin = this.props.ActiveCoin.coin;
- const _sendFrom = this.state.sendFrom;
-
- if (this.state.sendFromAmount === 0 &&
- this.props.ActiveCoin.mode === 'basilisk' &&
- _cache) {
- _amount = _cache[_coin][_sendFrom].getbalance.data && _cache[_coin][_sendFrom].getbalance.data.balance ? _cache[_coin][_sendFrom].getbalance.data.balance : 'N/A';
- } else {
- _amount = this.state.sendFromAmount;
- }
+ renderOPIDResult(opid) {
+ let isWaitingStatus = true;
+ if (opid.status === 'queued') {
+ isWaitingStatus = false;
+ return (
+ { translate('SEND.AWAITING') }...
+ );
+ }
+ if (opid.status === 'executing') {
+ isWaitingStatus = false;
+ return (
+ { translate('SEND.PROCESSING') }...
+ );
+ }
+ if (opid.status === 'failed') {
+ isWaitingStatus = false;
return (
-
- [ { _amount } { _coin } ] { _sendFrom }
+ { translate('SEND.ERROR_CODE') }: { opid.error.code }
+
+ { translate('KMD_NATIVE.MESSAGE') }: { opid.error.message }
);
- } else if (this.state.sendApiType) {
- const mainAddress = this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin];
- const mainAddressAmount = this.renderAddressAmount(mainAddress);
-
+ }
+ if (opid.status === 'success') {
+ isWaitingStatus = false;
return (
-
- [ { mainAddressAmount } { this.props.ActiveCoin.coin } ] { mainAddress }
+ { translate('KMD_NATIVE.TXID') }: { opid.result.txid }
+
+ { translate('KMD_NATIVE.EXECUTION_SECONDS') }: { opid.execution_secs }
);
- } else {
+ }
+ if (isWaitingStatus) {
return (
- { translate('SEND.SELECT_T_OR_Z_ADDR') }
+ { translate('SEND.WAITING') }...
);
}
}
- renderAddressList() {
- return (
-
-
-
-
- );
+ renderOPIDList() {
+ if (this.props.ActiveCoin.opids &&
+ this.props.ActiveCoin.opids.length) {
+ return this.props.ActiveCoin.opids.map((opid) =>
+
+ { this.renderOPIDLabel(opid) } |
+ { opid.id } |
+ { secondsToString(opid.creation_time) } |
+ { this.renderOPIDResult(opid) } |
+
+ );
+ } else {
+ return null;
+ }
}
openDropMenu() {
@@ -367,42 +326,43 @@ class SendCoin extends React.Component {
}
updateAddressSelection(address, type, amount) {
- let _sendFromAmount = amount ? amount : this.props.ActiveCoin.addresses[type][address].amount;
- const _cache = this.props.ActiveCoin.cache;
- const _coin = this.props.ActiveCoin.coin;
-
- if (this.props.ActiveCoin.mode === 'basilisk' &&
- this.props.ActiveCoin.cache) {
- _sendFromAmount = _cache[_coin][address].getbalance.data && _cache[_coin][address].getbalance.data.balance ? _cache[_coin][address].getbalance.data.balance : 'N/A';
- }
-
this.setState(Object.assign({}, this.state, {
sendFrom: address,
addressType: type,
- sendFromAmount: _sendFromAmount,
+ sendFromAmount: amount,
addressSelectorOpen: !this.state.addressSelectorOpen,
}));
}
- changeSendCoinStep(step) {
- if (step === 0) {
- Store.dispatch(clearLastSendToResponseState());
+ updateInput(e) {
+ this.setState({
+ [e.target.name]: e.target.value,
+ });
+ }
- this.setState({
- currentStep: 0,
- sendFrom: this.props.Dashboard && this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : null,
- sendFromAmount: 0,
- sendTo: '',
- sendToOA: null,
- amount: 0,
- fee: 0.0001,
- sendSig: false,
- sendApiType: true,
- addressSelectorOpen: false,
- currentStackLength: 0,
- totalStackLength: 0,
- utxoMethodInProgress: false,
- });
+ changeSendCoinStep(step, back) {
+ if (step === 0) {
+ if (back) {
+ this.setState({
+ currentStep: 0,
+ });
+ } else {
+ Store.dispatch(clearLastSendToResponseState());
+
+ this.setState({
+ currentStep: 0,
+ addressType: null,
+ sendFrom: null,
+ sendFromAmount: 0,
+ sendTo: '',
+ sendToOA: null,
+ amount: 0,
+ fee: 0,
+ addressSelectorOpen: false,
+ renderAddressDropdown: true,
+ substractFee: false,
+ });
+ }
}
if (step === 1) {
@@ -415,417 +375,48 @@ class SendCoin extends React.Component {
step === 2) {
this.setState(Object.assign({}, this.state, {
currentStep: step,
- utxoMethodInProgress: !this.state.sendApiType && this.props.ActiveCoin.mode === 'basilisk' ? true : false,
}));
}
if (step === 2) {
- if (!this.state.sendApiType &&
- this.props.ActiveCoin.mode === 'basilisk') {
- this.handleBasiliskSend();
- } else {
- Store.dispatch(
- sendToAddress(
- this.props.ActiveCoin.coin,
- this.state
- )
- );
- }
+ this.handleSubmit();
}
}
- toggleSendSig() {
- this.setState(Object.assign({}, this.state, {
- sendSig: !this.state.sendSig,
- }));
- }
-
- toggleSendAPIType() {
- this.setState(Object.assign({}, this.state, {
- sendApiType: !this.state.sendApiType,
- fee: !this.state.sendApiType ? 0 : 0.0001,
- sendFrom: this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin],
- }));
- }
-
- updateInput(e) {
- this.setState({
- [e.target.name]: e.target.value,
- });
- }
-
- // TODO: move to action creators
- handleBasiliskSend() {
- const refreshData = this.props.ActiveCoin.cache[this.props.ActiveCoin.coin][this.state.sendFrom].refresh;
- const listunspentData = this.props.ActiveCoin.cache[this.props.ActiveCoin.coin][this.state.sendFrom].listunspent;
- const utxoSet = (refreshData && refreshData.data) || (listunspentData && listunspentData.data);
- const _pubkey = this.props.Dashboard.activeHandle.pubkey;
- const forceUpdateCache = this._fetchNewUTXOData;
- const _sendFrom = this.state.sendFrom;
- const sendData = {
- coin: this.props.ActiveCoin.coin,
- sendfrom: this.state.sendFrom,
- sendtoaddr: this.state.sendTo,
- amount: this.state.amount,
- txfee: this.state.fee,
- sendsig: this.state.sendSig === true ? 0 : 1,
- utxos: utxoSet,
- };
-
- // TODO: es arrows
- iguanaUTXORawTX(sendData, Store.dispatch)
- .then(function(json) {
- if (json.result === 'success' &&
- json.completed === true) {
- Store.dispatch(
- triggerToaster(
- translate('TOASTR.SIGNED_TX_GENERATED'),
- translate('TOASTR.WALLET_NOTIFICATION'),
- 'success'
- )
- );
-
- if (sendData.sendsig === 1) {
- const dexrawtxData = {
- signedtx: json.signedtx,
- coin: sendData.coin,
- };
- dexSendRawTX(
- dexrawtxData,
- Store.dispatch
- ).then(function(dexRawTxJSON) {
- if (dexRawTxJSON.indexOf('"error":{"code"') > -1) {
- Store.dispatch(
- triggerToaster(
- translate('TOASTR.TRANSACTION_FAILED'),
- translate('TOASTR.WALLET_NOTIFICATION'),
- 'error'
- )
- );
- Store.dispatch(sendToAddressStateAlt(JSON.parse(dexRawTxJSON)));
-
- this.setState(Object.assign({}, this.state, {
- utxoMethodInProgress: false,
- }));
- } else {
- Store.dispatch(
- triggerToaster(
- translate('TOASTR.SIGNED_TX_SENT'),
- translate('TOASTR.WALLET_NOTIFICATION'),
- 'success'
- )
- );
- Store.dispatch(sendToAddressStateAlt(json));
-
- let getTxidData = function() {
- return new Promise(function(resolve, reject) {
- Store.dispatch(
- triggerToaster(
- translate('TOASTR.GETTING_TXID_INFO'),
- translate('TOASTR.WALLET_NOTIFICATION'),
- 'info'
- )
- );
-
- edexGetTransaction({
- coin: sendData.coin,
- txid: dexRawTxJSON.txid ? dexRawTxJSON.txid : dexRawTxJSON,
- }, Store.dispatch)
- .then(function(json) {
- resolve(json);
- });
- });
- }
-
- let processRefreshUTXOs = function(vinData) {
- return new Promise(function(resolve, reject) {
- let edexGetTxIDListRes = edexGetTxIDList(vinData);
- resolve(edexGetTxIDListRes);
- });
- }
-
- let getDataCacheContents = function(txidListToRemove) {
- return new Promise(function(resolve, reject) {
- getCacheFile(_pubkey)
- .then(function(result) {
- let saveThisData = edexRemoveTXID(result.result, _sendFrom, txidListToRemove);
- resolve(saveThisData);
- });
- });
- }
-
- let saveNewCacheData = function(saveThisData) {
- return new Promise(function(resolve, reject) {
- shepherdGroomPostPromise(
- _pubkey,
- saveThisData
- ).then(function(result) {
- resolve(result);
- forceUpdateCache();
- Store.dispatch(
- triggerToaster(
- translate('TOASTR.LOCAL_UTXO_UPDATED'),
- translate('TOASTR.WALLET_NOTIFICATION'),
- 'info'
- )
- );
-
- this.setState(Object.assign({}, this.state, {
- utxoMethodInProgress: false,
- }));
- }.bind(this));
- }.bind(this));
- }.bind(this);
-
- Store.dispatch(
- triggerToaster(
- `${translate('TOASTR.AWAITING_TX_RESP')}...`,
- translate('TOASTR.WALLET_NOTIFICATION'),
- 'info'
- )
- );
-
- function waterfallUTXOProcess() {
- Store.dispatch(
- triggerToaster(
- `${translate('TOASTR.PROCESSING_UTXO')}...`,
- translate('TOASTR.WALLET_NOTIFICATION'),
- 'info'
- )
- );
-
- getTxidData()
- .then(function(gettxdata) {
- return processRefreshUTXOs(gettxdata.vin);
- })
- .then(function(new_utxos_set) {
- return getDataCacheContents(new_utxos_set);
- })
- .then(function(save_this_data) {
- return saveNewCacheData(save_this_data);
- });
- }
-
- let sentTxData = setInterval(function() {
- getTxidData()
- .then(function(gettxdata) {
- if (gettxdata.vin &&
- gettxdata.vin.length) {
- clearInterval(sentTxData);
- waterfallUTXOProcess();
- }
- })
- }, 1000);
- }
- }.bind(this));
- } else {
- Store.dispatch(sendToAddressStateAlt(json));
-
- this.setState(Object.assign({}, this.state, {
- utxoMethodInProgress: false,
- }));
- }
- } else {
- Store.dispatch(sendToAddressStateAlt(json));
- Store.dispatch(
- triggerToaster(
- `${translate('TOASTR.SIGNED_TX_GENERATED_FAIL')}`,
- translate('TOASTR.WALLET_NOTIFICATION'),
- 'error'
- )
- );
-
- this.setState(Object.assign({}, this.state, {
- utxoMethodInProgress: false,
- }));
- }
-
- // console.log(json);
- }.bind(this));
- }
-
- renderSignedTx(isRawTx) {
- let substrBlocks;
-
- if (this.props.ActiveCoin.mode === 'basilisk') {
- substrBlocks = isRawTx ? 3 : 8;
- } else {
- substrBlocks = 10;
- }
-
- const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse[isRawTx ? 'rawtx' : 'signedtx'];
- const substrLength = _lastSendToResponse.length / substrBlocks;
- let out = [];
-
- for (let i = 0; i < substrBlocks; i++) {
- out.push(
- { _lastSendToResponse.substring(i * substrLength, substrLength * i + substrLength) }
- );
- }
-
- return out.length ? out : null;
- }
-
- renderKey(key) {
- if (key === 'signedtx') {
- return this.renderSignedTx();
- } else if (key === 'rawtx') {
- return this.renderSignedTx(true);
- } else if (key === 'complete' || key === 'completed' || key === 'result') {
- const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse;
-
- if (_lastSendToResponse[key] === true ||
- _lastSendToResponse[key] === 'success') {
- return (
- { _lastSendToResponse[key] === true ? 'true' : 'success' }
- );
- } else {
- if (key === 'result' &&
- _lastSendToResponse.result &&
- typeof _lastSendToResponse.result !== 'object') {
- return (
- { _lastSendToResponse.result }
- );
- } else {
- return (
- false
- );
- }
- }
- } else if (key === 'error') {
- const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse;
-
- if (Object.keys(_lastSendToResponse[key]).length) {
- return (
- { JSON.stringify(_lastSendToResponse[key], null, '\t') }
- );
- } else {
- return (
- { _lastSendToResponse[key] }
- );
- }
- } else if (key === 'sendrawtransaction') {
- const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse;
-
- if (_lastSendToResponse[key] === 'success') {
- return (
- true
- );
- } else {
- return (
- false
- );
- }
- } else if (key === 'txid' || key === 'sent') {
- const _lastSendToResponse = this.props.ActiveCoin.lastSendToResponse;
-
- return (
- { _lastSendToResponse[key] }
- );
- } else if (key === 'tag') {
- return null;
+ handleSubmit() {
+ if (!this.validateSendFormData()) {
+ return;
}
- }
- renderSendCoinResponse() {
- return SendCoinResponseRender.call(this);
- }
-
- // experimental, ask @kolo for details if required
- getOAdress() {
- resolveOpenAliasAddress(this.state.sendToOA)
- .then(function(json) {
- const reply = json.Answer;
-
- if (reply &&
- reply.length) {
- for (let i = 0; i < reply.length; i++) {
- const _address = reply[i].data.split(' ');
- const coin = _address[0].replace('"oa1:', '');
- const coinAddress = _address[1].replace('recipient_address=', '').replace(';', '');
-
- if (coin.toUpperCase() === this.props.ActiveCoin.coin) {
- this.setState(Object.assign({}, this.state, {
- sendTo: coinAddress,
- }));
- }
- }
+ Store.dispatch(
+ sendNativeTx(
+ this.props.ActiveCoin.coin,
+ this.state
+ )
+ );
- if (this.state.sendTo === '') {
- Store.dispatch(
- triggerToaster(
- 'Couldn\'t find any ' + this.props.ActiveCoin.coin + ' addresses',
- 'OpenAlias',
- 'error'
- )
- );
- }
- } else {
+ if (this.state.addressType === 'private') {
+ setTimeout(() => {
Store.dispatch(
- triggerToaster(
- 'Couldn\'t find any addresses',
- 'OpenAlias',
- 'error'
+ getKMDOPID(
+ null,
+ this.props.ActiveCoin.coin
)
);
- }
- }.bind(this));
- }
-
- renderOASendUI() {
- if (Config.openAlias) {
- return OASendUIRender.call(this);
+ }, 1000);
}
-
- return null;
- }
-
- renderSendApiTypeSelector() {
- if (this.props.ActiveCoin.mode === 'basilisk') {
- return SendApiTypeSelectorRender.call(this);
- }
-
- return null;
- }
-
- // TODO same as in walletsNav and receiveCoin, find a way to reuse it?
- checkBalance() {
- let _balance = '0';
- const _mode = this.props.ActiveCoin.mode;
-
- if (_mode === 'full') {
- _balance = this.props.ActiveCoin.balance || 0;
- } else if (_mode === 'basilisk') {
- if (this.props.ActiveCoin.cache) {
- const _cache = this.props.ActiveCoin.cache;
- const _coin = this.props.ActiveCoin.coin;
- const _address = this.props.ActiveCoin.activeAddress;
-
- if (_address &&
- _cache[_coin] &&
- _cache[_coin][_address] &&
- _cache[_coin][_address].getbalance &&
- _cache[_coin][_address].getbalance.data &&
- (_cache[_coin][_address].getbalance.data.balance ||
- _cache[_coin][_address].getbalance.data.interest)) {
- const _regBalance = _cache[_coin][_address].getbalance.data.balance ? _cache[_coin][_address].getbalance.data.balance : 0;
-
- _balance = _regBalance;
- }
- }
- }
-
- return _balance;
}
// TODO: reduce to a single toast
validateSendFormData() {
let valid = true;
- if (!this.state.sendTo || this.state.sendTo.length < 34) {
+
+ if (!this.state.sendTo ||
+ this.state.sendTo.length < 34) {
Store.dispatch(
triggerToaster(
translate('SEND.SEND_TO_ADDRESS_MIN_LENGTH'),
- '',
+ translate('TOASTR.WALLET_NOTIFICATION'),
'error'
)
);
@@ -836,82 +427,93 @@ class SendCoin extends React.Component {
Store.dispatch(
triggerToaster(
translate('SEND.AMOUNT_POSITIVE_NUMBER'),
- '',
+ translate('TOASTR.WALLET_NOTIFICATION'),
'error'
)
);
valid = false;
}
- if (!isPositiveNumber(this.state.fee)) {
+ if (((!this.state.sendFrom || this.state.addressType === 'public') &&
+ this.state.sendTo &&
+ this.state.sendTo.length === 34 &&
+ this.props.ActiveCoin.balance &&
+ this.props.ActiveCoin.balance.transparent &&
+ Number(this.state.amount) > Number(this.props.ActiveCoin.balance.transparent)) ||
+ (this.state.addressType === 'public' &&
+ this.state.sendTo &&
+ this.state.sendTo.length > 34 &&
+ Number(this.state.amount) > Number(this.state.sendFromAmount)) ||
+ (this.state.addressType === 'private' &&
+ this.state.sendTo &&
+ this.state.sendTo.length >= 34 &&
+ Number(this.state.amount) > Number(this.state.sendFromAmount))) {
Store.dispatch(
triggerToaster(
- translate('SEND.FEE_POSITIVE_NUMBER'),
- '',
+ translate('SEND.INSUFFICIENT_FUNDS'),
+ translate('TOASTR.WALLET_NOTIFICATION'),
'error'
)
);
valid = false;
}
- if (!isPositiveNumber(this.getTotalAmount())) {
+ if (this.state.sendTo.length > 34 &&
+ (!this.state.sendFrom || this.state.sendFrom.length < 34)) {
Store.dispatch(
triggerToaster(
- translate('SEND.TOTAL_AMOUNT_POSITIVE_NUMBER'),
- '',
+ translate('SEND.SELECT_SOURCE_ADDRESS'),
+ translate('TOASTR.WALLET_NOTIFICATION'),
'error'
)
);
valid = false;
}
- /*if ((this.props.ActiveCoin.mode === 'basilisk' && Number(this.state.amount) > Number(this.state.sendFromAmount)) ||
- (this.props.ActiveCoin.mode === 'full' && Number(this.state.amount) > Number(this.checkBalance()))) {
- Store.dispatch(
- triggerToaster(
- translate('SEND.INSUFFICIENT_FUNDS'),
- '',
- 'error'
- )
- );
- valid = false;
- }*/
-
return valid;
}
- getTotalAmount() {
- return Number(this.state.amount) - Number(this.state.fee);
+ isTransparentTx() {
+ if (((this.state.sendFrom && this.state.sendFrom.length === 34) || !this.state.sendFrom) &&
+ (this.state.sendTo && this.state.sendTo.length === 34)) {
+ return true;
+ }
+
+ return false;
}
render() {
- if (this.props.ActiveCoin &&
- this.props.ActiveCoin.send &&
- this.props.ActiveCoin.mode !== 'native') {
- return SendCoinRender.call(this);
+ if (this.props &&
+ this.props.ActiveCoin &&
+ (this.props.ActiveCoin.activeSection === 'send' || this.props.activeSection === 'send')) {
+ return SendRender.call(this);
}
return null;
}
}
-const mapStateToProps = (state) => {
- return {
+const mapStateToProps = (state, props) => {
+ let _mappedProps = {
ActiveCoin: {
+ addresses: state.ActiveCoin.addresses,
coin: state.ActiveCoin.coin,
mode: state.ActiveCoin.mode,
- send: state.ActiveCoin.send,
- receive: state.ActiveCoin.receive,
+ opids: state.ActiveCoin.opids,
balance: state.ActiveCoin.balance,
- cache: state.ActiveCoin.cache,
- activeAddress: state.ActiveCoin.activeAddress,
+ activeSection: state.ActiveCoin.activeSection,
lastSendToResponse: state.ActiveCoin.lastSendToResponse,
- addresses: state.ActiveCoin.addresses,
- },
- Dashboard: {
- activeHandle: state.Dashboard.activeHandle,
},
};
+
+ if (props &&
+ props.activeSection &&
+ props.renderFormOnly) {
+ _mappedProps.ActiveCoin.activeSection = props.activeSection;
+ _mappedProps.renderFormOnly = props.renderFormOnly;
+ }
+
+ return _mappedProps;
};
-export default connect(mapStateToProps)(SendCoin);
\ No newline at end of file
+export default connect(mapStateToProps)(SendCoin);
diff --git a/react/src/components/dashboard/sendCoin/sendCoin.render.js b/react/src/components/dashboard/sendCoin/sendCoin.render.js
index 4ca3d8d..995cb68 100644
--- a/react/src/components/dashboard/sendCoin/sendCoin.render.js
+++ b/react/src/components/dashboard/sendCoin/sendCoin.render.js
@@ -1,402 +1,327 @@
import React from 'react';
import { translate } from '../../../translate/translate';
-import {
- secondsElapsedToString,
- secondsToString
-} from '../../../util/time';
-
import QRModal from '../qrModal/qrModal';
-export const UTXOCacheInfoRender = function(refreshCacheData, isReadyToUpdate, waitUntilCallIsFinished, timestamp) {
- const _progress = 100 - this.state.currentStackLength * 100 / this.state.totalStackLength;
-
+export const AddressListRender = function() {
return (
-
-
- { translate('SEND.TOTAL_UTXO_AVAILABLE') }:
- { refreshCacheData ? refreshCacheData.data && refreshCacheData.data.length : translate('SEND.PRESS_UPDATE_BTN') }
-
- { translate('SEND.LAST_UPDATED') } @
- { secondsToString(refreshCacheData ? refreshCacheData.timestamp : 0, true) } |
- { secondsElapsedToString(timestamp || 0) }&nbps;
- { translate('SEND.AGO') }
-
-
- { translate('SEND.NEXT_UPDATE_IN') } { secondsElapsedToString(600 - timestamp) }s
-
-
-
- { translate('SEND.PROCESSING_REQ') }: { this.state.currentStackLength } / { this.state.totalStackLength }
-
-
+
+
+
+ - this.updateAddressSelection(null, 'public', null) }>
+
+ { translate('INDEX.T_FUNDS') }
+
+
+
+ { this.renderAddressByType('public') }
+ { this.renderAddressByType('private') }
+
+
);
};
-export const SendCoinResponseRender = function() {
- if (this.props.ActiveCoin.lastSendToResponse) {
- let items = [];
- const _response = this.props.ActiveCoin.lastSendToResponse;
-
- for (let key in _response) {
- if (key !== 'tag') {
- items.push(
-
- { key } |
- { this.renderKey(key) } |
-
- );
+export const _SendFormRender = function() {
+ return (
+
+ );
+}
- return items;
+export const SendRender = function() {
+ if (this.props.renderFormOnly) {
+ return (
+
{ this.SendFormRender() }
+ );
} else {
return (
-
-
-
-
- { translate('SEND.PROCESSING_TRANSACTION') }...
- { translate('SEND.NOTE_IT_WILL_TAKE') }.
-
-
-
-
-
-
+
+
+
+
+ 1
+
+ { translate('INDEX.FILL_SEND_FORM') }
+ { translate('INDEX.FILL_SEND_DETAILS') }
-
-
+
+ 2
+
+ { translate('INDEX.CONFIRMING') }
+ { translate('INDEX.CONFIRM_DETAILS') }
-
+
+ 3
+
+ { translate('INDEX.PROCESSING_TX') }
+ { translate('INDEX.PROCESSING_DETAILS') }
- |
-
- );
- }
-}
-
-export const OASendUIRender = function() {
- return (
-
-
-
-
-
-
-
-
-
- );
-};
-
-export const SendApiTypeSelectorRender = function() {
- return (
-
-
-
-
-
- { translate('SEND.SEND_VIA') } (sendtoaddress API)
-
-
-
-
-
-
-
- );
-};
+
-export const SendCoinRender = function() {
- return (
-
-
-
-
-
1
-
-
{ translate('INDEX.FILL_SEND_FORM') }
-
{ translate('INDEX.FILL_SEND_DETAILS') }
+
+
+
+
+ { translate('INDEX.SEND') } { this.props.ActiveCoin.coin }
+
-
-
-
2
-
-
{ translate('INDEX.CONFIRMING') }
-
{ translate('INDEX.CONFIRM_DETAILS') }
+
+
-
-
-
3
-
-
{ translate('INDEX.PROCESSING_TX') }
-
{ translate('INDEX.PROCESSING_DETAILS') }
+
+ { this.SendFormRender() }
-
-
-
- { translate('INDEX.SEND') } { this.props.ActiveCoin.coin }
-
-
-