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
- claim interest modal
- 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
--------------

22
react/src/actions/actionCreators.js

@ -193,7 +193,7 @@ export function triggerToaster(message, title, _type, autoClose = true) {
message,
title,
_type,
autoClose
autoClose,
}
}
@ -201,7 +201,7 @@ export function triggerToaster(message, title, _type, autoClose = true) {
export function dismissToaster(toastId) {
return {
type: REMOVE_TOASTER_MESSAGE,
toastId: toastId
toastId: toastId,
}
}
@ -217,7 +217,7 @@ export function dashboardCoinsState(json) {
return {
type: GET_ACTIVE_COINS,
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 &&
json.error) {
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++) {
publicAddressArray.push({
'address': json.result[i],
'amount': 'N/A'
address: json.result[i],
amount: 'N/A',
});
}
@ -320,7 +326,7 @@ export function setBasiliskMainAddress(json, coin, mode) {
return {
type: ACTIVE_COIN_GET_ADDRESSES,
addresses: { 'public': [] },
addresses: { public: [] },
}
}
@ -330,7 +336,7 @@ export function getNativeTxHistoryState(json) {
json = null;
} else if (json && json.result && json.result.length) {
json = json.result;
} else if (!json || !json.result.length) {
} else if (!json || (!json.result || !json.result.length)) {
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) {
let acData;
let herdData = {
@ -251,23 +262,35 @@ export function shepherdHerd(coin, mode, path, startupParams) {
)
);
})
.then(response => response.json())
.then(handleErrors)
.then(function(json) {
if (Config.iguanaLessMode) {
dispatch(
addCoinResult(coin, mode)
);
setTimeout(() => {
if (json) {
if (Config.iguanaLessMode) {
dispatch(
iguanaActiveHandleBypass()
addCoinResult(coin, mode)
);
}, 1000);
setTimeout(() => {
dispatch(
iguanaActiveHandleBypass()
);
}, 1000);
} else {
dispatch(
iguanaAddCoin(
coin,
mode,
acData
)
);
}
} else {
console.warn(acData);
dispatch(
iguanaAddCoin(
coin,
mode,
acData
triggerToaster(
`Error starting ${coin} daemon. Port ${acData.rpc} is already taken!`,
translate('TOASTR.SERVICE_NOTIFICATION'),
'error',
false
)
);
}

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

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

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

@ -704,8 +704,8 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) {
'WLC': {
'name': 'WIRELESS',
'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}) : {},
'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})
'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.WLC - 1,'rpc':assetChainPorts.WLC})
},
'PANGEA': {
'name': 'PANGEA',

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

@ -17,6 +17,7 @@ import {
shepherdCli,
checkForUpdateUIPromise,
updateUIPromise,
triggerToaster,
} from '../../../actions/actionCreators';
import Store from '../../../store';
@ -106,8 +107,6 @@ class Settings extends React.Component {
appConfigSchema: _appConfigSchema,
appSettings: _appSettings,
}));
console.warn(_appSettings);
} catch(e) {}
}
@ -263,14 +262,15 @@ class Settings extends React.Component {
renderUpdateStatus() {
let items = [];
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(
<div key={ `settings-update-log-${i}` }>{ this.state.updateLog[i] }</div>
);
}
if (this.state.updateLog.length) {
if (_updateLogLength) {
return (
<div style={{ minHeight: '200px' }}>
<hr />
@ -279,7 +279,7 @@ class Settings extends React.Component {
<div className={ updateProgressBar.patch > -1 ? 'progress progress-sm' : 'hide' }>
<div
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>
@ -300,7 +300,7 @@ class Settings extends React.Component {
shepherdCli(
'passthru',
this.state.cliCoin,
this.state.cliCmd
this.state.cliCmdString
)
);
}
@ -448,17 +448,53 @@ class Settings extends React.Component {
_saveAppConfig() {
const _appSettings = this.state.appSettings;
let _appSettingsPristine = Object.assign({}, this.props.Settings.appSettings);
let isError = false;
let saveAfterPathCheck = false;
for (let key in _appSettings) {
if (key.indexOf('__') === -1) {
_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 {
const _nestedKey = key.split('__');
_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() {
@ -503,11 +539,12 @@ class Settings extends React.Component {
value={ _appConfig[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
type="text"
name={ `${key}__${_key}` }
value={ _appConfig[key][_key] }
className={ this.state.appConfigSchema[key][_key].type === 'folder' ? 'full-width': '' }
onChange={ (event) => this.updateInputSettings(event, key, _key) } />
}
{ this.state.appConfigSchema[key][_key].type === 'boolean' &&
@ -550,11 +587,12 @@ class Settings extends React.Component {
value={ _appConfig[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
type="text"
name={ `${key}` }
value={ _appConfig[key] }
className={ this.state.appConfigSchema[key].type === 'folder' ? 'full-width': '' }
onChange={ (event) => this.updateInputSettings(event, key) } />
}
{ this.state.appConfigSchema[key].type === 'boolean' &&

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

@ -605,7 +605,7 @@ export const SettingsRender = function() {
<button
type="button"
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>
</div>
<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
className="pull-right padding-top-10 font-size-22"
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>
</div>
</div>
@ -58,7 +58,7 @@ const WalletsBalanceRender = function() {
<span
className="pull-right padding-top-10 font-size-22"
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>
</div>
</div>
@ -79,7 +79,7 @@ const WalletsBalanceRender = function() {
<span
className="pull-right padding-top-10 font-size-22"
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>
</div>
</div>
@ -100,7 +100,7 @@ const WalletsBalanceRender = function() {
<span
className="pull-right padding-top-10 font-size-22"
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>
</div>
</div>

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

@ -103,6 +103,31 @@ class WalletsData extends React.Component {
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() {
let columns = [];
@ -357,13 +382,11 @@ class WalletsData extends React.Component {
if (!this.state.itemsList ||
(this.state.coin && this.state.coin !== this.props.ActiveCoin.coin) ||
(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, {
itemsList: sortedItemsList,
filteredItemsList: this.filterTransactions(sortedItemsList, this.state.searchTerm),
itemsList: this.props.ActiveCoin.txhistory,
filteredItemsList: this.filterTransactions(this.props.ActiveCoin.txhistory, this.state.searchTerm),
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({
itemsListColumns: this.generateItemsListColumns()
itemsListColumns: this.generateItemsListColumns(),
});
}
@ -429,7 +452,7 @@ class WalletsData extends React.Component {
onPageSizeChange(pageSize, pageIndex) {
this.setState(Object.assign({}, this.state, {
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') {
_amount = formatValue('round', _amount, -6);
_amount = formatValue(_amount);
}
items.push(
@ -524,7 +547,7 @@ class WalletsData extends React.Component {
let _amount = _addresses.public[i].amount;
if (_amount !== 'N/A') {
_amount = formatValue('round', _amount, -6);
_amount = formatValue(_amount);
}
return _amount;
@ -539,7 +562,7 @@ class WalletsData extends React.Component {
}
if (_amount !== 'N/A') {
_amount = formatValue('round', _amount, -6);
_amount = formatValue(_amount);
}
return _amount;
@ -552,13 +575,15 @@ class WalletsData extends React.Component {
}
renderSelectorCurrentLabel() {
if (this.state.currentAddress) {
const _currentAddress = this.state.currentAddress;
if (_currentAddress) {
return (
<span>
<i className={ 'icon fa-eye' + (this.state.addressType === 'public' ? '' : '-slash') }></i>&nbsp;&nbsp;
<span className="text">
[ { this.renderAddressAmount() } { this.props.ActiveCoin.coin } ]&nbsp;&nbsp;
{ this.state.currentAddress }
{ _currentAddress }
</span>
</span>
);

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

@ -13,7 +13,8 @@ export const AddressTypeRender = function() {
return (
<span>
<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>
);
@ -34,7 +35,7 @@ export const AddressRender = function(tx) {
if (!tx.address) {
return (
<span>
<i className="icon fa-bullseye"></i>
<i className="icon fa-bullseye"></i>&nbsp;
<span className="label label-dark">
{ translate('DASHBOARD.ZADDR_NOT_LISTED') }
</span>
@ -154,7 +155,7 @@ export const TxAmountRender = function(tx) {
if (Config.roundValues) {
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') }
showPaginationBottom={ this.state.showPagination }
pageSize={ this.pageSize }
defaultSortMethod={ this.tableSorting }
defaultSorted={[{ // default sort
id: 'timestamp',
desc: true,
}]}
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="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 }
</div>
</div>

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

@ -32,6 +32,7 @@ class WalletsNativeSend extends React.Component {
fee: 0,
addressSelectorOpen: false,
renderAddressDropdown: true,
substractFee: false,
};
this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
@ -42,10 +43,18 @@ class WalletsNativeSend extends React.Component {
this.setRecieverFromScan = this.setRecieverFromScan.bind(this);
this.renderOPIDListCheck = this.renderOPIDListCheck.bind(this);
this.WalletsNativeSendFormRender = _WalletsNativeSendFormRender.bind(this);
this.isTransparentTx = this.isTransparentTx.bind(this);
this.toggleSubstractFee = this.toggleSubstractFee.bind(this);
}
WalletsNativeSendFormRender() {
return this._WalletsNativeSendFormRender();
return _WalletsNativeSendFormRender.call(this);
}
toggleSubstractFee() {
this.setState({
substractFee: !this.state.substractFee,
});
}
componentWillMount() {
@ -167,20 +176,20 @@ class WalletsNativeSend extends React.Component {
const _satatusDef = {
queued: {
icon: 'warning',
label: 'QUEUED'
label: 'QUEUED',
},
executing: {
icon: 'info',
label: 'EXECUTING'
label: 'EXECUTING',
},
failed: {
icon: 'danger',
label: 'FAILED'
label: 'FAILED',
},
success: {
icon: 'success',
label: 'SUCCESS'
}
label: 'SUCCESS',
},
};
return (
@ -220,7 +229,7 @@ class WalletsNativeSend extends React.Component {
isWaitingStatus = false;
return (
<span>
<strong>txid:</strong> <span>{ opid.result.txid }</span>
<strong>{ translate('KMD_NATIVE.TXID') }:</strong> <span>{ opid.result.txid }</span>
<br />
<strong>{ translate('KMD_NATIVE.EXECUTION_SECONDS') }:</strong> <span>{ opid.execution_secs }</span>
</span>
@ -303,6 +312,7 @@ class WalletsNativeSend extends React.Component {
fee: 0,
addressSelectorOpen: false,
renderAddressDropdown: true,
substractFee: false,
});
}
@ -366,11 +376,12 @@ class WalletsNativeSend extends React.Component {
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'
)
);
@ -381,7 +392,7 @@ class WalletsNativeSend extends React.Component {
Store.dispatch(
triggerToaster(
translate('SEND.AMOUNT_POSITIVE_NUMBER'),
'',
translate('TOASTR.WALLET_NOTIFICATION'),
'error'
)
);
@ -392,7 +403,19 @@ class WalletsNativeSend extends React.Component {
Store.dispatch(
triggerToaster(
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'
)
);
@ -402,6 +425,14 @@ class WalletsNativeSend extends React.Component {
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() {
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>
</a>
</li>
{ this.renderAddressByType('public') }
{ this.renderAddressByType('private') }
</ul>
</div>
@ -74,7 +75,7 @@ export const _WalletsNativeSendFormRender = function() {
{ this.state.renderAddressDropdown &&
<div className="row">
<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() }
</div>
</div>
@ -112,6 +113,23 @@ export const _WalletsNativeSendFormRender = function() {
placeholder="0.000"
autoComplete="off" />
</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">
<label
className="control-label"

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

@ -2,6 +2,7 @@ import React from 'react';
import WalletMain from './walletMain';
import { iguanaSetRPCAuth } from '../../util/auth';
import Store from '../../store';
import { translate } from '../../translate/translate';
import {
Config,
getDexCoins,
@ -26,20 +27,23 @@ class Main extends React.Component {
componentDidMount() {
let appVersion;
let zcashParamsExist;
let appConfig;
try {
appVersion = window.require('electron').remote.getCurrentWindow().appBasicInfo;
appConfig = window.require('electron').remote.getCurrentWindow().appConfig;
zcashParamsExist = window.require('electron').remote.getCurrentWindow().zcashParamsExist;
} catch (e) {}
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) {
Store.dispatch(
triggerToaster(
'Zcash params are missing',
translate('KMD_NATIVE.ZCASH_PARAMS_MISSING'),
'Komodo',
'error',
false

9
react/src/components/overrides.scss

@ -1071,6 +1071,13 @@ select{
top: 4px;
}
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',
'COULDNT_COPY_ADDRESS': 'Couldn\'t copy address to clipboard',
'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',
'ADDNODE_ALREADY_PENDING': 'Addnode connection was already pending',
'PEER_ALREADY_CONN': 'Peer was already connected',
@ -46,6 +46,8 @@ export const _lang = {
'NO_ACTIVE_COIN': 'No active coin',
},
'INDEX': {
'NATIVE_ONLY_MODE': 'Native only mode',
'NORMAL_MODE': 'Normal mode',
'T_FUNDS': 'Transparent funds',
'HASH': 'Hash',
'SYNC_IN_PROGRESS': 'Synchronization is in progress',
@ -443,6 +445,9 @@ export const _lang = {
'QR_ERR_UNKNOWN': 'Error: unknown error!',
},
'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',
'JUMBLR_DEPOSIT_ADDRESS_SET': 'Jumblr deposit address is set',
'JUMBLR_SECRET_ADDRESSES_IMPORTED': 'Jumblr secret addresses imported',
@ -544,6 +549,8 @@ export const _lang = {
'MESSAGE': 'Message',
'EXECUTION_SECONDS': 'Execution Seconds',
'WAIT_UNTIL_SYNCED': 'Transaction history is unavailable during synchronization progresss',
'TXID': 'Transaction ID',
'ZCASH_PARAMS_MISSING': 'Zcash params are missing',
},
'LOGIN': {
'QUICK_ACCESS': 'Quick access',
@ -638,6 +645,7 @@ export const _lang = {
'FEE_POSITIVE_NUMBER': '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',
'SELECT_SOURCE_ADDRESS': 'Select source (from) address',
},
'FIAT_CURRENCIES': {
'AUD': 'Australian Dollar (AUD)',

8
react/src/translate/translate.js

@ -1,7 +1,7 @@
import { _lang } from './en';
import Config from '../config';
export function translate(langID) {
export function translate(langID, interpolateStr) {
let defaultLang = Config.defaultLang || 'EN';
if (langID &&
@ -11,7 +11,11 @@ export function translate(langID) {
if (_lang &&
langIDComponents &&
_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 {
console.warn(`Missing translation ${langID} in js/${defaultLang.toLowerCase()}.js`);
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
export function formatValue(formatType, formatValue, formatExp) {
let _formatExp;
/**
* 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));
}
// display rounding
export function formatValue(formatValue) {
const _valueToStr = formatValue.toString();
if (Math.abs(Number(formatValue)) >= 1) {
_formatExp = -3;
if (_valueToStr.indexOf('.') === -1) {
return formatValue;
} 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) {
case 'round':
return decimalAdjust('round', formatValue, _formatExp);
break;
case 'floor':
return decimalAdjust('floor', formatValue, _formatExp);
break;
case 'ceil':
return decimalAdjust('ceil', formatValue, _formatExp);
break;
return newVal;
}
}
}

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) {
if (a[sortKey] < b[sortKey]) {
return -1;

Loading…
Cancel
Save