Browse Source

Merge branch 'redux' of https://github.com/SuperNETorg/EasyDEX-GUI into feature/prop-refactor

all-modes
pbca26 8 years ago
parent
commit
752929c51b
  1. 5
      react/change.log
  2. 22
      react/src/actions/actionCreators.js
  3. 47
      react/src/actions/actions/addCoin.js
  4. 46
      react/src/actions/actions/nativeSend.js
  5. 4
      react/src/components/addcoin/payload.js
  6. 56
      react/src/components/dashboard/settings/settings.js
  7. 2
      react/src/components/dashboard/settings/settings.render.js
  8. 8
      react/src/components/dashboard/walletsBalance/walletsBalance.render.js
  9. 49
      react/src/components/dashboard/walletsData/walletsData.js
  10. 14
      react/src/components/dashboard/walletsData/walletsData.render.js
  11. 53
      react/src/components/dashboard/walletsNativeSend/walletsNativeSend.js
  12. 20
      react/src/components/dashboard/walletsNativeSend/walletsNativeSend.render.js
  13. 8
      react/src/components/main/main.js
  14. 9
      react/src/components/overrides.scss
  15. 10
      react/src/translate/en.js
  16. 8
      react/src/translate/translate.js
  17. 66
      react/src/util/formatValue.js
  18. 2
      react/src/util/sort.js

5
react/change.log

@ -21,6 +21,11 @@ UI:
- zcashparams folder check - zcashparams folder check
- claim interest modal - claim interest modal
- renewed transactions history look - renewed transactions history look
- prevent app from closing while komodod is still loading/processing data
- send form validation
- coin daemon port check on addcoin
- updated application settings
- komodo datadir
v0.2.0.21a-beta v0.2.0.21a-beta
-------------- --------------

22
react/src/actions/actionCreators.js

@ -193,7 +193,7 @@ export function triggerToaster(message, title, _type, autoClose = true) {
message, message,
title, title,
_type, _type,
autoClose autoClose,
} }
} }
@ -201,7 +201,7 @@ export function triggerToaster(message, title, _type, autoClose = true) {
export function dismissToaster(toastId) { export function dismissToaster(toastId) {
return { return {
type: REMOVE_TOASTER_MESSAGE, type: REMOVE_TOASTER_MESSAGE,
toastId: toastId toastId: toastId,
} }
} }
@ -217,7 +217,7 @@ export function dashboardCoinsState(json) {
return { return {
type: GET_ACTIVE_COINS, type: GET_ACTIVE_COINS,
coins: json, coins: json,
activeCoins: Object.keys(json.native).length || Object.keys(json.basilisk).length || Object.keys(json.full).length ? true : false activeCoins: Object.keys(json.native).length || Object.keys(json.basilisk).length || Object.keys(json.full).length ? true : false,
} }
} }
@ -291,7 +291,13 @@ export function rpcErrorHandler(json, dispatch) {
if (json && if (json &&
json.error) { json.error) {
if (json.error === 'bitcoinrpc needs coin that is active') { if (json.error === 'bitcoinrpc needs coin that is active') {
dispatch(triggerToaster(translate('API.NO_ACTIVE_COIN'), translate('TOASTR.SERVICE_NOTIFICATION'), 'error')); dispatch(
triggerToaster(
translate('API.NO_ACTIVE_COIN'),
translate('TOASTR.SERVICE_NOTIFICATION'),
'error'
)
);
} }
} }
} }
@ -302,8 +308,8 @@ export function setBasiliskMainAddress(json, coin, mode) {
for (let i = 0; i < json.result.length; i++) { for (let i = 0; i < json.result.length; i++) {
publicAddressArray.push({ publicAddressArray.push({
'address': json.result[i], address: json.result[i],
'amount': 'N/A' amount: 'N/A',
}); });
} }
@ -320,7 +326,7 @@ export function setBasiliskMainAddress(json, coin, mode) {
return { return {
type: ACTIVE_COIN_GET_ADDRESSES, type: ACTIVE_COIN_GET_ADDRESSES,
addresses: { 'public': [] }, addresses: { public: [] },
} }
} }
@ -330,7 +336,7 @@ export function getNativeTxHistoryState(json) {
json = null; json = null;
} else if (json && json.result && json.result.length) { } else if (json && json.result && json.result.length) {
json = json.result; json = json.result;
} else if (!json || !json.result.length) { } else if (!json || (!json.result || !json.result.length)) {
json = 'no data'; json = 'no data';
} }

47
react/src/actions/actions/addCoin.js

@ -159,6 +159,17 @@ export function iguanaAddCoin(coin, mode, acData, port) {
} }
} }
function handleErrors(response) {
let _parsedResponse;
if (!response.ok) {
return null;
} else {
_parsedResponse = response.text().then(function(text) { return text; });
return _parsedResponse;
}
}
export function shepherdHerd(coin, mode, path, startupParams) { export function shepherdHerd(coin, mode, path, startupParams) {
let acData; let acData;
let herdData = { let herdData = {
@ -251,23 +262,35 @@ export function shepherdHerd(coin, mode, path, startupParams) {
) )
); );
}) })
.then(response => response.json()) .then(handleErrors)
.then(function(json) { .then(function(json) {
if (Config.iguanaLessMode) { if (json) {
dispatch( if (Config.iguanaLessMode) {
addCoinResult(coin, mode)
);
setTimeout(() => {
dispatch( dispatch(
iguanaActiveHandleBypass() addCoinResult(coin, mode)
); );
}, 1000); setTimeout(() => {
dispatch(
iguanaActiveHandleBypass()
);
}, 1000);
} else {
dispatch(
iguanaAddCoin(
coin,
mode,
acData
)
);
}
} else { } else {
console.warn(acData);
dispatch( dispatch(
iguanaAddCoin( triggerToaster(
coin, `Error starting ${coin} daemon. Port ${acData.rpc} is already taken!`,
mode, translate('TOASTR.SERVICE_NOTIFICATION'),
acData 'error',
false
) )
); );
} }

46
react/src/actions/actions/nativeSend.js

@ -71,10 +71,20 @@ export function sendNativeTx(coin, _payload) {
cmd: payload.function, cmd: payload.function,
params: params:
(_payload.addressType === 'public' && _payload.sendTo.length !== 95) || !_payload.sendFrom ? (_payload.addressType === 'public' && _payload.sendTo.length !== 95) || !_payload.sendFrom ?
[ (_payload.substractFee ?
_payload.sendTo, [
_payload.amount _payload.sendTo,
] _payload.amount,
'',
'',
true
]
:
[
_payload.sendTo,
_payload.amount
]
)
: :
[ [
_payload.sendFrom, _payload.sendFrom,
@ -134,25 +144,31 @@ export function sendNativeTx(coin, _payload) {
json.indexOf('"},"id":"jl777"') json.indexOf('"},"id":"jl777"')
); );
dispatch(
triggerToaster(
true,
_message,
translate('TOASTR.WALLET_NOTIFICATION'),
'error'
)
);
if (json.indexOf('"code":-4') > -1) { if (json.indexOf('"code":-4') > -1) {
dispatch( dispatch(
triggerToaster( triggerToaster(
true,
translate('TOASTR.WALLET_NOTIFICATION'),
translate('API.WALLETDAT_MISMATCH'), translate('API.WALLETDAT_MISMATCH'),
translate('TOASTR.WALLET_NOTIFICATION'),
'info', 'info',
false false
) )
); );
} else if (json.indexOf('"code":-5') > -1) {
dispatch(
triggerToaster(
translate('TOASTR.INVALID_ADDRESS', coin),
translate('TOASTR.WALLET_NOTIFICATION'),
'error',
)
);
} else {
dispatch(
triggerToaster(
_message,
translate('TOASTR.WALLET_NOTIFICATION'),
'error'
)
);
} }
} else { } else {
dispatch( dispatch(

4
react/src/components/addcoin/payload.js

@ -704,8 +704,8 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) {
'WLC': { 'WLC': {
'name': 'WIRELESS', 'name': 'WIRELESS',
'supply': 210000000, 'supply': 210000000,
'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {'coin':'WLC','conf':'WLC.conf','path':confpath,'RELAY':-1,'VALIDATE':0,'startpend':4,'endpend':4,'maxpeers':8,'newcoin':'WLC','name':'WIRELESS','netmagic':'62071ed3','p2p':assetChainPorts.WIRELESS - 1,'rpc':assetChainPorts.WIRELESS}) : {}, 'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {'coin':'WLC','conf':'WLC.conf','path':confpath,'RELAY':-1,'VALIDATE':0,'startpend':4,'endpend':4,'maxpeers':8,'newcoin':'WLC','name':'WIRELESS','netmagic':'62071ed3','p2p':assetChainPorts.WLC - 1,'rpc':assetChainPorts.WLC}) : {},
'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,'RELAY':mode,'VALIDATE':mode,'startpend':tmpPendValue,'endpend':tmpPendValue,'maxpeers':8,'newcoin':'WLC','name':'WIRELESS','netmagic':'62071ed3','p2p':assetChainPorts.WIRELESS - 1,'rpc':assetChainPorts.WIRELESS}) 'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,'RELAY':mode,'VALIDATE':mode,'startpend':tmpPendValue,'endpend':tmpPendValue,'maxpeers':8,'newcoin':'WLC','name':'WIRELESS','netmagic':'62071ed3','p2p':assetChainPorts.WLC - 1,'rpc':assetChainPorts.WLC})
}, },
'PANGEA': { 'PANGEA': {
'name': 'PANGEA', 'name': 'PANGEA',

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

@ -17,6 +17,7 @@ import {
shepherdCli, shepherdCli,
checkForUpdateUIPromise, checkForUpdateUIPromise,
updateUIPromise, updateUIPromise,
triggerToaster,
} from '../../../actions/actionCreators'; } from '../../../actions/actionCreators';
import Store from '../../../store'; import Store from '../../../store';
@ -106,8 +107,6 @@ class Settings extends React.Component {
appConfigSchema: _appConfigSchema, appConfigSchema: _appConfigSchema,
appSettings: _appSettings, appSettings: _appSettings,
})); }));
console.warn(_appSettings);
} catch(e) {} } catch(e) {}
} }
@ -263,14 +262,15 @@ class Settings extends React.Component {
renderUpdateStatus() { renderUpdateStatus() {
let items = []; let items = [];
let patchProgressBar = null; let patchProgressBar = null;
const _updateLogLength = this.state.updateLog.length;
for (let i = 0; i < this.state.updateLog.length; i++) { for (let i = 0; i < _updateLogLength; i++) {
items.push( items.push(
<div key={ `settings-update-log-${i}` }>{ this.state.updateLog[i] }</div> <div key={ `settings-update-log-${i}` }>{ this.state.updateLog[i] }</div>
); );
} }
if (this.state.updateLog.length) { if (_updateLogLength) {
return ( return (
<div style={{ minHeight: '200px' }}> <div style={{ minHeight: '200px' }}>
<hr /> <hr />
@ -279,7 +279,7 @@ class Settings extends React.Component {
<div className={ updateProgressBar.patch > -1 ? 'progress progress-sm' : 'hide' }> <div className={ updateProgressBar.patch > -1 ? 'progress progress-sm' : 'hide' }>
<div <div
className="progress-bar progress-bar-striped active progress-bar-indicating progress-bar-success font-size-80-percent" className="progress-bar progress-bar-striped active progress-bar-indicating progress-bar-success font-size-80-percent"
style={{ width: updateProgressBar.patch + '%' }}> style={{ width: `${updateProgressBar.patch}%` }}>
</div> </div>
</div> </div>
</div> </div>
@ -300,7 +300,7 @@ class Settings extends React.Component {
shepherdCli( shepherdCli(
'passthru', 'passthru',
this.state.cliCoin, this.state.cliCoin,
this.state.cliCmd this.state.cliCmdString
) )
); );
} }
@ -448,17 +448,53 @@ class Settings extends React.Component {
_saveAppConfig() { _saveAppConfig() {
const _appSettings = this.state.appSettings; const _appSettings = this.state.appSettings;
let _appSettingsPristine = Object.assign({}, this.props.Settings.appSettings); let _appSettingsPristine = Object.assign({}, this.props.Settings.appSettings);
let isError = false;
let saveAfterPathCheck = false;
for (let key in _appSettings) { for (let key in _appSettings) {
if (key.indexOf('__') === -1) { if (key.indexOf('__') === -1) {
_appSettingsPristine[key] = this.state.appConfigSchema[key].type === 'number' ? Number(_appSettings[key]) : _appSettings[key]; _appSettingsPristine[key] = this.state.appConfigSchema[key].type === 'number' ? Number(_appSettings[key]) : _appSettings[key];
if (this.state.appConfigSchema[key].type === 'folder' &&
_appSettings[key] &&
_appSettings[key].length) {
const _testLocation = window.require('electron').remote.getCurrentWindow().testLocation;
saveAfterPathCheck = true;
_testLocation(_appSettings[key])
.then((res) => {
if (res === -1) {
isError = true;
Store.dispatch(
triggerToaster(
translate('TOASTR.KOMODO_DATADIR_INVALID'),
translate('INDEX.SETTINGS'),
'error'
)
);
} else if (res === false) {
isError = true;
Store.dispatch(
triggerToaster(
translate('TOASTR.KOMODO_DATADIR_NOT_DIR'),
translate('INDEX.SETTINGS'),
'error'
)
);
} else {
Store.dispatch(saveAppConfig(_appSettingsPristine));
}
});
}
} else { } else {
const _nestedKey = key.split('__'); const _nestedKey = key.split('__');
_appSettingsPristine[_nestedKey[0]][_nestedKey[1]] = this.state.appConfigSchema[_nestedKey[0]][_nestedKey[1]].type === 'number' ? Number(_appSettings[key]) : _appSettings[key]; _appSettingsPristine[_nestedKey[0]][_nestedKey[1]] = this.state.appConfigSchema[_nestedKey[0]][_nestedKey[1]].type === 'number' ? Number(_appSettings[key]) : _appSettings[key];
} }
} }
Store.dispatch(saveAppConfig(_appSettingsPristine)); if (!saveAfterPathCheck) {
Store.dispatch(saveAppConfig(_appSettingsPristine));
}
} }
renderConfigEditForm() { renderConfigEditForm() {
@ -503,11 +539,12 @@ class Settings extends React.Component {
value={ _appConfig[key][_key] } value={ _appConfig[key][_key] }
onChange={ (event) => this.updateInputSettings(event, key, _key) } /> onChange={ (event) => this.updateInputSettings(event, key, _key) } />
} }
{ this.state.appConfigSchema[key][_key].type === 'string' && { (this.state.appConfigSchema[key][_key].type === 'string' || this.state.appConfigSchema[key][_key].type === 'folder') &&
<input <input
type="text" type="text"
name={ `${key}__${_key}` } name={ `${key}__${_key}` }
value={ _appConfig[key][_key] } value={ _appConfig[key][_key] }
className={ this.state.appConfigSchema[key][_key].type === 'folder' ? 'full-width': '' }
onChange={ (event) => this.updateInputSettings(event, key, _key) } /> onChange={ (event) => this.updateInputSettings(event, key, _key) } />
} }
{ this.state.appConfigSchema[key][_key].type === 'boolean' && { this.state.appConfigSchema[key][_key].type === 'boolean' &&
@ -550,11 +587,12 @@ class Settings extends React.Component {
value={ _appConfig[key] } value={ _appConfig[key] }
onChange={ (event) => this.updateInputSettings(event, key) } /> onChange={ (event) => this.updateInputSettings(event, key) } />
} }
{ this.state.appConfigSchema[key].type === 'string' && { (this.state.appConfigSchema[key].type === 'string' || this.state.appConfigSchema[key].type === 'folder') &&
<input <input
type="text" type="text"
name={ `${key}` } name={ `${key}` }
value={ _appConfig[key] } value={ _appConfig[key] }
className={ this.state.appConfigSchema[key].type === 'folder' ? 'full-width': '' }
onChange={ (event) => this.updateInputSettings(event, key) } /> onChange={ (event) => this.updateInputSettings(event, key) } />
} }
{ this.state.appConfigSchema[key].type === 'boolean' && { this.state.appConfigSchema[key].type === 'boolean' &&

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

@ -605,7 +605,7 @@ export const SettingsRender = function() {
<button <button
type="button" type="button"
className="btn btn-primary waves-effect waves-light" className="btn btn-primary waves-effect waves-light"
disabled={ !this.state.cliCoin || !this.state.cliCmd } disabled={ !this.state.cliCoin || !this.state.cliCmdString }
onClick={ () => this.execCliCmd() }>{ translate('INDEX.EXECUTE') }</button> onClick={ () => this.execCliCmd() }>{ translate('INDEX.EXECUTE') }</button>
</div> </div>
<div className="col-sm-12 col-xs-12 text-align-left"> <div className="col-sm-12 col-xs-12 text-align-left">

8
react/src/components/dashboard/walletsBalance/walletsBalance.render.js

@ -38,7 +38,7 @@ const WalletsBalanceRender = function() {
<span <span
className="pull-right padding-top-10 font-size-22" className="pull-right padding-top-10 font-size-22"
title={ this.renderBalance('transparent') }> title={ this.renderBalance('transparent') }>
{ Config.roundValues ? formatValue('round', this.renderBalance('transparent'), -6) : this.renderBalance('transparent') } { Config.roundValues ? formatValue(this.renderBalance('transparent')) : this.renderBalance('transparent') }
</span> </span>
</div> </div>
</div> </div>
@ -58,7 +58,7 @@ const WalletsBalanceRender = function() {
<span <span
className="pull-right padding-top-10 font-size-22" className="pull-right padding-top-10 font-size-22"
title={ this.renderBalance('private') }> title={ this.renderBalance('private') }>
{ Config.roundValues ? formatValue('round', this.renderBalance('private'), -6) : this.renderBalance('private') } { Config.roundValues ? formatValue(this.renderBalance('private')) : this.renderBalance('private') }
</span> </span>
</div> </div>
</div> </div>
@ -79,7 +79,7 @@ const WalletsBalanceRender = function() {
<span <span
className="pull-right padding-top-10 font-size-22" className="pull-right padding-top-10 font-size-22"
title={ this.renderBalance('interest') }> title={ this.renderBalance('interest') }>
{ Config.roundValues ? formatValue('round', this.renderBalance('interest'), -6) : this.renderBalance('interest') } { Config.roundValues ? formatValue(this.renderBalance('interest')) : this.renderBalance('interest') }
</span> </span>
</div> </div>
</div> </div>
@ -100,7 +100,7 @@ const WalletsBalanceRender = function() {
<span <span
className="pull-right padding-top-10 font-size-22" className="pull-right padding-top-10 font-size-22"
title={ this.renderBalance('total') }> title={ this.renderBalance('total') }>
{ Config.roundValues ? formatValue('round', this.renderBalance('total'), -6) : this.renderBalance('total') } { Config.roundValues ? formatValue(this.renderBalance('total')) : this.renderBalance('total') }
</span> </span>
</div> </div>
</div> </div>

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

@ -103,6 +103,31 @@ class WalletsData extends React.Component {
socket.removeAllListeners('messages'); socket.removeAllListeners('messages');
} }
// https://react-table.js.org/#/custom-sorting
tableSorting(a, b) { // ugly workaround, override default sort
if (Date.parse(a)) { // convert date to timestamp
a = Date.parse(a);
}
if (Date.parse(b)) {
b = Date.parse(b);
}
// force null and undefined to the bottom
a = (a === null || a === undefined) ? -Infinity : a;
b = (b === null || b === undefined) ? -Infinity : b;
// force any string values to lowercase
a = typeof a === 'string' ? a.toLowerCase() : a;
b = typeof b === 'string' ? b.toLowerCase() : b;
// Return either 1 or -1 to indicate a sort priority
if (a > b) {
return 1;
}
if (a < b) {
return -1;
}
// returning 0 or undefined will use any subsequent column sorting methods or the row index as a tiebreaker
return 0;
}
generateItemsListColumns() { generateItemsListColumns() {
let columns = []; let columns = [];
@ -357,13 +382,11 @@ class WalletsData extends React.Component {
if (!this.state.itemsList || if (!this.state.itemsList ||
(this.state.coin && this.state.coin !== this.props.ActiveCoin.coin) || (this.state.coin && this.state.coin !== this.props.ActiveCoin.coin) ||
(JSON.stringify(this.props.ActiveCoin.txhistory) !== JSON.stringify(this.state.txhistory))) { (JSON.stringify(this.props.ActiveCoin.txhistory) !== JSON.stringify(this.state.txhistory))) {
const sortedItemsList = this.indexTxHistory(sortByDate(this.props.ActiveCoin.txhistory, this.props.ActiveCoin.mode === 'basilisk' ? 'index' : 'confirmations'));
this.setState(Object.assign({}, this.state, { this.setState(Object.assign({}, this.state, {
itemsList: sortedItemsList, itemsList: this.props.ActiveCoin.txhistory,
filteredItemsList: this.filterTransactions(sortedItemsList, this.state.searchTerm), filteredItemsList: this.filterTransactions(this.props.ActiveCoin.txhistory, this.state.searchTerm),
txhistory: this.props.ActiveCoin.txhistory, txhistory: this.props.ActiveCoin.txhistory,
showPagination: this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length >= this.state.defaultPageSize showPagination: this.props.ActiveCoin.txhistory && this.props.ActiveCoin.txhistory.length >= this.state.defaultPageSize,
})); }));
} }
} }
@ -380,7 +403,7 @@ class WalletsData extends React.Component {
} }
this.setState({ this.setState({
itemsListColumns: this.generateItemsListColumns() itemsListColumns: this.generateItemsListColumns(),
}); });
} }
@ -429,7 +452,7 @@ class WalletsData extends React.Component {
onPageSizeChange(pageSize, pageIndex) { onPageSizeChange(pageSize, pageIndex) {
this.setState(Object.assign({}, this.state, { this.setState(Object.assign({}, this.state, {
pageSize: pageSize, pageSize: pageSize,
showPagination: this.state.itemsList && this.state.itemsList.length >= defaultPageSize, showPagination: this.state.itemsList && this.state.itemsList.length >= this.state.defaultPageSize,
})) }))
} }
@ -487,7 +510,7 @@ class WalletsData extends React.Component {
} }
if (_amount !== 'N/A') { if (_amount !== 'N/A') {
_amount = formatValue('round', _amount, -6); _amount = formatValue(_amount);
} }
items.push( items.push(
@ -524,7 +547,7 @@ class WalletsData extends React.Component {
let _amount = _addresses.public[i].amount; let _amount = _addresses.public[i].amount;
if (_amount !== 'N/A') { if (_amount !== 'N/A') {
_amount = formatValue('round', _amount, -6); _amount = formatValue(_amount);
} }
return _amount; return _amount;
@ -539,7 +562,7 @@ class WalletsData extends React.Component {
} }
if (_amount !== 'N/A') { if (_amount !== 'N/A') {
_amount = formatValue('round', _amount, -6); _amount = formatValue(_amount);
} }
return _amount; return _amount;
@ -552,13 +575,15 @@ class WalletsData extends React.Component {
} }
renderSelectorCurrentLabel() { renderSelectorCurrentLabel() {
if (this.state.currentAddress) { const _currentAddress = this.state.currentAddress;
if (_currentAddress) {
return ( return (
<span> <span>
<i className={ 'icon fa-eye' + (this.state.addressType === 'public' ? '' : '-slash') }></i>&nbsp;&nbsp; <i className={ 'icon fa-eye' + (this.state.addressType === 'public' ? '' : '-slash') }></i>&nbsp;&nbsp;
<span className="text"> <span className="text">
[ { this.renderAddressAmount() } { this.props.ActiveCoin.coin } ]&nbsp;&nbsp; [ { this.renderAddressAmount() } { this.props.ActiveCoin.coin } ]&nbsp;&nbsp;
{ this.state.currentAddress } { _currentAddress }
</span> </span>
</span> </span>
); );

14
react/src/components/dashboard/walletsData/walletsData.render.js

@ -13,7 +13,8 @@ export const AddressTypeRender = function() {
return ( return (
<span> <span>
<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>&nbsp;
{ translate('IAPI.PUBLIC_SM') }
</span> </span>
</span> </span>
); );
@ -34,7 +35,7 @@ export const AddressRender = function(tx) {
if (!tx.address) { if (!tx.address) {
return ( return (
<span> <span>
<i className="icon fa-bullseye"></i> <i className="icon fa-bullseye"></i>&nbsp;
<span className="label label-dark"> <span className="label label-dark">
{ translate('DASHBOARD.ZADDR_NOT_LISTED') } { translate('DASHBOARD.ZADDR_NOT_LISTED') }
</span> </span>
@ -154,7 +155,7 @@ export const TxAmountRender = function(tx) {
if (Config.roundValues) { if (Config.roundValues) {
return ( return (
<span title={ tx.amount * _amountNegative }>{ formatValue('round', tx.amount, -6) * _amountNegative || translate('DASHBOARD.UNKNOWN') }</span> <span title={ tx.amount * _amountNegative }>{ formatValue(tx.amount) * _amountNegative || translate('DASHBOARD.UNKNOWN') }</span>
); );
} }
@ -176,6 +177,11 @@ export const TxHistoryListRender = function() {
previousText={ translate('INDEX.PREVIOUS_PAGE') } previousText={ translate('INDEX.PREVIOUS_PAGE') }
showPaginationBottom={ this.state.showPagination } showPaginationBottom={ this.state.showPagination }
pageSize={ this.pageSize } pageSize={ this.pageSize }
defaultSortMethod={ this.tableSorting }
defaultSorted={[{ // default sort
id: 'timestamp',
desc: true,
}]}
onPageSizeChange={ (pageSize, pageIndex) => this.onPageSizeChange(pageSize, pageIndex) } /> onPageSizeChange={ (pageSize, pageIndex) => this.onPageSizeChange(pageSize, pageIndex) } />
); );
}; };
@ -200,7 +206,7 @@ export const WalletsDataRender = function() {
<div className={ 'margin-bottom-3 basilisk-progress-bar ' + (this.state.currentStackLength === 1 || (this.state.currentStackLength === 0 && this.state.totalStackLength === 0) ? 'hide' : 'progress progress-sm') }> <div className={ 'margin-bottom-3 basilisk-progress-bar ' + (this.state.currentStackLength === 1 || (this.state.currentStackLength === 0 && this.state.totalStackLength === 0) ? 'hide' : 'progress progress-sm') }>
<div <div
className="progress-bar progress-bar-striped active progress-bar-indicating progress-bar-success font-size-80-percent" className="progress-bar progress-bar-striped active progress-bar-indicating progress-bar-success font-size-80-percent"
style={{ width: _basiliskProgressBarWidth + '%' }}> style={{ width: `${_basiliskProgressBarWidth}%` }}>
{ translate('SEND.PROCESSING_REQ') }: { this.state.currentStackLength } / { this.state.totalStackLength } { translate('SEND.PROCESSING_REQ') }: { this.state.currentStackLength } / { this.state.totalStackLength }
</div> </div>
</div> </div>

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

@ -32,6 +32,7 @@ class WalletsNativeSend extends React.Component {
fee: 0, fee: 0,
addressSelectorOpen: false, addressSelectorOpen: false,
renderAddressDropdown: true, renderAddressDropdown: true,
substractFee: false,
}; };
this.updateInput = this.updateInput.bind(this); this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
@ -42,10 +43,18 @@ class WalletsNativeSend extends React.Component {
this.setRecieverFromScan = this.setRecieverFromScan.bind(this); this.setRecieverFromScan = this.setRecieverFromScan.bind(this);
this.renderOPIDListCheck = this.renderOPIDListCheck.bind(this); this.renderOPIDListCheck = this.renderOPIDListCheck.bind(this);
this.WalletsNativeSendFormRender = _WalletsNativeSendFormRender.bind(this); this.WalletsNativeSendFormRender = _WalletsNativeSendFormRender.bind(this);
this.isTransparentTx = this.isTransparentTx.bind(this);
this.toggleSubstractFee = this.toggleSubstractFee.bind(this);
} }
WalletsNativeSendFormRender() { WalletsNativeSendFormRender() {
return this._WalletsNativeSendFormRender(); return _WalletsNativeSendFormRender.call(this);
}
toggleSubstractFee() {
this.setState({
substractFee: !this.state.substractFee,
});
} }
componentWillMount() { componentWillMount() {
@ -167,20 +176,20 @@ class WalletsNativeSend extends React.Component {
const _satatusDef = { const _satatusDef = {
queued: { queued: {
icon: 'warning', icon: 'warning',
label: 'QUEUED' label: 'QUEUED',
}, },
executing: { executing: {
icon: 'info', icon: 'info',
label: 'EXECUTING' label: 'EXECUTING',
}, },
failed: { failed: {
icon: 'danger', icon: 'danger',
label: 'FAILED' label: 'FAILED',
}, },
success: { success: {
icon: 'success', icon: 'success',
label: 'SUCCESS' label: 'SUCCESS',
} },
}; };
return ( return (
@ -220,7 +229,7 @@ class WalletsNativeSend extends React.Component {
isWaitingStatus = false; isWaitingStatus = false;
return ( return (
<span> <span>
<strong>txid:</strong> <span>{ opid.result.txid }</span> <strong>{ translate('KMD_NATIVE.TXID') }:</strong> <span>{ opid.result.txid }</span>
<br /> <br />
<strong>{ translate('KMD_NATIVE.EXECUTION_SECONDS') }:</strong> <span>{ opid.execution_secs }</span> <strong>{ translate('KMD_NATIVE.EXECUTION_SECONDS') }:</strong> <span>{ opid.execution_secs }</span>
</span> </span>
@ -303,6 +312,7 @@ class WalletsNativeSend extends React.Component {
fee: 0, fee: 0,
addressSelectorOpen: false, addressSelectorOpen: false,
renderAddressDropdown: true, renderAddressDropdown: true,
substractFee: false,
}); });
} }
@ -366,11 +376,12 @@ class WalletsNativeSend extends React.Component {
validateSendFormData() { validateSendFormData() {
let valid = true; let valid = true;
if (!this.state.sendTo || this.state.sendTo.length < 34) { if (!this.state.sendTo ||
this.state.sendTo.length < 34) {
Store.dispatch( Store.dispatch(
triggerToaster( triggerToaster(
translate('SEND.SEND_TO_ADDRESS_MIN_LENGTH'), translate('SEND.SEND_TO_ADDRESS_MIN_LENGTH'),
'', translate('TOASTR.WALLET_NOTIFICATION'),
'error' 'error'
) )
); );
@ -381,7 +392,7 @@ class WalletsNativeSend extends React.Component {
Store.dispatch( Store.dispatch(
triggerToaster( triggerToaster(
translate('SEND.AMOUNT_POSITIVE_NUMBER'), translate('SEND.AMOUNT_POSITIVE_NUMBER'),
'', translate('TOASTR.WALLET_NOTIFICATION'),
'error' 'error'
) )
); );
@ -392,7 +403,19 @@ class WalletsNativeSend extends React.Component {
Store.dispatch( Store.dispatch(
triggerToaster( triggerToaster(
translate('SEND.INSUFFICIENT_FUNDS'), translate('SEND.INSUFFICIENT_FUNDS'),
'', translate('TOASTR.WALLET_NOTIFICATION'),
'error'
)
);
valid = false;
}
if (this.state.sendTo.length > 34 &&
(!this.state.sendFrom || this.state.sendFrom.length < 34)) {
Store.dispatch(
triggerToaster(
translate('SEND.SELECT_SOURCE_ADDRESS'),
translate('TOASTR.WALLET_NOTIFICATION'),
'error' 'error'
) )
); );
@ -402,6 +425,14 @@ class WalletsNativeSend extends React.Component {
return valid; return valid;
} }
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() { render() {
if (this.props && if (this.props &&

20
react/src/components/dashboard/walletsNativeSend/walletsNativeSend.render.js

@ -27,6 +27,7 @@ export const AddressListRender = function() {
style={{ display: this.state.sendFrom === null ? 'inline-block' : 'none' }}></span> style={{ display: this.state.sendFrom === null ? 'inline-block' : 'none' }}></span>
</a> </a>
</li> </li>
{ this.renderAddressByType('public') }
{ this.renderAddressByType('private') } { this.renderAddressByType('private') }
</ul> </ul>
</div> </div>
@ -74,7 +75,7 @@ export const _WalletsNativeSendFormRender = function() {
{ this.state.renderAddressDropdown && { this.state.renderAddressDropdown &&
<div className="row"> <div className="row">
<div className="col-xlg-12 form-group form-material"> <div className="col-xlg-12 form-group form-material">
<label className="control-label">{ translate('INDEX.SEND_FROM') }</label> <label className="control-label padding-bottom-10">{ translate('INDEX.SEND_FROM') }</label>
{ this.renderAddressList() } { this.renderAddressList() }
</div> </div>
</div> </div>
@ -112,6 +113,23 @@ export const _WalletsNativeSendFormRender = function() {
placeholder="0.000" placeholder="0.000"
autoComplete="off" /> autoComplete="off" />
</div> </div>
<div className={ 'col-lg-6 form-group form-material' + (this.isTransparentTx() ? '' : ' hide') }>
<span className="pointer">
<label className="switch">
<input
type="checkbox"
checked={ this.state.substractFee } />
<div
className="slider"
onClick={ () => this.toggleSubstractFee() }></div>
</label>
<div
className="toggle-label"
onClick={ () => this.toggleSubstractFee() }>
Subtract fee from amount
</div>
</span>
</div>
<div className="col-lg-6 form-group form-material hide"> <div className="col-lg-6 form-group form-material hide">
<label <label
className="control-label" className="control-label"

8
react/src/components/main/main.js

@ -2,6 +2,7 @@ import React from 'react';
import WalletMain from './walletMain'; import WalletMain from './walletMain';
import { iguanaSetRPCAuth } from '../../util/auth'; import { iguanaSetRPCAuth } from '../../util/auth';
import Store from '../../store'; import Store from '../../store';
import { translate } from '../../translate/translate';
import { import {
Config, Config,
getDexCoins, getDexCoins,
@ -26,20 +27,23 @@ class Main extends React.Component {
componentDidMount() { componentDidMount() {
let appVersion; let appVersion;
let zcashParamsExist; let zcashParamsExist;
let appConfig;
try { try {
appVersion = window.require('electron').remote.getCurrentWindow().appBasicInfo; appVersion = window.require('electron').remote.getCurrentWindow().appBasicInfo;
appConfig = window.require('electron').remote.getCurrentWindow().appConfig;
zcashParamsExist = window.require('electron').remote.getCurrentWindow().zcashParamsExist; zcashParamsExist = window.require('electron').remote.getCurrentWindow().zcashParamsExist;
} catch (e) {} } catch (e) {}
if (appVersion) { if (appVersion) {
document.title = `${appVersion.name} (v${appVersion.version.replace('version=', '')}-beta)`; const _appMode = `${appConfig.iguanaLessMode ? ' - ' + translate('INDEX.NATIVE_ONLY_MODE') : ' - ' + translate('INDEX.NORMAL_MODE')}`;
document.title = `${appVersion.name} (v${appVersion.version.replace('version=', '')}-beta)${_appMode}`;
} }
if (!zcashParamsExist) { if (!zcashParamsExist) {
Store.dispatch( Store.dispatch(
triggerToaster( triggerToaster(
'Zcash params are missing', translate('KMD_NATIVE.ZCASH_PARAMS_MISSING'),
'Komodo', 'Komodo',
'error', 'error',
false false

9
react/src/components/overrides.scss

@ -1071,6 +1071,13 @@ select{
top: 4px; top: 4px;
} }
table { table {
width: 80%; width: 100%;
td:first-child {
width: 40%;
}
td:last-child {
width: 60%;
}
} }
} }

10
react/src/translate/en.js

@ -35,7 +35,7 @@ export const _lang = {
'ADDRESS_ALREADY_REG': 'Address already registered', 'ADDRESS_ALREADY_REG': 'Address already registered',
'COULDNT_COPY_ADDRESS': 'Couldn\'t copy address to clipboard', 'COULDNT_COPY_ADDRESS': 'Couldn\'t copy address to clipboard',
'COULDNT_CREATE_SEED': 'Couldn\'t create new wallet seed', 'COULDNT_CREATE_SEED': 'Couldn\'t create new wallet seed',
'WALLETDAT_MISMATCH': 'Your wallet.dat is not matching the blockchain. Please resync from the scratch.', 'WALLETDAT_MISMATCH': 'Your wallet.dat is not matching the blockchain. Please restart the wallet with -reindex param.',
'PEER_ADDED': 'Peer is added', 'PEER_ADDED': 'Peer is added',
'ADDNODE_ALREADY_PENDING': 'Addnode connection was already pending', 'ADDNODE_ALREADY_PENDING': 'Addnode connection was already pending',
'PEER_ALREADY_CONN': 'Peer was already connected', 'PEER_ALREADY_CONN': 'Peer was already connected',
@ -46,6 +46,8 @@ export const _lang = {
'NO_ACTIVE_COIN': 'No active coin', 'NO_ACTIVE_COIN': 'No active coin',
}, },
'INDEX': { 'INDEX': {
'NATIVE_ONLY_MODE': 'Native only mode',
'NORMAL_MODE': 'Normal mode',
'T_FUNDS': 'Transparent funds', 'T_FUNDS': 'Transparent funds',
'HASH': 'Hash', 'HASH': 'Hash',
'SYNC_IN_PROGRESS': 'Synchronization is in progress', 'SYNC_IN_PROGRESS': 'Synchronization is in progress',
@ -443,6 +445,9 @@ export const _lang = {
'QR_ERR_UNKNOWN': 'Error: unknown error!', 'QR_ERR_UNKNOWN': 'Error: unknown error!',
}, },
'TOASTR': { 'TOASTR': {
'KOMODO_DATADIR_INVALID': 'Komodo datadir path is invalid',
'KOMODO_DATADIR_NOT_DIR': 'Komodo datadir path is not a directory',
'INVALID_ADDRESS': 'Invalid @template@ address',
'RESTART_AGAMA_WITH_REINDEX_PARAM': 'Restart Agama and run Komodo with -reindex param', 'RESTART_AGAMA_WITH_REINDEX_PARAM': 'Restart Agama and run Komodo with -reindex param',
'JUMBLR_DEPOSIT_ADDRESS_SET': 'Jumblr deposit address is set', 'JUMBLR_DEPOSIT_ADDRESS_SET': 'Jumblr deposit address is set',
'JUMBLR_SECRET_ADDRESSES_IMPORTED': 'Jumblr secret addresses imported', 'JUMBLR_SECRET_ADDRESSES_IMPORTED': 'Jumblr secret addresses imported',
@ -544,6 +549,8 @@ export const _lang = {
'MESSAGE': 'Message', 'MESSAGE': 'Message',
'EXECUTION_SECONDS': 'Execution Seconds', 'EXECUTION_SECONDS': 'Execution Seconds',
'WAIT_UNTIL_SYNCED': 'Transaction history is unavailable during synchronization progresss', 'WAIT_UNTIL_SYNCED': 'Transaction history is unavailable during synchronization progresss',
'TXID': 'Transaction ID',
'ZCASH_PARAMS_MISSING': 'Zcash params are missing',
}, },
'LOGIN': { 'LOGIN': {
'QUICK_ACCESS': 'Quick access', 'QUICK_ACCESS': 'Quick access',
@ -638,6 +645,7 @@ export const _lang = {
'FEE_POSITIVE_NUMBER': 'Fee must be a positive number', 'FEE_POSITIVE_NUMBER': 'Fee must be a positive number',
'TOTAL_AMOUNT_POSITIVE_NUMBER': 'Total amount (amount - fee) must be a positive number', 'TOTAL_AMOUNT_POSITIVE_NUMBER': 'Total amount (amount - fee) must be a positive number',
'INSUFFICIENT_FUNDS': 'You don\'t have the necessary funds to make this transaction', 'INSUFFICIENT_FUNDS': 'You don\'t have the necessary funds to make this transaction',
'SELECT_SOURCE_ADDRESS': 'Select source (from) address',
}, },
'FIAT_CURRENCIES': { 'FIAT_CURRENCIES': {
'AUD': 'Australian Dollar (AUD)', 'AUD': 'Australian Dollar (AUD)',

8
react/src/translate/translate.js

@ -1,7 +1,7 @@
import { _lang } from './en'; import { _lang } from './en';
import Config from '../config'; import Config from '../config';
export function translate(langID) { export function translate(langID, interpolateStr) {
let defaultLang = Config.defaultLang || 'EN'; let defaultLang = Config.defaultLang || 'EN';
if (langID && if (langID &&
@ -11,7 +11,11 @@ export function translate(langID) {
if (_lang && if (_lang &&
langIDComponents && langIDComponents &&
_lang[defaultLang][langIDComponents[0]][langIDComponents[1]]) { _lang[defaultLang][langIDComponents[0]][langIDComponents[1]]) {
return _lang[defaultLang][langIDComponents[0]][langIDComponents[1]]; if (interpolateStr) {
return _lang[defaultLang][langIDComponents[0]][langIDComponents[1]].replace('@template@', interpolateStr);
} else {
return _lang[defaultLang][langIDComponents[0]][langIDComponents[1]];
}
} else { } else {
console.warn(`Missing translation ${langID} in js/${defaultLang.toLowerCase()}.js`); console.warn(`Missing translation ${langID} in js/${defaultLang.toLowerCase()}.js`);
return `--> ${langID} <--`; return `--> ${langID} <--`;

66
react/src/util/formatValue.js

@ -1,52 +1,24 @@
// ref: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math/round#Decimal_rounding // display rounding
export function formatValue(formatType, formatValue, formatExp) { export function formatValue(formatValue) {
let _formatExp; const _valueToStr = formatValue.toString();
/**
* Decimal adjustment of a number.
*
* @param {String} type The type of adjustment.
* @param {Number} value The number.
* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
* @returns {Number} The adjusted value.
*/
function decimalAdjust(type, value, exp) {
// If the exp is undefined or zero...
if (typeof exp === 'undefined' || +exp === 0) {
return Math[type](value);
}
value = +value;
exp = +exp;
// If the value is not a number or the exp is not an integer...
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
return NaN;
}
// If the value is negative...
if (value < 0) {
return -decimalAdjust(type, -value, exp);
}
// Shift
value = value.toString().split('e');
value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
}
if (Math.abs(Number(formatValue)) >= 1) { if (_valueToStr.indexOf('.') === -1) {
_formatExp = -3; return formatValue;
} else { } else {
_formatExp = formatExp; if (_valueToStr) {
} const _decimal = _valueToStr.substr(_valueToStr.indexOf('.') + 1, _valueToStr.length);
let newVal = _valueToStr.substr(0, _valueToStr.indexOf('.') + 1);
for (let i = 0; i < _decimal.length; i++) {
if (_decimal[i] === '0') {
newVal = newVal + _decimal[i];
} else {
newVal = newVal + _decimal[i];
break;
}
}
switch (formatType) { return newVal;
case 'round': }
return decimalAdjust('round', formatValue, _formatExp);
break;
case 'floor':
return decimalAdjust('floor', formatValue, _formatExp);
break;
case 'ceil':
return decimalAdjust('ceil', formatValue, _formatExp);
break;
} }
} }

2
react/src/util/sort.js

@ -1,4 +1,4 @@
export function sortByDate(data, sortKey) { export function sortByDate(data, sortKey) { // deprecated
return data.sort(function(a, b) { return data.sort(function(a, b) {
if (a[sortKey] < b[sortKey]) { if (a[sortKey] < b[sortKey]) {
return -1; return -1;

Loading…
Cancel
Save