Browse Source

resolved merge conflicts

all-modes^2
pbca26 8 years ago
parent
commit
8fdc9da0eb
  1. 359
      assets/mainWindow/css/loading.css
  2. BIN
      assets/mainWindow/img/fa-caret-down.png
  3. BIN
      assets/mainWindow/img/fa-caret-up.png
  4. BIN
      assets/mainWindow/img/fa-close.png
  5. BIN
      assets/mainWindow/img/fa-cogs.png
  6. BIN
      assets/mainWindow/img/fa-cube.png
  7. BIN
      assets/mainWindow/img/fa-cubes.png
  8. BIN
      assets/mainWindow/img/fa-question.png
  9. 6
      assets/mainWindow/js/init.js
  10. 301
      assets/mainWindow/js/loading.js
  11. 3
      react/change.log
  12. 63
      react/src/actions/actionCreators.js
  13. 34
      react/src/actions/actions/addCoin.js
  14. 113
      react/src/actions/actions/addressBalance.js
  15. 30
      react/src/actions/actions/atomic.js
  16. 4
      react/src/actions/actions/basiliskCache.js
  17. 56
      react/src/actions/actions/basiliskProcessAddress.js
  18. 4
      react/src/actions/actions/basiliskTxHistory.js
  19. 4
      react/src/actions/actions/cli.js
  20. 4
      react/src/actions/actions/coinList.js
  21. 30
      react/src/actions/actions/createWallet.js
  22. 30
      react/src/actions/actions/dexCoins.js
  23. 49
      react/src/actions/actions/edexBalance.js
  24. 30
      react/src/actions/actions/edexGetTx.js
  25. 30
      react/src/actions/actions/fullTxHistory.js
  26. 30
      react/src/actions/actions/getAddrByAccount.js
  27. 30
      react/src/actions/actions/iguanaHelpers.js
  28. 20
      react/src/actions/actions/iguanaInstance.js
  29. 4
      react/src/actions/actions/interest.js
  30. 8
      react/src/actions/actions/jumblr.js
  31. 61
      react/src/actions/actions/log.js
  32. 30
      react/src/actions/actions/logout.js
  33. 30
      react/src/actions/actions/nativeBalance.js
  34. 86
      react/src/actions/actions/nativeDashboardUpdate.js
  35. 30
      react/src/actions/actions/nativeNewAddress.js
  36. 61
      react/src/actions/actions/nativeSend.js
  37. 235
      react/src/actions/actions/nativeSyncInfo.js
  38. 30
      react/src/actions/actions/nativeTxHistory.js
  39. 223
      react/src/actions/actions/notary.js
  40. 4
      react/src/actions/actions/openAlias.js
  41. 126
      react/src/actions/actions/pin.js
  42. 110
      react/src/actions/actions/sendFullBasilisk.js
  43. 86
      react/src/actions/actions/settings.js
  44. 30
      react/src/actions/actions/syncInfo.js
  45. 4
      react/src/actions/actions/syncOnly.js
  46. 4
      react/src/actions/actions/sysInfo.js
  47. 4
      react/src/actions/actions/update.js
  48. 127
      react/src/actions/actions/walletAuth.js
  49. 14
      react/src/actions/storeType.js
  50. 29
      react/src/components/addcoin/addcoin.js
  51. 59
      react/src/components/addcoin/addcoin.scss
  52. 46
      react/src/components/addcoin/addcoinOptionsAC.js
  53. 77
      react/src/components/addcoin/addcoinOptionsACFiat.js
  54. 56
      react/src/components/addcoin/addcoinOptionsCrypto.js
  55. 8
      react/src/components/addcoin/coin-selectors.render.js
  56. 3
      react/src/components/addcoin/payload.js
  57. 1
      react/src/components/app/app.js
  58. 14
      react/src/components/dashboard/atomic/atomic.js
  59. 26
      react/src/components/dashboard/claimInterestModal/claimInterestModal.js
  60. 53
      react/src/components/dashboard/claimInterestModal/claimInterestModal.render.js
  61. 47
      react/src/components/dashboard/claimInterestModal/claimInterestModal.scss
  62. 23
      react/src/components/dashboard/coinTile/coinTile.js
  63. 197
      react/src/components/dashboard/coinTile/coinTileItem.js
  64. 2
      react/src/components/dashboard/coinTile/coinTileItem.render.js
  65. 51
      react/src/components/dashboard/coindDownModal/coindDownModal.js
  66. 5
      react/src/components/dashboard/coindDownModal/coindDownModal.render.js
  67. 24
      react/src/components/dashboard/coindDownModal/coindDownModal.scss
  68. 243
      react/src/components/dashboard/importKeyModal/importKeyModal.js
  69. 136
      react/src/components/dashboard/importKeyModal/importKeyModal.render.js
  70. 33
      react/src/components/dashboard/importKeyModal/importKeyModal.scss
  71. 29
      react/src/components/dashboard/jumblr/jumblr.js
  72. 2
      react/src/components/dashboard/jumblr/jumblr.render.js
  73. 92
      react/src/components/dashboard/jumblr/jumblr.scss
  74. 2
      react/src/components/dashboard/loginModal/loginModal.render.js
  75. 9
      react/src/components/dashboard/loginSettingsModal/loginSettingsModal.js
  76. 3
      react/src/components/dashboard/loginSettingsModal/loginSettingsModal.render.js
  77. 7
      react/src/components/dashboard/loginSettingsModal/loginSettingsModal.scss
  78. 17
      react/src/components/dashboard/main/dashboard.js
  79. 36
      react/src/components/dashboard/main/dashboard.render.js
  80. 40
      react/src/components/dashboard/navbar/navbar.js
  81. 13
      react/src/components/dashboard/navbar/navbar.render.js
  82. 110
      react/src/components/dashboard/notifications/notifications.js
  83. 116
      react/src/components/dashboard/notifications/notifications.render.js
  84. 4
      react/src/components/dashboard/qrModal/qrModal.js
  85. 76
      react/src/components/dashboard/qrModal/qrModal.render.js
  86. 11
      react/src/components/dashboard/qrModal/qrModal.scss
  87. 29
      react/src/components/dashboard/receiveCoin/receiveCoin.js
  88. 50
      react/src/components/dashboard/sendCoin/sendCoin.js
  89. 180
      react/src/components/dashboard/settings/settings.addNodePanel.js
  90. 90
      react/src/components/dashboard/settings/settings.appInfoPanel.js
  91. 321
      react/src/components/dashboard/settings/settings.appSettingsPanel.js
  92. 151
      react/src/components/dashboard/settings/settings.appUpdatePanel.js
  93. 206
      react/src/components/dashboard/settings/settings.cliPanel.js
  94. 180
      react/src/components/dashboard/settings/settings.debugLogPanel.js
  95. 235
      react/src/components/dashboard/settings/settings.exportKeysPanel.js
  96. 23
      react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js
  97. 67
      react/src/components/dashboard/settings/settings.importKeysPanel.js
  98. 818
      react/src/components/dashboard/settings/settings.js
  99. 575
      react/src/components/dashboard/settings/settings.render.js
  100. 121
      react/src/components/dashboard/settings/settings.scss

359
assets/mainWindow/css/loading.css

@ -1,7 +1,7 @@
body {
overflow: hidden !important;
border: solid 1px #ccc;
height: 300px;
user-select: none;
cursor: default;
}
.text-center {
@ -19,30 +19,41 @@ body {
margin: auto;
}
.pulse-loader {
position: absolute;
top: 10px;
left: -100px;
margin: 80px 50px;
width: 400px !important;
}
body.agamaMode {
background-color: rgba(33, 33, 33, 0.85);
padding-top: 40px;
color: #fff;
}
body.loading-window,
body.agama-default-window-height {
height: 355px;
}
body.agama-app-settings-window {
height: 700px;
}
.agama-logo {
padding-bottom: 20px;
}
#agamaModeStatus {
padding-bottom: 25px;
padding-bottom: 35px;
font-weight: bold;
font-size: 16px;
}
.btn-info {
color: #fff;
background-color: #25b4c5 !important;
border-color: #25b4c5 !important;
}
.btn-info:hover {
background-color: #6cd2de !important;
border-color: #6cd2de !important;
}
.btn-primary.focus,
.btn-primary:focus,
.btn-primary:hover,
@ -67,8 +78,8 @@ body.agamaMode {
font-size: 14px;
line-height: 1.57142857;
border-radius: 3px;
-webkit-box-shadow: 0 1px 4px 0 rgba(0,0,0,.1);
box-shadow: 0 1px 4px 0 rgba(0,0,0,.1);
-webkit-box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.1);
-webkit-transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear;
-o-transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear;
transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear;
@ -114,4 +125,326 @@ body.agamaMode {
.app-closing {
position: relative;
top: 50px;
}
.height--auto {
height: auto;
}
.settings-title {
font-weight: bold;
margin-bottom: 30px;
}
.margin-right-5 {
margin-right: 5px;
}
.margin-right-10 {
margin-right: 10px;
}
.margin-right-20 {
margin-right: 20px;
}
.margin-top-15 {
margin-top: 15px;
}
.margin-top-20 {
margin-top: 20px;
}
.pull-left {
float: left;
margin-left: 50px;
}
.btn-close {
border-bottom-left-radius: 50%;
background: #fff;
color: rgba(33, 33, 33, 0.85);
padding: 8px 10px;
font-weight: bold;
font-size: 20px;
position: absolute;
top: 0;
right: 0;
cursor: pointer;
}
.btn-close img {
height: 12px;
position: relative;
top: -1px;
right: -1px;
}
.btn-mode img {
height: 20px;
position: relative;
top: -1px;
left: -4px;
padding-right: 5px;
}
/* settings */
.settings-help {
position: relative;
top: -2px;
left: 10px;
color: #fff;
border-radius: 50%;
background: #5683ad;
display: inline-block;
padding: 4px 4px;
line-height: 30px;
cursor: default;
}
.settings-help img {
height: 13px;
}
.settings-buttons-block {
margin-top: 50px;
margin-right: 50px;
text-align: right;
}
.settings-table {
margin: 0 auto;
width: 650px;
text-align: left;
}
.settings-table input[type="number"] {
width: 100px;
padding: 0 4px;
}
.settings-table input[type="text"] {
width: 100%;
padding: 0 4px;
}
.settings-table td {
padding-bottom: 35px;
}
.settings-table tr:last-child td {
padding: 0;
}
.settings-table .left {
width: 50%;
}
.settings-table .right {
width: 50%;
text-align: left;
}
.agama-app-settings-window #agamaModeStatus {
padding-bottom: 50px;
}
/* toggle */
.slider {
border-radius: 20px;
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
transition: .4s;
}
.switch input {
display: none;
}
input[type=checkbox],
input[type=radio] {
margin: 4px 0 0;
margin-top: 1px\9;
line-height: normal;
}
input[type=checkbox],
input[type=radio] {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
.switch {
position: relative;
display: inline-block;
width: 40px;
height: 24px;
}
label {
font-weight: 300;
}
label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: 700;
}
input:checked + .slider {
background: #36ab7a;
}
input:checked + .slider:before {
background: #fff;
}
input:checked + .slider:before {
-ms-transform: translateX(16px);
transform: translateX(16px);
}
.slider:before {
content: '';
display: inline-block;
border-radius: 50%;
position: absolute;
height: 20px;
width: 20px;
left: 2px;
bottom: 2px;
background-color: #ccc;
transition: .4s;
}
input[type="text"],
input[type="number"] {
color: rgb(33, 33, 33);
}
/* toastr */
#toast-container {
position: fixed;
z-index: 999999;
}
.toast-bottom-right {
right: 12px;
bottom: 12px;
}
#toast-container > .toast-success {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==) !important;
}
#toast-container > .toast-error {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=) !important;
}
#toast-container > div {
margin: 0 0 6px;
padding: 15px 15px 15px 50px;
width: 300px;
-moz-border-radius: 3px 3px 3px 3px;
-webkit-border-radius: 3px 3px 3px 3px;
border-radius: 3px 3px 3px 3px;
background-position: 15px center;
background-repeat: no-repeat;
color: #fff;
}
.toast-success {
background-color: #51a351;
}
.toast-error {
background-color: #bd362f;
}
.toast-title {
font-weight: bold;
text-align: left;
margin-left: 10px;
}
button.toast-close-button {
padding: 0;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
}
.toast-close-button {
position: relative;
right: -0.3em;
top: -0.3em;
float: right;
font-size: 20px;
font-weight: bold;
color: #fff;
-webkit-text-shadow: 0 1px 0 #fff;
text-shadow: 0 1px 0 #fff;
opacity: .8;
-ms-filter: alpha(opacity=80);
filter: alpha(opacity=80);
}
.toast-message {
text-align: left;
margin-left: 10px;
-ms-word-wrap: break-word;
word-wrap: break-word;
}
.test-bins {
text-align: left;
margin-top: 10px;
margin-left: 30px;
}
.btn-caret {
display: inline-block;
position: relative;
left: -4px;
height: 36px;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
box-shadow: none;
width: 38px;
}
.btn-caret:before {
content: '';
display: inline-block;
position: absolute;
height: 25px;
background: #fff;
width: 1px;
left: -2px;
top: 4px;
}
.btn-caret img {
height: 14px;
position: absolute;
top: 10px;
left: 10px;
}
.btn-native {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
.btn-native:hover + .btn-caret:before {
display: none;
}
.btn-caret:hover:before {
display: none;
}
.dropdown-menu {
display: inherit;
top: inherit;
left: inherit;
right: 48%;
padding: 2px 0;
}
.dropdown-menu li {
cursor: pointer;
margin: 5px 0;
}
body.iguana-less {
height: 570px;
}
.iguana-less #iguanaCorePort,
.iguana-less #useBasiliskInstance {
display: none;
}

BIN
assets/mainWindow/img/fa-caret-down.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
assets/mainWindow/img/fa-caret-up.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
assets/mainWindow/img/fa-close.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
assets/mainWindow/img/fa-cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
assets/mainWindow/img/fa-cube.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
assets/mainWindow/img/fa-cubes.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
assets/mainWindow/img/fa-question.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

6
assets/mainWindow/js/init.js

@ -3,6 +3,12 @@ $(document).ready(function() {
var window = remote.getCurrentWindow();
var appConf = remote.getCurrentWindow().appConfig;
if (!appConf.experimentalFeatures) {
$('#normalStartBtn').hide();
$('.dropdown-menu').css('right', '34.8%');
$('#nativeOnlyBtnCarret').css('margin-right', '0');
}
$('#pulse').jRoll({
radius: 100,
animation: 'pulse'

301
assets/mainWindow/js/loading.js

@ -1,59 +1,284 @@
function closeMainWindow() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
let _configCopy;
window.createWindow('open');
window.hide();
function toggleDropdown() {
const _dropdown = $('.dropdown-menu');
if (_dropdown.hasClass('hide')) {
_dropdown.removeClass('hide');
} else {
_dropdown.addClass('hide');
}
}
function quitApp() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
function initSettingsForm() {
const remote = require('electron').remote;
let appConf = remote.getCurrentWindow().appConfig;
let appConfSchema = remote.getCurrentWindow().appConfigSchema;
_configCopy = Object.assign({}, appConf);
if (!appConf.experimentalFeatures) {
$('.agama-app-settings-window').addClass('iguana-less');
}
let _htmlOut = '<table class="settings-table">';
for (let key in appConf) {
if (appConfSchema[key] &&
appConfSchema[key].initDisplay) {
_htmlOut = `
${_htmlOut}
<tr id="${key}">
<td class="left">
${appConfSchema[key].displayName}`;
window.forseCloseApp();
if (appConfSchema[key].info) {
_htmlOut = `
${_htmlOut}
<div
class="settings-help"
title="${appConfSchema[key].info}">
<img src="../EasyDEX-GUI/assets/mainWindow/img/fa-question.png" />
</div>`;
}
if (appConfSchema[key].type === 'number') {
_htmlOut = `
${_htmlOut}
</td>
<td class="right">
<input
type="number"
id="${key}"
pattern="[0-9]*"
onKeyup="handleInput('${key}')"
value="${_configCopy[key]}" />
</td>
</tr>`;
} else if (appConfSchema[key].type === 'string' || appConfSchema[key].type === 'folder') {
_htmlOut = `
${_htmlOut}
</td>
<td class="right">
<input
type="text"
id="${key}"
onKeyup="handleInput('${key}')"
value="${_configCopy[key]}" />
</td>
</tr>`;
} else if (appConfSchema[key].type === 'boolean') {
_htmlOut = `${_htmlOut}
</td>
<td class="right">
<label
class="switch"
id="${key}"
onClick="settingsToggle(\'${key}\')">
${(appConf[key] ? '<input type="checkbox" class="cb" checked />' : '<input type="checkbox" class="cb" />')}
<div class="slider"></div>
</label>
</td>
</tr>`;
}
}
}
function normalStart() {
_htmlOut = `
${_htmlOut}
</table>`;
$('#agamaConfigBlock').html(_htmlOut);
}
function hideToastImmediate() {
$('#toast-container').addClass('hide');
}
function hideToast() {
setTimeout(function() {
$('#toast-container').addClass('hide');
}, 5000);
}
function showToast(type, message) {
$('#toast-container .toast').removeClass('toast-success').removeClass('toast-error');
$('#toast-container .toast').addClass(`toast-${type}`);
$('#toast-container .toast-message').html(message);
$('#toast-container').removeClass('hide');
hideToast();
}
function setDefaultAppSettings() {
const remote = require('electron').remote;
remote.getCurrentWindow().setDefaultAppSettings();
remote.getCurrentWindow().appConfig = remote.getCurrentWindow().defaultAppSettings;
initSettingsForm();
showToast('success', 'App settings are reset to default');
}
function testBins(binName) {
const remote = require('electron').remote;
remote.getCurrentWindow().testBins(binName).
then(function(res) {
$('#debugOut').html(JSON.stringify(res, null, '\t'));
});
}
function handleSaveSettings() {
if (_configCopy.dataDir &&
_configCopy.dataDir.length) {
const remote = require('electron').remote;
let appConf = remote.getCurrentWindow().appConfig;
appConf.iguanaLessMode = false;
// run iguana-less mode with no daemons startup
if (appConf && appConf.iguanaLessMode) {
// do something
} else { // run normal mode with 2 iguana instances started prior loading GUI
if (appConf && !appConf.manualIguanaStart) {
StartIguana();
remote.getCurrentWindow().testLocation(_configCopy.dataDir)
.then(function(res) {
$('#debugOut').html(res + ' | ' + _configCopy.dataDir);
if (res === -1) {
showToast('error', 'Komodo datadir path is invalid');
} else if (res === false) {
showToast('error', 'Komodo datadir path is not a directory');
} else {
// save settings
remote.getCurrentWindow().updateAppSettings(_configCopy);
remote.getCurrentWindow().appConfig = _configCopy;
showToast('success', 'Settings saved');
}
});
} else {
// save settings
const remote = require('electron').remote;
var portcheck;
remote.getCurrentWindow().updateAppSettings(_configCopy);
remote.getCurrentWindow().appConfig = _configCopy;
showToast('success', 'Settings saved');
}
}
function startcheck() {
portcheck = setInterval(function() {
Iguana_activehandle(appConf).then(function(result){
console.log(result);
function handleInput(key) {
const _value = $(`#${key}`).val();
_configCopy[key] = _value;
}
if (result !== 'error') {
stopcheck();
function settingsToggle(key) {
const _value = $(`#${key} .cb`).prop('checked');
_configCopy[key] = _value;
}
if (appConf && appConf.useBasiliskInstance) {
StartIguana_Cache();
}
function closeSettingsWindow() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
toggleDropdown();
window.destroyAppSettingsWindow();
}
function reloadSettingsWindow() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
$('#loading_status_text').text('Connecting to Basilisk Network...');
EDEX_DEXgetinfoAll(appConf.skipBasiliskNetworkCheck, appConf.minNotaries, appConf);
window.reloadSettingsWindow();
}
function openSettingsWindow() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
$('.dropdown-menu').addClass('hide');
window.createAppSettingsWindow();
}
function startKMDPassive() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
$('.dropdown-menu').addClass('hide');
disableModeButtons();
window.startKMDNative('KMD', true);
window.createWindow('open');
window.hide();
}
function closeMainWindow(isKmdOnly, isCustom) {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
$('.dropdown-menu').addClass('hide');
disableModeButtons();
if (!isCustom) {
window.startKMDNative(isKmdOnly ? 'KMD' : null);
setTimeout(function() {
window.createWindow('open');
window.hide();
}, 3000);
} else {
window.createWindow('open');
window.hide();
}
}
function quitApp() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
window.forseCloseApp();
}
function disableModeButtons() {
$('#nativeOnlyBtn').attr('disabled', true);
$('#normalStartBtn').attr('disabled', true);
$('#settingsBtn').attr('disabled', true);
$('#nativeOnlyBtnCarret').attr('disabled', true);
}
function normalStart() {
const remote = require('electron').remote;
let appConf = remote.getCurrentWindow().appConfig;
appConf.iguanaLessMode = false;
$('.dropdown-menu').addClass('hide');
disableModeButtons();
// run iguana-less mode with no daemons startup
if (appConf &&
appConf.iguanaLessMode) {
// do something
} else { // run normal mode with 2 iguana instances started prior loading GUI
if (appConf &&
!appConf.manualIguanaStart) {
StartIguana();
}
var portcheck;
function startcheck() {
portcheck = setInterval(function() {
Iguana_activehandle(appConf).then(function(result){
console.log(result);
if (result !== 'error') {
stopcheck();
if (appConf && appConf.useBasiliskInstance) {
StartIguana_Cache();
}
})
}, 2000);
}
function stopcheck() {
clearInterval(portcheck);
}
$('#loading_status_text').text('Connecting to Basilisk Network...');
EDEX_DEXgetinfoAll(appConf.skipBasiliskNetworkCheck, appConf.minNotaries, appConf);
}
})
}, 2000);
}
startcheck();
function stopcheck() {
clearInterval(portcheck);
}
startcheck();
}
}
function IguanaAJAX(url, ajax_data, timeout) {
return $.ajax({

3
react/change.log

@ -8,7 +8,7 @@ UI:
- minor placeholders fixes
- hide address dropdown if wallet has only one address
- komodod crash report modal
- values rounding (up to 6 decimals)
- values clipping
- add coin multi ui reflow fix
- reset app setting to default
- manual balance / transactions list refresh
@ -26,6 +26,7 @@ UI:
- coin daemon port check on addcoin
- updated application settings
- komodo datadir
- windows bins path fix
v0.2.0.21a-beta
--------------

63
react/src/actions/actionCreators.js

@ -6,7 +6,6 @@ import {
GET_ACTIVE_COINS,
DASHBOARD_ACTIVE_ADDRESS,
VIEW_CACHE_DATA,
DASHBOARD_DISPLAY_NOTARIES_MODAL,
DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR,
DASHBOARD_ACTIVE_SECTION,
DASHBOARD_ACTIVE_TXINFO_MODAL,
@ -30,13 +29,10 @@ import {
DISPLAY_CLAIM_INTEREST_MODAL,
START_INTERVAL,
STOP_INTERVAL,
GET_PIN_LIST
GET_PIN_LIST,
DASHBOARD_SYNC_ONLY_UPDATE,
DISPLAY_IMPORT_KEY_MODAL,
} from './storeType';
import {
logGuiHttp,
getAgamaLog,
guiLogState
} from './actions/log';
export * from './actions/nativeSyncInfo';
export * from './actions/basiliskCache';
@ -53,7 +49,6 @@ export * from './actions/sendFullBasilisk';
export * from './actions/settings';
export * from './actions/syncOnly';
export * from './actions/iguanaInstance';
export * from './actions/notary';
export * from './actions/edexBalance';
export * from './actions/addCoin';
export * from './actions/addressBalance';
@ -72,6 +67,7 @@ export * from './actions/cli';
export * from './actions/update';
export * from './actions/jumblr';
export * from './actions/interest';
export * from './actions/nativeDashboardUpdate';
export function changeActiveAddress(address) {
return {
@ -93,13 +89,6 @@ export function toggleViewCacheModal(display) {
}
}
export function displayNotariesModal(display) {
return {
type: DASHBOARD_DISPLAY_NOTARIES_MODAL,
display,
}
}
export function changeMainBasiliskAddress(address) {
return {
type: DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR,
@ -122,34 +111,6 @@ export function toggleDashboardTxInfoModal(display, txIndex) {
}
}
export function basiliskConnectionState(display, json) {
return {
type: BASILISK_CONNECTION,
basiliskConnection: display,
progress: json,
}
}
export function basiliskRefreshState(display, json) {
return {
type: BASILISK_REFRESH,
basiliskRefresh: display,
progress: json,
}
}
export function basiliskRefresh(display) {
return dispatch => {
dispatch(basiliskRefreshState(display));
}
}
export function basiliskConnection(display) {
return dispatch => {
dispatch(basiliskConnectionState(display));
}
}
export function syncingNativeModeState(display, json) {
return {
type: SYNCING_NATIVE_MODE,
@ -388,6 +349,20 @@ export function toggleClaimInterestModal(display) {
export function getPinList(pinList) {
return {
type: GET_PIN_LIST,
pinList: pinList
pinList: pinList,
}
}
export function skipFullDashboardUpdate(skip) {
return {
type: DASHBOARD_SYNC_ONLY_UPDATE,
skipFullDashboardUpdate: skip,
}
}
export function displayImportKeyModal(display) {
return {
type: DISPLAY_IMPORT_KEY_MODAL,
displayImportKeyModal: display,
}
}

34
react/src/actions/actions/addCoin.js

@ -7,10 +7,6 @@ import {
startIguanaInstance,
iguanaWalletPassphraseState,
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import {
startCurrencyAssetChain,
startAssetChain,
@ -96,31 +92,12 @@ export function addCoin(coin, mode, syncOnly, port, startupParams) {
export function iguanaAddCoin(coin, mode, acData, port) {
function _iguanaAddCoin(dispatch) {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaAddCoin',
type: 'post',
url: `http://127.0.0.1:${(port ? port : Config.iguanaCorePort)}`,
payload: acData,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${(port ? port : Config.iguanaCorePort)}`, {
method: 'POST',
body: JSON.stringify(acData),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
translate('TOASTR.FAILED_TO_ADDCOIN'),
@ -131,13 +108,6 @@ export function iguanaAddCoin(coin, mode, acData, port) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
addCoinResult(
coin,
@ -287,7 +257,7 @@ export function shepherdHerd(coin, mode, path, startupParams) {
console.warn(acData);
dispatch(
triggerToaster(
`Error starting ${coin} daemon. Port ${acData.rpc} is already taken!`,
`Error starting ${coin} daemon. Port ${acData.rpc} is already taken!`, // translate
translate('TOASTR.SERVICE_NOTIFICATION'),
'error',
false
@ -372,7 +342,7 @@ export function iguanaActiveHandleBypass() {
.then(response => response.json())
.then(
json => dispatch(
iguanaWalletPassphraseState(json, dispatch)
iguanaWalletPassphraseState(json, dispatch, true)
)
)
}

113
react/src/actions/actions/addressBalance.js

@ -5,10 +5,6 @@ import {
getPassthruAgent,
iguanaHashHex
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
function getKMDAddressesNativeState(json) {
@ -105,18 +101,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
};
}
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDAddressesNative',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -139,13 +123,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative',
@ -156,13 +133,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(Config.cli.default && mode === 'native' ? json.result : json);
})
}
@ -307,16 +277,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
hex: hashHexJson,
};
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDAddressesNative+ZBalance',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
@ -349,13 +309,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative+ZBalance',
@ -369,13 +322,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
if (json &&
json.error) {
resolve(0);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: json,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative+ZBalance',
@ -394,13 +340,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
amount: json,
type: 'private',
};
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
}
});
});
@ -448,31 +387,12 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
if (json[coin][currentAddress].refresh) {
calcBalance(result, json[coin][currentAddress].refresh.data, dispatch, mode);
} else {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDAddressesNative+Balance',
type: 'post',
url: `http://127.0.0.1:${(Config.useBasiliskInstance && mode === 'basilisk' ? Config.iguanaCorePort + 1 : Config.iguanaCorePort)}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${(Config.useBasiliskInstance && mode === 'basilisk' ? Config.iguanaCorePort + 1 : Config.iguanaCorePort)}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative+Balance',
@ -483,13 +403,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
})
.then(response => response.json())
.then(function(json) {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
updatedCache.basilisk[coin][currentAddress].refresh = {
data: json,
status: 'done',
@ -506,18 +419,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
}
})
} else {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDAddressesNative+Balance',
type: 'post',
url: `http://127.0.0.1:${(Config.useBasiliskInstance && mode === 'basilisk' ? Config.iguanaCorePort + 1 : Config.iguanaCorePort)}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -547,13 +448,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative+Balance',
@ -568,13 +462,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
mode === 'native') {
json = json.result;
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
calcBalance(
result,
json,

30
react/src/actions/actions/atomic.js

@ -1,38 +1,15 @@
import { ATOMIC } from '../storeType';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function atomic(payload) {
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'atomic',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
payload.method,
@ -43,13 +20,6 @@ export function atomic(payload) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(atomicState(json));
});
}

4
react/src/actions/actions/basiliskCache.js

@ -1,9 +1,5 @@
import { DASHBOARD_ACTIVE_COIN_GET_CACHE } from '../storeType';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
// TODO: rewrite cache API to use POST

56
react/src/actions/actions/basiliskProcessAddress.js

@ -1,9 +1,5 @@
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function checkAddressBasilisk(coin, address) {
@ -16,31 +12,12 @@ export function checkAddressBasilisk(coin, address) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'checkAddressBasilisk',
type: 'post',
url: `http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'checkAddressBasilisk',
@ -51,13 +28,6 @@ export function checkAddressBasilisk(coin, address) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(checkAddressBasiliskHandle(json));
})
}
@ -102,31 +72,12 @@ export function validateAddressBasilisk(coin, address) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'validateAddressBasilisk',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'validateAddressBasilisk',
@ -137,13 +88,6 @@ export function validateAddressBasilisk(coin, address) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(validateAddressBasiliskHandle(json));
})
}

4
react/src/actions/actions/basiliskTxHistory.js

@ -2,10 +2,6 @@ import {
triggerToaster,
getNativeTxHistoryState
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getBasiliskTransactionsList(coin, address) {

4
react/src/actions/actions/cli.js

@ -1,9 +1,5 @@
import { triggerToaster } from '../actionCreators';
import { CLI } from '../storeType';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function shepherdCliPromise(mode, chain, cmd) {

4
react/src/actions/actions/coinList.js

@ -1,8 +1,4 @@
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function shepherdGetCoinList() {

30
react/src/actions/actions/createWallet.js

@ -1,9 +1,5 @@
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
function createNewWalletState(json) {
@ -41,31 +37,12 @@ export function createNewWallet(_passphrase) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'createNewWallet',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'createNewWallet',
@ -76,13 +53,6 @@ export function createNewWallet(_passphrase) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(createNewWalletState(json));
})
}

30
react/src/actions/actions/dexCoins.js

@ -2,10 +2,6 @@ import {
triggerToaster,
dashboardCoinsState
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
// TODO: find out why it errors on slow systems
@ -17,18 +13,6 @@ export function getDexCoins() {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getDexCoins',
type: 'post',
url: Config.iguanaLessMode ? `http://127.0.0.1:${Config.agamaPort}/shepherd/InstantDEX/allcoins` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: _payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(_payload),
@ -49,13 +33,6 @@ export function getDexCoins() {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'Error getDexCoins',
@ -66,13 +43,6 @@ export function getDexCoins() {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(dashboardCoinsState(json));
});
}

49
react/src/actions/actions/edexBalance.js

@ -1,9 +1,5 @@
import { DASHBOARD_ACTIVE_COIN_BALANCE } from '../storeType';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function iguanaEdexBalance(coin) {
@ -16,31 +12,12 @@ export function iguanaEdexBalance(coin) {
return dispatch => {
if (coin) {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaEdexBalance',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: _payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(_payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'Error iguanaEdexBalance',
@ -73,31 +50,12 @@ export function getDexBalance(coin, mode, addr) {
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getDexBalance',
type: 'post',
url: `http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getDexBalance',
@ -109,13 +67,6 @@ export function getDexBalance(coin, mode, addr) {
.then(response => response.json())
.then(json => {
console.log(json);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
})
resolve(index);

30
react/src/actions/actions/edexGetTx.js

@ -1,8 +1,4 @@
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function edexGetTransaction(data, dispatch) {
@ -16,31 +12,12 @@ export function edexGetTransaction(data, dispatch) {
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'edexGetTransaction',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'edexGetTransaction',
@ -51,13 +28,6 @@ export function edexGetTransaction(data, dispatch) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(json);
})
});

30
react/src/actions/actions/fullTxHistory.js

@ -2,10 +2,6 @@ import {
triggerToaster,
getNativeTxHistoryState
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getFullTransactionsList(coin) {
@ -21,31 +17,12 @@ export function getFullTransactionsList(coin) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getFullTransactionsList',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getFullTransactionsList',
@ -56,13 +33,6 @@ export function getFullTransactionsList(coin) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getNativeTxHistoryState(json));
})
}

30
react/src/actions/actions/getAddrByAccount.js

@ -1,8 +1,4 @@
import { ACTIVE_COIN_GET_ADDRESSES } from '../storeType';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getAddressesByAccountState(json, coin, mode) {
@ -36,31 +32,12 @@ export function getAddressesByAccount(coin, mode) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getAddressesByAccount',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(updateErrosStack('activeHandle'));
dispatch(
triggerToaster(
@ -72,13 +49,6 @@ export function getAddressesByAccount(coin, mode) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
getAddressesByAccountState(
json,

30
react/src/actions/actions/iguanaHelpers.js

@ -1,7 +1,3 @@
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
import { checkAC } from '../../components/addcoin/payload';
@ -29,31 +25,12 @@ export function iguanaHashHex(data, dispatch) {
if (Config.cli.default) {
resolve(true);
} else {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaHashHex',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'iguanaHashHex',
@ -64,13 +41,6 @@ export function iguanaHashHex(data, dispatch) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(json.hex);
})
}

20
react/src/actions/actions/iguanaInstance.js

@ -1,8 +1,4 @@
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function restartIguanaInstance(pmid) {
@ -28,22 +24,6 @@ export function restartIguanaInstance(pmid) {
});
}
export function restartBasiliskInstance() {
return dispatch => {
getIguanaInstancesList()
.then(function(json) {
for (let port in json.result) {
if (json.result[port].mode === 'basilisk') {
restartIguanaInstance(json.result[port].pmid)
.then(function(json) {
console.log('restartBasiliskInstance', json);
});
}
}
});
}
}
export function startIguanaInstance(mode, coin) {
return new Promise((resolve, reject) => {
fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/forks`, {

4
react/src/actions/actions/interest.js

@ -1,10 +1,6 @@
import {
triggerToaster
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getListUnspent(coin) {

8
react/src/actions/actions/jumblr.js

@ -2,10 +2,6 @@ import {
triggerToaster,
getNewKMDAddresses
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
function getNewAddress(coin) { // TODO: remove(?)
@ -121,7 +117,7 @@ function dumpPrivkey(coin, key) {
});
}
export function importPrivkey(coin, key) {
export function importPrivkey(coin, key, rescan = false) {
return new Promise((resolve, reject) => {
const payload = {
mode: null,
@ -130,7 +126,7 @@ export function importPrivkey(coin, key) {
params: [
key,
'',
false
rescan
],
};

61
react/src/actions/actions/log.js

@ -1,61 +0,0 @@
import { LOG_GUI_HTTP } from '../storeType';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
export function logGuiHttp(payload) {
return dispatch => {
dispatch(guiLogState(payload));
// disabled for now
/*return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/guilog`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
dispatch(triggerToaster('logGuiHttp', 'Error', 'error'));
})
.then(response => response.json())*/
}
}
export function getAgamaLog(type) {
return dispatch => {
return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/getlog?type=${type}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getAgamaLog',
'Error',
'error'
)
);
})
.then(response => response.json())
}
}
export function guiLogState(logData) {
return {
type: LOG_GUI_HTTP,
timestamp: logData.timestamp,
log: {
timestamp: logData.timestamp,
function: logData.function,
httpMethod: logData.type,
url: logData.url,
payload: logData.payload,
status: logData.status,
response: logData.response,
}
}
}

30
react/src/actions/actions/logout.js

@ -4,10 +4,6 @@ import {
} from '../storeType';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
function logoutState(json) {
sessionStorage.removeItem('IguanaActiveAccount');
@ -38,31 +34,12 @@ function walletLock() {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'walletLock',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'walletLock',
@ -73,13 +50,6 @@ function walletLock() {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(logoutState(json));
dispatch(logoutResetAppState());
})

30
react/src/actions/actions/nativeBalance.js

@ -4,10 +4,6 @@ import {
getPassthruAgent
} from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function getKMDBalanceTotal(coin) {
let payload;
@ -41,18 +37,6 @@ export function getKMDBalanceTotal(coin) {
}
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDBalanceTotal',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -74,13 +58,6 @@ export function getKMDBalanceTotal(coin) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDBalanceTotal',
@ -91,13 +68,6 @@ export function getKMDBalanceTotal(coin) {
})
.then(response => response.json())
.then(function(json) { // TODO: figure out why komodod spits out "parse error"
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
if (json &&
!json.error) {
dispatch(getNativeBalancesState(json));

86
react/src/actions/actions/nativeDashboardUpdate.js

@ -0,0 +1,86 @@
import {
triggerToaster,
} from '../actionCreators';
import Config from '../../config';
import { DASHBOARD_UPDATE } from '../storeType';
export function getDashboardUpdate(coin, activeCoinProps) {
return dispatch => {
const _fetchConfig = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ coin: coin }),
};
return fetch(
`http://127.0.0.1:${Config.agamaPort}/shepherd/native/dashboard/update`,
_fetchConfig
)
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getDashboardUpdate',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
dispatch(getDashboardUpdateState(json, coin));
// dirty hack to trigger dashboard render
if (!activeCoinProps.balance &&
!activeCoinProps.addresses) {
setTimeout(() => {
dispatch(getDashboardUpdateState(json, coin));
}, 100);
}
})
}
}
export function getDashboardUpdateState(json, coin, fakeResponse) {
// rescan or similar resource heavy process
if (fakeResponse ||
((json.result['getinfo'].error && json.result['getinfo'].error === 'daemon is busy') &&
(json.result['z_getoperationstatus'].error && json.result['z_getoperationstatus'].error === 'daemon is busy') &&
(json.result['listtransactions'].error && json.result['listtransactions'].error === 'daemon is busy') &&
(json.result['listtransactions'].error && json.result['listtransactions'].error === 'daemon is busy'))) {
return {
type: DASHBOARD_UPDATE,
progress: null,
opids: null,
txhistory: null,
balance: null,
addresses: null,
coin: coin,
rescanInProgress: true,
};
} else {
let _listtransactions = json.result['listtransactions'];
if (_listtransactions &&
_listtransactions.error) {
_listtransactions = null;
} else if (_listtransactions && _listtransactions.result && _listtransactions.result.length) {
_listtransactions = _listtransactions.result;
} else if (!_listtransactions || (!_listtransactions.result || !_listtransactions.result.length)) {
_listtransactions = 'no data';
}
return {
type: DASHBOARD_UPDATE,
progress: json.result['getinfo'].result,
opids: json.result['z_getoperationstatus'].result,
txhistory: _listtransactions,
balance: json.result['z_gettotalbalance'].result,
addresses: json.result['addresses'],
coin: coin,
rescanInProgress: false,
};
}
}

30
react/src/actions/actions/nativeNewAddress.js

@ -5,10 +5,6 @@ import {
getKMDAddressesNative
} from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function getNewKMDAddresses(coin, pubpriv, mode) {
let payload;
@ -34,18 +30,6 @@ export function getNewKMDAddresses(coin, pubpriv, mode) {
}
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getNewKMDAddresses',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -73,13 +57,6 @@ export function getNewKMDAddresses(coin, pubpriv, mode) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getNewKMDAddresses',
@ -93,13 +70,6 @@ export function getNewKMDAddresses(coin, pubpriv, mode) {
if (Config.cli.default) {
json = json.result;
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
triggerToaster(
json.result ? json.result : json,

61
react/src/actions/actions/nativeSend.js

@ -5,10 +5,6 @@ import {
getPassthruAgent,
iguanaHashHex
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function sendNativeTx(coin, _payload) {
@ -47,18 +43,6 @@ export function sendNativeTx(coin, _payload) {
};
}
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'sendNativeTx',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -110,13 +94,6 @@ export function sendNativeTx(coin, _payload) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'sendNativeTx',
@ -130,14 +107,6 @@ export function sendNativeTx(coin, _payload) {
return _response;
})
.then(function(json) {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
if (json.indexOf('"code":') > -1) {
const _message = json.substring(
`${json.indexOf('"message":"')}11`,
@ -230,18 +199,6 @@ export function getKMDOPID(opid, coin) {
};
}
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDOPID',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -251,7 +208,7 @@ export function getKMDOPID(opid, coin) {
payload = {
mode: null,
chain: coin,
cmd: 'z_getoperationstatus'
cmd: 'z_getoperationstatus',
};
_fetchConfig = {
@ -269,13 +226,6 @@ export function getKMDOPID(opid, coin) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDOPID',
@ -289,13 +239,6 @@ export function getKMDOPID(opid, coin) {
if (Config.cli.default) {
json = json.result;
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getKMDOPIDState(json));
})
})
@ -342,6 +285,6 @@ export function sendToAddressPromise(coin, address, amount) {
.then(response => response.json())
.then(json => {
resolve(json);
})
});
});
}

235
react/src/actions/actions/nativeSyncInfo.js

@ -1,98 +1,105 @@
import { SYNCING_NATIVE_MODE } from '../storeType';
import {
SYNCING_NATIVE_MODE,
DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE
} from '../storeType';
import {
triggerToaster,
getPassthruAgent,
getDebugLog,
toggleCoindDownModal
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getSyncInfoNativeKMD(skipDebug, json) {
const coin = 'KMD';
// https://www.kmd.host/
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getSyncInfoNativeKMD',
type: 'post',
url: Config.iguanaLessMode ? 'http://kmd.explorer.supernet.org/api/status?q=getInfo' : `http://127.0.0.1:${Config.iguanaCorePort}/api/dex/getinfo?userpass=tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}&symbol=${coin}`,
payload: '',
status: 'pending',
}));
}
export function nativeGetinfoFailureState() {
return {
type: DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE,
}
}
// TODO: use debug.log instead
export function getSyncInfoNativeKMD(skipDebug, json, skipRemote) {
let _json = json;
if (skipRemote) {
return dispatch => {
dispatch(getSyncInfoNativeState(Config.iguanaLessMode ? json.info : json ));
return fetch(
Config.iguanaLessMode ? 'http://kmd.explorer.supernet.org/api/status?q=getInfo' : `http://127.0.0.1:${Config.iguanaCorePort}/api/dex/getinfo?userpass=tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}&symbol=${coin}`, {
method: 'GET',
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
/*dispatch(
triggerToaster(
'getSyncInfoNativeKMD',
'Error',
'error'
)
);*/
console.warn('remote kmd node fetch failed', true);
dispatch(getSyncInfoNativeState({ remoteKMDNode: null }));
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: Config.iguanaLessMode ? json.info : json,
}));
}
dispatch(getSyncInfoNativeState({ remoteKMDNode: Config.iguanaLessMode ? json.info : json }));
})
.then(function() {
if (!skipDebug) {
dispatch(getDebugLog('komodo', 1));
}
})
}
} else {
const coin = 'KMD';
// https://www.kmd.host/
return dispatch => {
return fetch(
Config.iguanaLessMode ? 'https://kmd.explorer.supernet.org/api/status?q=getInfo' : `http://127.0.0.1:${Config.iguanaCorePort}/api/dex/getinfo?userpass=tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}&symbol=${coin}`, {
method: 'GET',
})
.catch(function(error) {
console.log(error);
/*dispatch(
triggerToaster(
'getSyncInfoNativeKMD',
'Error',
'error'
)
);*/
console.warn('remote kmd node fetch failed', true);
_json = _json.error;
_json['remoteKMDNode'] = null;
dispatch(getSyncInfoNativeState(_json));
})
.then(response => response.json())
.then(json => {
_json = _json.error;
_json['remoteKMDNode'] = json.info;
dispatch(getSyncInfoNativeState(_json));
})
.then(function() {
if (!skipDebug) {
dispatch(getDebugLog('komodo', 1));
}
})
}
}
}
function getSyncInfoNativeState(json, coin, skipDebug) {
if (coin === 'KMD' &&
json &&
json.error &&
json.error.message.indexOf('Activating best') === -1) {
return getSyncInfoNativeKMD(skipDebug, json);
function getSyncInfoNativeState(json, coin, skipDebug, skipRemote) {
/*if (!json.remoteKMDNode) {
json = { error: { code: -28, message: 'Activating best chain...' } };
}*/
if (json.remoteKMDNode) {
return {
type: SYNCING_NATIVE_MODE,
progress: json,
}
} else {
if (json &&
if (coin === 'KMD' &&
json &&
json.error &&
Config.cli.default) {
return {
type: SYNCING_NATIVE_MODE,
progress: json.error,
}
json.error.message.indexOf('Activating best') > -1) {
return getSyncInfoNativeKMD(skipDebug, json, skipRemote);
} else {
return {
type: SYNCING_NATIVE_MODE,
progress: json.result ? json.result : json,
if (json &&
json.error &&
Config.cli.default) {
return {
type: SYNCING_NATIVE_MODE,
progress: json.error,
}
} else {
return {
type: SYNCING_NATIVE_MODE,
progress: json.result ? json.result : json,
}
}
}
}
}
export function getSyncInfoNative(coin, skipDebug) {
export function getSyncInfoNative(coin, skipDebug, skipRemote, suppressErrors) {
let payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: getPassthruAgent(coin),
@ -111,17 +118,6 @@ export function getSyncInfoNative(coin, skipDebug) {
}
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getSyncInfo',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -143,20 +139,15 @@ export function getSyncInfoNative(coin, skipDebug) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
if (!suppressErrors) { // rescan case
dispatch(
triggerToaster(
'getSyncInfo',
'Error',
'error'
)
);
}
dispatch(
triggerToaster(
'getSyncInfo',
'Error',
'error'
)
);
})
.then(function(response) {
const _response = response.text().then(function(text) { return text; });
@ -164,6 +155,11 @@ export function getSyncInfoNative(coin, skipDebug) {
})
.then(json => {
if (json === 'Work queue depth exceeded') {
if (coin === 'KMD') {
dispatch(getDebugLog('komodo', 100));
} else {
dispatch(getDebugLog('komodo', 100, coin));
}
dispatch(
getSyncInfoNativeState(
{
@ -172,20 +168,39 @@ export function getSyncInfoNative(coin, skipDebug) {
id: null
},
coin,
skipDebug
true,
skipRemote
)
);
} else {
if (!json &&
Config.cli.default) {
dispatch(
triggerToaster(
'Komodod is down',
'Critical Error',
'error',
true
)
);
let _kmdMainPassiveMode;
try {
_kmdMainPassiveMode = window.require('electron').remote.getCurrentWindow().kmdMainPassiveMode;
} catch (e) {}
if (!_kmdMainPassiveMode) {
dispatch(nativeGetinfoFailureState());
/* dispatch(
triggerToaster(
'Komodod is down',
'Critical Error',
'error',
true
)
); */
} else {
dispatch(
triggerToaster(
'Please make sure to run komodod manually',
'Connection error',
'warning',
true
)
);
}
if (coin === 'KMD') {
dispatch(getDebugLog('komodo', 50));
@ -206,18 +221,12 @@ export function getSyncInfoNative(coin, skipDebug) {
}
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
getSyncInfoNativeState(
json,
coin,
skipDebug
skipDebug,
skipRemote
)
);
}

30
react/src/actions/actions/nativeTxHistory.js

@ -4,10 +4,6 @@ import {
getNativeTxHistoryState
} from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function getNativeTxHistory(coin) {
let payload;
@ -32,18 +28,6 @@ export function getNativeTxHistory(coin) {
}
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getNativeTxHistory',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -71,13 +55,6 @@ export function getNativeTxHistory(coin) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getNativeTxHistory',
@ -88,13 +65,6 @@ export function getNativeTxHistory(coin) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getNativeTxHistoryState(json));
})
}

223
react/src/actions/actions/notary.js

@ -1,223 +0,0 @@
import {
DASHBOARD_CONNECT_NOTARIES,
DASHBOARD_GET_NOTARIES_LIST
} from '../storeType';
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
function initNotaryNodesConSequence(nodes) {
return dispatch => {
Promise.all(nodes.map((node, index) => {
const payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: 'dex',
method: 'getinfo',
symbol: node,
timeout: 10000,
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: `initNotaryNodesConSequence+${node}`,
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${(Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort)}/api/dex/getinfo?userpass=${('tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'))}&symbol=${node}`, {
method: 'GET',
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
`getInfoDexNode+${node}`,
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
updateNotaryNodeConState(
json,
nodes.length,
index,
node
)
);
})
});
}));
}
}
function updateNotaryNodeConState(json, totalNodes, currentNodeIndex, currentNodeName) {
if (currentNodeIndex === totalNodes - 1) {
return dispatch => {
dispatch(basiliskConnectionState(false));
};
} else {
if (json &&
json.error === 'less than required responses') {
return {
type: DASHBOARD_CONNECT_NOTARIES,
total: totalNodes - 1,
current: currentNodeIndex,
name: currentNodeName,
failedNode: currentNodeName,
}
} else {
return {
type: DASHBOARD_CONNECT_NOTARIES,
total: totalNodes - 1,
current: currentNodeIndex,
name: currentNodeName,
}
}
}
}
function connectAllNotaryNodes(json, dispatch) {
if (json &&
json.length) {
dispatch(initNotaryNodesConSequence(json));
return {
type: DASHBOARD_CONNECT_NOTARIES,
total: json.length - 1,
current: 0,
name: json[0],
}
}
}
export function connectNotaries() {
const payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: 'dpow',
method: 'notarychains',
};
return dispatch => {
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'connectNotaries',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(
json => dispatch(
connectAllNotaryNodes(json, dispatch)
)
)
}
}
function getDexNotariesState(json) {
if (json.error === 'less than required responses') {
return dispatch => {
dispatch(
triggerToaster(
translate('TOASTR.LESS_RESPONSES_REQ'),
translate('TOASTR.BASILISK_NOTIFICATION'),
'error'
)
);
}
} else {
return {
type: DASHBOARD_GET_NOTARIES_LIST,
notaries: json,
}
}
}
export function getDexNotaries(coin) {
const payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: 'dex',
method: 'getnotaries',
symbol: coin,
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getDexNotaries',
type: 'post',
url: `http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getDexNotaries',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getDexNotariesState(json));
})
}
}

4
react/src/actions/actions/openAlias.js

@ -1,8 +1,4 @@
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
export function resolveOpenAliasAddress(email) {
const url = email.replace('@', '.');

126
react/src/actions/actions/pin.js

@ -4,9 +4,9 @@ import { iguanaWalletPassphrase } from "./walletAuth";
export function encryptPassphrase(passphrase, key, pubKey) {
const payload = {
'string': passphrase,
'key': key,
'pubkey': pubKey
string: passphrase,
key: key,
pubkey: pubKey,
};
return dispatch => {
@ -17,34 +17,33 @@ export function encryptPassphrase(passphrase, key, pubKey) {
},
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'encryptKey',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
console.log('encrypt result', json);
dispatch(
triggerToaster(
'passphrase successfully encrypted',
'Success',
'success'
)
);
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'encryptKey',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
dispatch(
triggerToaster(
'Passphrase successfully encrypted',
'Success',
'success'
)
);
})
}
}
export function loginWithPin(key, pubKey) {
const payload = {
'key': key,
'pubkey': pubKey
key: key,
pubkey: pubKey,
};
return dispatch => {
@ -55,21 +54,20 @@ export function loginWithPin(key, pubKey) {
},
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'decryptKey',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
console.log('decrypt result', json);
dispatch(iguanaWalletPassphrase(json.result));
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'decryptKey',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
dispatch(iguanaWalletPassphrase(json.result));
})
}
}
@ -81,30 +79,28 @@ export function loadPinList() {
'Content-Type': 'application/json',
}
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getPinList',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
console.log('getpinlist result', json);
dispatch(
triggerToaster(
'getPinList',
'Success',
'success'
)
);
dispatch(
getPinList(json.result)
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getPinList',
'Error',
'error'
)
})
);
})
.then(response => response.json())
.then(json => {
dispatch(
triggerToaster(
'getPinList',
'Success',
'success'
)
);
dispatch(
getPinList(json.result)
)
})
}
}

110
react/src/actions/actions/sendFullBasilisk.js

@ -5,10 +5,6 @@ import {
getDispatch
} from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function sendToAddress(coin, _payload) {
const payload = {
@ -24,31 +20,12 @@ export function sendToAddress(coin, _payload) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'sendToAddress',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'sendToAddress',
@ -59,13 +36,6 @@ export function sendToAddress(coin, _payload) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(sendToAddressState(json, dispatch));
})
}
@ -86,31 +56,12 @@ export function sendFromAddress(coin, _payload) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'sendFromAddress',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'sendFromAddress',
@ -121,13 +72,6 @@ export function sendFromAddress(coin, _payload) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(sendToAddressState(json, dispatch));
})
}
@ -151,31 +95,12 @@ export function iguanaUTXORawTX(data, dispatch) {
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaUTXORawTX',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch => dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'iguanaUTXORawTX',
@ -186,13 +111,6 @@ export function iguanaUTXORawTX(data, dispatch) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(json);
})
});
@ -208,31 +126,12 @@ export function dexSendRawTX(data, dispatch) {
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'dexSendRawTX',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch('http://127.0.0.1:' + Config.iguanaCorePort, {
fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'dexSendRawTX',
@ -247,13 +146,6 @@ export function dexSendRawTX(data, dispatch) {
return _response;
})
.then(function(json) {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(json);
})
});

86
react/src/actions/actions/settings.js

@ -8,10 +8,6 @@ import {
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
function getAppInfoState(json) {
return {
@ -56,7 +52,7 @@ function parseImportPrivKeyResponse(json, dispatch) {
return dispatch => {
dispatch(
triggerToaster(
transalte('API.ILLEGAL_PRIVKEY'),
translate('API.ILLEGAL_PRIVKEY'),
translate('TOASTR.SETTINGS_NOTIFICATION'),
'error'
)
@ -67,7 +63,7 @@ function parseImportPrivKeyResponse(json, dispatch) {
return dispatch => {
dispatch(
triggerToaster(
transalte('API.PRIVKEY_IN_WALLET'),
translate('API.PRIVKEY_IN_WALLET'),
translate('TOASTR.SETTINGS_NOTIFICATION'),
'warning'
)
@ -100,31 +96,12 @@ export function importPrivKey(wifKey) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'importPrivKey',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'importPrivKey',
@ -135,13 +112,6 @@ export function importPrivKey(wifKey) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
parseImportPrivKeyResponse(
json,
@ -209,31 +179,12 @@ export function getPeersList(coin) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getPeersList',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getPeersList',
@ -244,13 +195,6 @@ export function getPeersList(coin) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getPeersListState(json, dispatch));
})
}
@ -331,31 +275,12 @@ export function addPeerNode(coin, ip) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'addPeerNode',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'addPeerNode',
@ -366,13 +291,6 @@ export function addPeerNode(coin, ip) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(addPeerNodeState(json, dispatch));
})
}

30
react/src/actions/actions/syncInfo.js

@ -1,10 +1,6 @@
import { SYNCING_FULL_MODE } from '../storeType';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
// TODO: add custom json parser
function getSyncInfoState(json) {
@ -30,31 +26,12 @@ export function getSyncInfo(coin) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getSyncInfo',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getSyncInfo',
@ -69,13 +46,6 @@ export function getSyncInfo(coin) {
return _response;
})
.then(function(json) {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
if (json.indexOf('coin is busy processing') === -1) {
dispatch(getSyncInfoState(json, dispatch));
}

4
react/src/actions/actions/syncOnly.js

@ -5,10 +5,6 @@ import {
import { translate } from '../../translate/translate';
import Config from '../../config';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
export function toggleSyncOnlyModal(display) {
return {

4
react/src/actions/actions/sysInfo.js

@ -1,9 +1,5 @@
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function shepherdGetSysInfo() {
return dispatch => {

4
react/src/actions/actions/update.js

@ -1,9 +1,5 @@
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function checkForUpdateUIPromise() {
return new Promise((resolve, reject) => {

127
react/src/actions/actions/walletAuth.js

@ -9,10 +9,6 @@ import {
getMainAddressState,
updateErrosStack
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
export function encryptWallet(_passphrase, cb, coin) {
const payload = {
@ -23,31 +19,12 @@ export function encryptWallet(_passphrase, cb, coin) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'encryptWallet',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'encryptWallet',
@ -59,13 +36,6 @@ export function encryptWallet(_passphrase, cb, coin) {
.then(dispatch(walletPassphrase(_passphrase)))
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
cb.call(
this,
@ -87,31 +57,12 @@ export function walletPassphrase(_passphrase) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'walletpassphrase',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'walletPassphrase',
@ -121,13 +72,6 @@ export function walletPassphrase(_passphrase) {
);
})
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
})
}
}
@ -143,31 +87,12 @@ export function iguanaWalletPassphrase(_passphrase) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaWalletPassphrase',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: _payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(_payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'Error iguanaWalletPassphrase',
@ -178,13 +103,6 @@ export function iguanaWalletPassphrase(_passphrase) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(iguanaWalletPassphraseState(json, dispatch));
});
}
@ -198,18 +116,6 @@ export function iguanaActiveHandle(getMainAddress) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaActiveHandle',
type: 'post',
url: Config.iguanaLessMode ? `http://127.0.0.1:${Config.agamaPort}/shepherd/SuperNET/activehandle` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: _payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(_payload),
@ -230,13 +136,6 @@ export function iguanaActiveHandle(getMainAddress) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(updateErrosStack('activeHandle'));
dispatch(
triggerToaster(
@ -248,13 +147,6 @@ export function iguanaActiveHandle(getMainAddress) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
if (!Config.iguanaLessMode &&
sessionStorage.getItem('IguanaActiveAccount') &&
JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey === json.pubkey &&
@ -266,15 +158,18 @@ export function iguanaActiveHandle(getMainAddress) {
}
}
export function iguanaWalletPassphraseState(json, dispatch) {
export function iguanaWalletPassphraseState(json, dispatch, skipToastr) {
sessionStorage.setItem('IguanaActiveAccount', JSON.stringify(json));
dispatch(
triggerToaster(
translate('TOASTR.LOGIN_SUCCESSFULL'),
translate('TOASTR.ACCOUNT_NOTIFICATION'),
'success'
)
);
if (!skipToastr) {
dispatch(
triggerToaster(
translate('TOASTR.LOGIN_SUCCESSFULL'),
translate('TOASTR.ACCOUNT_NOTIFICATION'),
'success'
)
);
}
dispatch(getMainAddressState(json));
dispatch(iguanaActiveHandleState(json));

14
react/src/actions/storeType.js

@ -20,8 +20,8 @@ export const BASILISK_CONNECTION = 'BASILISK_CONNECTION';
export const SYNCING_FULL_MODE = 'SYNCING_FULL_MODE';
export const SYNCING_NATIVE_MODE = 'SYNCING_NATIVE_MODE';
export const ACTIVE_COIN_GET_ADDRESSES = 'ACTIVE_COIN_GET_ADDRESSES';
export const START_INTERVAL= 'START_INTERVAL';
export const STOP_INTERVAL= 'STOP_INTERVAL';
export const START_INTERVAL = 'START_INTERVAL';
export const STOP_INTERVAL = 'STOP_INTERVAL';
export const DASHBOARD_ACTIVE_SECTION = 'DASHBOARD_ACTIVE_SECTION';
export const DASHBOARD_ACTIVE_TXINFO_MODAL = 'DASHBOARD_ACTIVE_TXINFO_MODAL';
export const DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE = 'DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE';
@ -30,9 +30,9 @@ export const DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS = 'DASHBOARD_ACTIVE_COIN_NATIVE_
export const DASHBOARD_ACTIVE_COIN_SENDTO = 'DASHBOARD_ACTIVE_COIN_SENDTO';
export const DASHBOARD_ACTIVE_COIN_GET_CACHE = 'DASHBOARD_ACTIVE_COIN_GET_CACHE';
export const DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR = 'DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR';
export const DASHBOARD_GET_NOTARIES_LIST = 'DASHBOARD_GET_NOTARIES_LIST';
export const DASHBOARD_DISPLAY_NOTARIES_MODAL = 'DASHBOARD_DISPLAY_NOTARIES_MODAL';
export const DASHBOARD_CONNECT_NOTARIES = 'DASHBOARD_CONNECT_NOTARIES';
export const DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE = 'DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE';
export const DASHBOARD_UPDATE = 'DASHBOARD_UPDATE';
export const DASHBOARD_SYNC_ONLY_UPDATE = 'DASHBOARD_SYNC_ONLY_UPDATE';
export const VIEW_CACHE_DATA = 'VIEW_CACHE_DATA';
export const SYNC_ONLY_MODAL_TOGGLE = 'SYNC_ONLY_MODAL_TOGGLE';
export const SYNC_ONLY_DATA = 'SYNC_ONLY_DATA';
@ -41,10 +41,10 @@ export const SAVE_APP_CONFIG = 'SAVE_APP_CONFIG';
export const SERVICE_ERROR = 'SERVICE_ERROR';
export const DASHBOARD_ACTIVE_ADDRESS = 'DASHBOARD_ACTIVE_ADDRESS';
export const LOAD_APP_INFO = 'LOAD_APP_INFO';
export const LOG_GUI_HTTP = 'LOG_GUI_HTTP';
export const CLI = 'CLI';
export const LOGOUT = 'LOGOUT';
export const DISPLAY_COIND_DOWN_MODAL = 'DISPLAY_COIND_DOWN_MODAL';
export const DISPLAY_LOGIN_SETTINGS_MODAL = 'DISPLAY_LOGIN_SETTINGS_MODAL';
export const DISPLAY_CLAIM_INTEREST_MODAL = 'DISPLAY_CLAIM_INTEREST_MODAL';
export const GET_PIN_LIST = 'GET_PIN_LIST';
export const GET_PIN_LIST = 'GET_PIN_LIST';
export const DISPLAY_IMPORT_KEY_MODAL = 'DISPLAY_IMPORT_KEY_MODAL';

29
react/src/components/addcoin/addcoin.js

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../translate/translate';
import Config from '../../config';
import {
@ -16,8 +17,8 @@ import CoinSelectorsRender from './coin-selectors.render';
import AddCoinRender from './addcoin.render';
class AddCoin extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
nativeOnly: Config.iguanaLessMode,
coins: [],
@ -42,6 +43,7 @@ class AddCoin extends React.Component {
display: false,
actionsMenu: false,
modalClassName: 'hide',
isExperimentalOn: false,
};
this.existingCoins = null;
this.activateCoin = this.activateCoin.bind(this);
@ -112,6 +114,16 @@ class AddCoin extends React.Component {
componentWillMount() {
this.addNewItem();
let appConfig;
try {
appConfig = window.require('electron').remote.getCurrentWindow().appConfig;
} catch (e) {}
this.setState({
isExperimentalOn: appConfig.experimentalFeatures,
});
}
componentWillReceiveProps(props) {
@ -355,4 +367,15 @@ class AddCoin extends React.Component {
}
}
export default AddCoin;
const mapStateToProps = (state) => {
return {
Main: state.Main,
ActiveCoin: {
coin: state.ActiveCoin.coin,
},
AddCoin: state.AddCoin,
};
};
export default connect(mapStateToProps)(AddCoin);

59
react/src/components/addcoin/addcoin.scss

@ -1,5 +1,43 @@
.add-coin-modal {
color: #757575;
.modal-body {
max-height: 590px;
overflow-y: auto;
}
.multi {
.col-sm-8 {
width: 30%;
}
.col-sm-12 {
&.text-center {
width: 60%;
padding: 0;
.col-lg-4 {
width: 25%;
margin-right: 8%;
padding: 0;
.input{
&.to-labelauty+label {
max-width: 136px;
}
}
}
.col-lg-4 {
&:last-child {
margin-right: 0;
}
}
.col-sm-1 {
width: 44px;
padding: 0;
}
}
}
}
}
.vertical-margin-20 {
@ -24,4 +62,25 @@
margin: 0;
}
}
}
.btn-add-coin-item,
.btn-add-coin-item-options,
.btn-save-coin-selection,
.btn-load-coin-selection {
position: absolute;
right: 32px;
z-index: 50;
}
.btn-add-coin-item {
right: 60px;
}
.btn-add-coin-item-options {
padding: 6px;
}
.btn-save-coin-selection {
top: 60px;
}
.btn-load-coin-selection {
top: 95px;
}

46
react/src/components/addcoin/addcoinOptionsAC.js

@ -3,25 +3,37 @@ import { translate } from '../../translate/translate';
class AddCoinOptionsAC extends React.Component {
render() {
const _assetChains = [
'bet',
'bots',
'ceal',
'coqui',
'crypto',
'hodl',
'dex',
'jumblr',
'kv',
'mgw',
//'mvp',
'pangea',
'revs',
'shark',
'supernet',
'wlc',
];
let _items = [];
for (let i = 0; i < _assetChains.length; i++) {
_items.push(
<option
key={ _assetChains[i] }
value={ `${_assetChains[i].toUpperCase()}|basilisk|native` }>{ translate(`ASSETCHAINS.${_assetChains[i].toUpperCase()}`) }</option>
);
}
return (
<optgroup label={ translate('ADD_COIN.ASSETCHAINS') }>
<option value="BET|basilisk|native">BET (BET)</option>
<option value="BOTS|basilisk|native">BOTS (BOTS)</option>
<option value="CEAL|basilisk|native">CEAL NET (CEAL)</option>
<option value="COQUI|basilisk|native">COQUI (COQUI)</option>
<option value="CRYPTO|basilisk|native">CRYPTO (CRYPTO)</option>
<option value="HODL|basilisk|native">HODL (HODL)</option>
<option value="DEX|basilisk|native">InstantDEX (DEX)</option>
<option value="JUMBLR|basilisk|native">JUMBLR (JUMBLR)</option>
<option value="KV|basilisk|native">KV (KV)</option>
<option value="MGW|basilisk|native">MultiGateway (MGW)</option>
<option value="MVP|basilisk|native" className="hide">MVP Lineup (MVP)</option>
<option value="PANGEA|basilisk|native">PANGEA (PANGEA)</option>
<option value="REVS|basilisk|native">REVS (REVS)</option>
<option value="SHARK|basilisk|native">SHARK (SHARK)</option>
<option value="MESH|basilisk|native">SpaceMesh (MESH)</option>
<option value="SUPERNET|basilisk|native">SUPERNET (SUPERNET)</option>
<option value="WLC|basilisk|native">WIRELESS (WIRELESS)</option>
{ _items }
</optgroup>
);
}

77
react/src/components/addcoin/addcoinOptionsACFiat.js

@ -3,40 +3,53 @@ import { translate } from '../../translate/translate';
class AddCoinOptionsACFiat extends React.Component {
render() {
const _fiat = [
'aud',
'brl',
'gbp',
'bgn',
'cad',
'hrk',
'czk',
'cny',
'dkk',
'eur',
'hkd',
'huf',
'inr',
'idr',
'ils',
'jpy',
'krw',
'myr',
'mxn',
'nzd',
'nok',
'php',
'pln',
'ron',
'rub',
'sgd',
'zar',
'sek',
'chf',
'thb',
'try',
'usd'
];
let _items = [];
for (let i = 0; i < _fiat.length; i++) {
_items.push(
<option
key={ _fiat[i] }
value={ `${_fiat[i].toUpperCase()}|basilisk|native` }>{ translate(`FIAT_CURRENCIES.${_fiat[i].toUpperCase()}`) }</option>
);
}
return (
<optgroup label={ translate('ADD_COIN.FIAT_CURRENCIES') }>
<option value="AUD|basilisk|native">Australian Dollar (AUD)</option>
<option value="BRL|basilisk|native">Brazilian Real (BRL)</option>
<option value="GBP|basilisk|native">British Pound (GBP)</option>
<option value="BGN|basilisk|native">Bulgarian Lev (BGN)</option>
<option value="CAD|basilisk|native">Canadian Dollar (CAD)</option>
<option value="HRK|basilisk|native">Croatian Kuna (HRK)</option>
<option value="CZK|basilisk|native">Czech Koruna (CZK)</option>
<option value="CNY|basilisk|native">Chinese Yuan (CNY)</option>
<option value="DKK|basilisk|native">Danish Krone (DKK)</option>
<option value="EUR|basilisk|native">Euro (EUR)</option>
<option value="HKD|basilisk|native">Hong Kong Dollar (HKD)</option>
<option value="HUF|basilisk|native">Hungarian Forint (HUF)</option>
<option value="INR|basilisk|native">Indian Rupee (INR)</option>
<option value="IDR|basilisk|native">Indonesian Rupiah (IDR)</option>
<option value="ILS|basilisk|native">Israeli Shekel (ILS)</option>
<option value="JPY|basilisk|native">Japanese Yen (JPY)</option>
<option value="KRW|basilisk|native">Korean Won (KRW)</option>
<option value="MYR|basilisk|native">Malaysian Ringgit (MYR)</option>
<option value="MXN|basilisk|native">Mexican peso (MXN)</option>
<option value="NZD|basilisk|native">New Zealand Dollar (NZD)</option>
<option value="NOK|basilisk|native">Norwegian Krone (NOK)</option>
<option value="PHP|basilisk|native">Philippine Peso (PHP)</option>
<option value="PLN|basilisk|native">Polish Zloty (PLN)</option>
<option value="RON|basilisk|native">Romanian Leu (RON)</option>
<option value="RUB|basilisk|native">Russian Ruble (RUB)</option>
<option value="SGD|basilisk|native">Singapore Dollar (SGD)</option>
<option value="ZAR|basilisk|native">South African Rand (ZAR)</option>
<option value="SEK|basilisk|native">Swedish Krona (SEK)</option>
<option value="CHF|basilisk|native">Swiss Franc (CHF)</option>
<option value="THB|basilisk|native">Thai Baht (THB)</option>
<option value="TRY|basilisk|native">Turkish Lira (TRY)</option>
<option value="USD|basilisk|native">US Dollar (USD)</option>
{ _items }
</optgroup>
);
}

56
react/src/components/addcoin/addcoinOptionsCrypto.js

@ -1,63 +1,81 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../translate/translate';
import Config from '../../config';
class AddCoinOptionsCrypto extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
nativeOnly: Config.iguanaLessMode,
}
}
render() {
const isWindows = this.props.appSettings && this.props.appSettings.appInfo && this.props.appSettings.appInfo.sysInfo && this.props.appSettings.appInfo.sysInfo.platform === 'win32';
// const isWindows = this.props.appSettings && this.props.appSettings.appInfo && this.props.appSettings.appInfo.sysInfo && this.props.appSettings.appInfo.sysInfo.platform === 'win32';
let appConfig;
try {
appConfig = window.require('electron').remote.getCurrentWindow().appConfig;
} catch (e) {}
//<option value="ANC|full">AnonCoin (ANC)</option>
//<option value="MZC|full">MazaCoin (MZC)</option>
//<option value="SYS|full">SysCoin (SYS)</option>
return (
<optgroup label={ translate('ADD_COIN.CRYPTO_CURRENCIES') }>
<option
value="ANC|full"
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>AnonCoin (ANC)</option>
<option
value="BTCD|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>BitcoinDark (BTCD)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>BitcoinDark (BTCD)</option>
<option
value="BTC|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Bitcoin (BTC)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Bitcoin (BTC)</option>
<option
value="BTM|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Bitmark (BTM)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Bitmark (BTM)</option>
<option
value="CARB|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Carboncoin (CARB)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Carboncoin (CARB)</option>
<option
value="DGB|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Digibyte (DGB)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Digibyte (DGB)</option>
<option
value="DOGE|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Dogecoin (DOGE)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Dogecoin (DOGE)</option>
<option
value="FRK|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Franko (FRK)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Franko (FRK)</option>
<option
value="GAME|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Gamecredits (GAME)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Gamecredits (GAME)</option>
<option value="KMD|basilisk|native">Komodo (KMD)</option>
<option
value="MZC|full"
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>MazaCoin (MZC)</option>
<option
value="LTC|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Litecoin (LTC)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Litecoin (LTC)</option>
<option
value="SYS|full"
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>SysCoin (SYS)</option>
<option
value="UNO|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Unobtanium (UNO)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Unobtanium (UNO)</option>
<option
value="ZEC|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Zcash (ZEC)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Zcash (ZEC)</option>
<option
value="ZET|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Zetacoin (ZET)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Zetacoin (ZET)</option>
</optgroup>
);
}
}
export default AddCoinOptionsCrypto;
const mapStateToProps = (state) => {
return {
appSettings: state.appSettings,
};
};
export default connect(mapStateToProps)(AddCoinOptionsCrypto);

8
react/src/components/addcoin/coin-selectors.render.js

@ -5,7 +5,8 @@ import AddCoinOptionsAC from '../addcoin/addcoinOptionsAC';
import AddCoinOptionsACFiat from '../addcoin/addcoinOptionsACFiat';
const CoinSelectorsRender = function(item, coin, i) {
const isWindows = this.props.Settings && this.props.Settings.appInfo && this.props.Settings.appInfo.sysInfo && this.props.Settings.appInfo.sysInfo.platform === 'win32';
// const isWindows = this.props.Settings && this.props.Settings.appInfo && this.props.Settings.appInfo.sysInfo && this.props.Settings.appInfo.sysInfo.platform === 'win32';
const hideFullModeBtn = item && item.selectedCoin && item.selectedCoin.indexOf('|full') === -1 || !this.state.isExperimentalOn ? true : false;
return (
<div
@ -54,7 +55,7 @@ const CoinSelectorsRender = function(item, coin, i) {
</button>
</div>
<div className="col-sm-11 text-center add-coin-modes">
<div className={ this.state.nativeOnly || isWindows ? 'hide' : 'form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login' }>
<div className={ this.state.nativeOnly || hideFullModeBtn ? 'hide' : 'form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login' }>
<input
type="radio"
className="to-labelauty labelauty"
@ -169,7 +170,7 @@ const CoinSelectorsRender = function(item, coin, i) {
</select>
</div>
</div>
<div className={ item.mode === '1' || item.mode === 1 ? 'col-sm-12' : 'hide' }>
<div className={ (item.mode === '1' || item.mode === 1) && this.state.isExperimentalOn ? 'col-sm-12' : 'hide' }>
<div className="toggle-box padding-top-3 padding-bottom-10">
<span className="pointer">
<label className="switch">
@ -191,4 +192,5 @@ const CoinSelectorsRender = function(item, coin, i) {
</div>
)
};
export default CoinSelectorsRender;

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

@ -688,6 +688,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) {
'seedipaddr': '78.47.196.146'
};
// TODO: move netmagic to node
const acConfig = {
'SUPERNET': {
'name': 'SUPERNET',
@ -790,7 +791,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) {
'supply': 72000000,
'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {'coin':'COQUI','conf':'COQUI.conf','path':confpath,'RELAY':-1,'VALIDATE':1,'startpend':4,'endpend':4,'maxpeers':8,'newcoin':'COQUI','name':'COQUI','netmagic':'4cbd5ef4','p2p':assetChainPorts.COQUI - 1,'rpc':assetChainPorts.COQUI}) : {},
'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,'RELAY':mode,'VALIDATE':mode,'startpend':tmpPendValue,'endpend':tmpPendValue,'maxpeers':8,'newcoin':'COQUI','name':'COQUI','netmagic':'4cbd5ef4','p2p':assetChainPorts.COQUI - 1,'rpc':assetChainPorts.COQUI})
}
},
};
if (mode === '-1') {

1
react/src/components/app/app.js

@ -15,7 +15,6 @@ function mapStateToProps(state) {
Settings: state.Settings,
Interval: state.Interval,
SyncOnly: state.SyncOnly,
Errors: state.Errors,
};
}

14
react/src/components/dashboard/atomic/atomic.js

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import { atomic } from '../../../actions/actionCreators';
import Store from '../../../store';
@ -10,8 +11,8 @@ import AtomicRender from './atomic.render';
2) validation
*/
class Atomic extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
output: null,
api: null,
@ -497,5 +498,12 @@ class Atomic extends React.Component {
return AtomicRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
Atomic: {
response: state.Atomic.response,
},
};
};
export default Atomic;
export default connect(mapStateToProps)(Atomic);

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

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import ReactDOM from 'react-dom';
import Store from '../../../store';
import {
@ -16,13 +17,14 @@ import {
} from './claimInterestModal.render';
class ClaimInterestModal extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
open: false,
isLoading: true,
transactionsList: [],
showZeroInterest: true,
totalInterest: 0,
};
this.claimInterestTableRender = this.claimInterestTableRender.bind(this);
this.toggleZeroInterest = this.toggleZeroInterest.bind(this);
@ -36,6 +38,7 @@ class ClaimInterestModal extends React.Component {
loadListUnspent() {
let _transactionsList = [];
let _totalInterest = 0;
getListUnspent(this.props.ActiveCoin.coin)
.then((json) => {
@ -51,11 +54,13 @@ class ClaimInterestModal extends React.Component {
interest: json[i].interest,
txid: json[i].txid,
});
_totalInterest += Number(json[i].interest);
if (i === json.length - 1) {
this.setState({
transactionsList: _transactionsList,
isLoading: false,
totalInterest: _totalInterest,
});
}
});
@ -79,7 +84,7 @@ class ClaimInterestModal extends React.Component {
} else if (json.result && json.result.length && json.result.length === 64) {
Store.dispatch(
triggerToaster(
`translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P1') ${this.state.transactionsList[0].address}. translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P2')`,
`${translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P1')} ${this.state.transactionsList[0].address}. ${translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P2')}`,
translate('TOASTR.WALLET_NOTIFICATION'),
'success',
false
@ -134,4 +139,17 @@ class ClaimInterestModal extends React.Component {
}
}
export default ClaimInterestModal;
const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
balance: state.ActiveCoin.balance,
activeSection: state.ActiveCoin.activeSection,
},
Dashboard: {
displayClaimInterestModal: state.Dashboard.displayClaimInterestModal,
},
};
};
export default connect(mapStateToProps)(ClaimInterestModal);

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

@ -39,29 +39,36 @@ export const _ClaimInterestTableRender = function() {
return (
<span>
<div className="padding-bottom-20">
<strong>{ translate('CLAIM_INTEREST.REQ_P1') }:</strong> { translate('CLAIM_INTEREST.REQ_P2') } <strong>10 KMD</strong>
<p>
<strong>{ translate('CLAIM_INTEREST.REQ_P1') }:</strong> { translate('CLAIM_INTEREST.REQ_P2') } <strong>10 KMD</strong>
</p>
<p>
<strong>{ translate('CLAIM_INTEREST.TIP') }:</strong> { translate('CLAIM_INTEREST.TIP_DESC') }
</p>
</div>
<div className="text-left padding-top-10 padding-bottom-10">
<label className="switch">
<input
type="checkbox"
checked={ this.state.showZeroInterest } />
{ this.state.totalInterest > 0 &&
<div className="text-left padding-top-10 padding-bottom-10">
<label className="switch">
<input
type="checkbox"
checked={ this.state.showZeroInterest } />
<div
className="slider"
onClick={ this.toggleZeroInterest }></div>
</label>
<div
className="slider"
onClick={ this.toggleZeroInterest }></div>
</label>
<div
className="toggle-label margin-right-15 pointer"
onClick={ this.toggleZeroInterest }>
Show zero interest
className="toggle-label margin-right-15 pointer"
onClick={ this.toggleZeroInterest }>
Show zero interest
</div>
<button
type="button"
className="btn btn-success waves-effect waves-light claim-btn"
onClick={ () => this.claimInterest() }>
<i className="icon fa-dollar"></i> { translate('CLAIM_INTEREST.CLAIM_INTEREST', `${this.state.totalInterest} KMD `) }
</button>
</div>
</div>
<button
type="button"
className="btn btn-success waves-effect waves-light claim-btn"
onClick={ () => this.claimInterest() }>
<i className="icon fa-dollar"></i> { translate('CLAIM_INTEREST.CLAIM_INTEREST') }
</button>
}
<div className="table-scroll">
<table className="table table-hover dataTable table-striped">
<thead>
@ -69,7 +76,7 @@ export const _ClaimInterestTableRender = function() {
<th></th>
<th>{ translate('INDEX.ADDRESS') }</th>
<th>{ translate('INDEX.AMOUNT') }</th>
<th>{ translate('INDEX.Address') }</th>
<th>{ translate('INDEX.INTEREST') }</th>
<th>Locktime</th>
</tr>
</thead>
@ -81,7 +88,7 @@ export const _ClaimInterestTableRender = function() {
<th></th>
<th>{ translate('INDEX.ADDRESS') }</th>
<th>{ translate('INDEX.AMOUNT') }</th>
<th>{ translate('INDEX.Address') }</th>
<th>{ translate('INDEX.INTEREST') }</th>
<th>Locktime</th>
</tr>
</tfoot>
@ -104,7 +111,7 @@ export const ClaimInterestModalRender = function() {
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">{ translate('INDEX.CLAIM_INTEREST') }</h4>
<h4 className="modal-title white text-left">{ translate('CLAIM_INTEREST.CLAIM_INTEREST', ' ') }</h4>
</div>
<div className="modal-body">
<i

47
react/src/components/dashboard/claimInterestModal/claimInterestModal.scss

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

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

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import {
getCoinTitle,
getModeInfo
@ -8,10 +9,8 @@ import CoinTileItem from './coinTileItem';
import CoinTileRender from './coinTile.render';
class CoinTile extends React.Component {
constructor(props) {
super(props);
this.state = {
};
constructor() {
super();
this.renderTiles = this.renderTiles.bind(this);
}
@ -21,11 +20,10 @@ class CoinTile extends React.Component {
'basilisk',
'full'
];
const allCoins = this.props.Main.coins;
const allCoins = this.props.allCoins;
let items = [];
if (this.props.Main &&
allCoins) {
if (allCoins) {
modes.map(function(mode) {
allCoins[mode].map(function(coin) {
const _coinMode = getModeInfo(mode);
@ -55,8 +53,7 @@ class CoinTile extends React.Component {
<CoinTileItem
key={ i }
i={ i }
item={ item }
{...this.props} />)
item={ item } />)
);
}
@ -64,5 +61,11 @@ class CoinTile extends React.Component {
return CoinTileRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
allCoins: state.Main.coins,
};
};
export default connect(mapStateToProps)(CoinTile);
export default CoinTile;

197
react/src/components/dashboard/coinTile/coinTileItem.js

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import {
dashboardChangeActiveCoin,
iguanaActiveHandle,
@ -17,7 +18,8 @@ import {
getNativeTxHistory,
getKMDBalanceTotal,
getSyncInfoNative,
getDebugLog
getDebugLog,
getDashboardUpdate
} from '../../../actions/actionCreators';
import Store from '../../../store';
import Config from '../../../config';
@ -30,82 +32,141 @@ const IGUNA_ACTIVE_HANDLE_TIMEOUT_KMD_NATIVE = 15000;
const NATIVE_MIN_SYNC_PERCENTAGE_THRESHOLD = 90;
class CoinTileItem extends React.Component {
constructor(props) {
super(props);
this.state = {
};
constructor() {
super();
}
// TODO: 1) cache native/full node data to file
// 2) limit amount of req per update e.g. list of addresses don't change too often
// 3) limit req in basilisk as much as possible incl. activehandle
dispatchCoinActions(coin, mode) {
if (mode === 'native') {
Store.dispatch(iguanaActiveHandle(true));
const _propsDashboard = this.props.Dashboard;
const syncPercentage = _propsDashboard && _propsDashboard.progress && (parseFloat(parseInt(_propsDashboard.progress.blocks, 10) * 100 / parseInt(this.props.Dashboard.progress.longestchain, 10)).toFixed(2)).replace('NaN', 0);
if (syncPercentage < 100 &&
!this.props.Dashboard.displayCoindDownModal) {
Store.dispatch(getDebugLog('komodo', 10));
}
if (!this.props.Dashboard.displayCoindDownModal &&
_propsDashboard.progress &&
_propsDashboard.progress.blocks &&
_propsDashboard.progress.longestchain &&
syncPercentage &&
(Config.iguanaLessMode || syncPercentage >= NATIVE_MIN_SYNC_PERCENTAGE_THRESHOLD)) {
Store.dispatch(getSyncInfoNative(coin, true));
Store.dispatch(getKMDBalanceTotal(coin));
Store.dispatch(getNativeTxHistory(coin));
Store.dispatch(getKMDAddressesNative(coin, mode));
Store.dispatch(getKMDOPID(null, coin));
} else {
Store.dispatch(getSyncInfoNative(coin));
componentWillMount() {
if (!this.props.ActiveCoin.coin) {
let _coinSelected = false;
let _mode;
let _coin;
let _coinMode = {};
const modes = [
'native',
'basilisk',
'full'
];
const allCoins = this.props.Main.coins;
if (allCoins) {
modes.map((mode) => {
allCoins[mode].map((coin) => {
if (!_coinSelected) {
_coinSelected = true;
_coin = coin;
_mode = mode;
}
_coinMode[coin] = mode;
});
if (_coinMode['KMD'] &&
_coinMode['KMD'] === 'native') {
_coin = 'KMD';
_mode = 'native';
}
});
setTimeout(() => {
this._dashboardChangeActiveCoin(_coin, _mode);
}, 100);
}
}
if (mode === 'full') {
Store.dispatch(iguanaActiveHandle(true));
Store.dispatch(getSyncInfo(coin));
Store.dispatch(iguanaEdexBalance(coin, mode));
Store.dispatch(getAddressesByAccount(coin, mode));
Store.dispatch(getFullTransactionsList(coin));
}
if (mode === 'basilisk') {
const useAddress = this.props.ActiveCoin.mainBasiliskAddress ? this.props.ActiveCoin.mainBasiliskAddress : this.props.Dashboard.activeHandle[coin];
}
Store.dispatch(iguanaActiveHandle(true));
dispatchCoinActions(coin, mode) {
if (this.props.Dashboard &&
this.props.Dashboard.activeSection === 'wallets') {
if (mode === 'native') {
Store.dispatch(iguanaActiveHandle(true));
const _propsDashboard = this.props.ActiveCoin;
const syncPercentage = _propsDashboard && _propsDashboard.progress && (parseFloat(parseInt(_propsDashboard.progress.blocks, 10) * 100 / parseInt(_propsDashboard.progress.longestchain, 10)).toFixed(2)).replace('NaN', 0);
Store.dispatch(
getKMDAddressesNative(
coin,
mode,
useAddress
)
);
if ((syncPercentage < 100 &&
!this.props.Dashboard.displayCoindDownModal) ||
this.props.ActiveCoin.rescanInProgress) {
if (coin === 'KMD') {
Store.dispatch(getDebugLog('komodo', 50));
} else {
Store.dispatch(getDebugLog('komodo', 50, coin));
}
}
Store.dispatch(
getShepherdCache(
JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey,
coin
)
);
if (!this.props.Dashboard.displayCoindDownModal &&
_propsDashboard.progress &&
_propsDashboard.progress.blocks &&
_propsDashboard.progress.longestchain &&
syncPercentage &&
(Config.iguanaLessMode || syncPercentage >= NATIVE_MIN_SYNC_PERCENTAGE_THRESHOLD)) {
Store.dispatch(
getSyncInfoNative(
coin,
true,
this.props.Dashboard.skipFullDashboardUpdate,
this.props.ActiveCoin.rescanInProgress
)
);
if (this.props &&
this.props.Dashboard &&
this.props.Dashboard.activeHandle &&
this.props.Dashboard.activeHandle[coin]) {
if (!this.props.ActiveCoin.addresses) {
Store.dispatch(getAddressesByAccount(coin, mode));
if (!this.props.Dashboard.skipFullDashboardUpdate) {
Store.dispatch(getDashboardUpdate(coin, _propsDashboard));
}
} else {
Store.dispatch(
getSyncInfoNative(
coin,
null,
this.props.Dashboard.skipFullDashboardUpdate,
this.props.ActiveCoin.rescanInProgress
)
);
}
}
if (mode === 'full') {
Store.dispatch(iguanaActiveHandle(true));
Store.dispatch(getSyncInfo(coin));
Store.dispatch(iguanaEdexBalance(coin, mode));
Store.dispatch(getAddressesByAccount(coin, mode));
Store.dispatch(getFullTransactionsList(coin));
}
if (mode === 'basilisk') {
const useAddress = this.props.ActiveCoin.mainBasiliskAddress ? this.props.ActiveCoin.mainBasiliskAddress : this.props.Dashboard.activeHandle[coin];
Store.dispatch(getBasiliskTransactionsList(coin, useAddress));
Store.dispatch(iguanaActiveHandle(true));
Store.dispatch(
getKMDAddressesNative(
coin,
mode,
useAddress
)
);
Store.dispatch(
getShepherdCache(
JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey,
coin
)
);
if (this.props &&
this.props.Dashboard &&
this.props.Dashboard.activeHandle &&
this.props.Dashboard.activeHandle[coin]) {
if (!this.props.ActiveCoin.addresses) {
Store.dispatch(getAddressesByAccount(coin, mode));
}
Store.dispatch(getBasiliskTransactionsList(coin, useAddress));
}
}
}
}
dashboardChangeActiveCoin(coin, mode) {
_dashboardChangeActiveCoin(coin, mode) {
if (coin !== this.props.ActiveCoin.coin) {
Store.dispatch(dashboardChangeActiveCoin(coin, mode));
setTimeout(() => {
@ -201,5 +262,21 @@ class CoinTileItem extends React.Component {
return CoinTileItemRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
addresses: state.ActiveCoin.addresses,
mainBasiliskAddress: state.ActiveCoin.mainBasiliskAddress,
progress: state.ActiveCoin.progress,
rescanInProgress: state.ActiveCoin.rescanInProgress,
},
Dashboard: state.Dashboard,
Interval: {
interval: state.Interval.interval,
},
Main: state.Main,
};
};
export default CoinTileItem;
export default connect(mapStateToProps)(CoinTileItem);

2
react/src/components/dashboard/coinTile/coinTileItem.render.js

@ -8,7 +8,7 @@ const CoinTileItemRender = function() {
<div className={ 'widget widget-shadow' + (this.props.ActiveCoin.coin === item.coin ? ' active' : '') }>
<div
className="widget-content text-center bg-white padding-20"
onClick={ () => this.dashboardChangeActiveCoin(item.coin, item.mode) }>
onClick={ () => this._dashboardChangeActiveCoin(item.coin, item.mode) }>
<a className="avatar margin-bottom-5">
<img
className="img-responsive"

51
react/src/components/dashboard/coindDownModal/coindDownModal.js

@ -1,15 +1,19 @@
import React from 'react';
import { connect } from 'react-redux';
import { toggleCoindDownModal } from '../../../actions/actionCreators';
import Store from '../../../store';
import CoindDownModalRender from './coindDownModal.render';
const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = 5;
class CoindDownModal extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
display: false,
debugLogCrash: null,
kmdMainPassiveMode: false,
};
this.dismiss = this.dismiss.bind(this);
}
@ -18,25 +22,30 @@ class CoindDownModal extends React.Component {
Store.dispatch(toggleCoindDownModal(false));
}
componentWillReceiveProps(props) {
const coindDownModalProps = props ? props.Dashboard : null;
componentWillMount() {
let _kmdMainPassiveMode;
try {
_kmdMainPassiveMode = window.require('electron').remote.getCurrentWindow().kmdMainPassiveMode;
} catch (e) {}
this.setState(Object.assign({}, this.state, {
kmdMainPassiveMode: _kmdMainPassiveMode,
}));
}
if (coindDownModalProps &&
coindDownModalProps.displayCoindDownModal !== this.state.display) {
componentWillReceiveProps(nextProps) {
if (this.props.displayCoindDownModal !== nextProps.displayCoindDownModal) {
this.setState(Object.assign({}, this.state, {
display: coindDownModalProps.displayCoindDownModal,
display: nextProps.displayCoindDownModal,
}));
setTimeout(() => {
this.setState(Object.assign({}, this.state, {
display: coindDownModalProps.displayCoindDownModal,
}));
}, 100);
}
}
render() {
if (this.state.display) {
if (this.state.display &&
!this.state.kmdMainPassiveMode &&
this.props.ActiveCoin.getinfoFetchFailures >= COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD) {
return CoindDownModalRender.call(this);
}
@ -44,4 +53,16 @@ class CoindDownModal extends React.Component {
}
}
export default CoindDownModal;
const mapStateToProps = (state) => {
return {
ActiveCoin: {
mode: state.ActiveCoin.mode,
coin: state.ActiveCoin.coin,
getinfoFetchFailures: state.ActiveCoin.getinfoFetchFailures,
},
displayCoindDownModal: state.Dashboard.displayCoindDownModal,
debugLog: state.Settings.debugLog,
};
};
export default connect(mapStateToProps)(CoindDownModal);

5
react/src/components/dashboard/coindDownModal/coindDownModal.render.js

@ -1,7 +1,7 @@
import React from 'react';
import { translate } from '../../../translate/translate';
const CoindDownModalRender = function () {
const CoindDownModalRender = function() {
return (
<div>
<div
@ -24,8 +24,9 @@ const CoindDownModalRender = function () {
<strong>Debug.log ({ translate('INDEX.LAST_50_LINES') })</strong>
<div className="form-group form-material floating">
<textarea
readOnly
className="form-control"
value={ this.props.Settings.debugLog }></textarea>
value={ this.props.debugLog || '' }></textarea>
</div>
<button
type="button"

24
react/src/components/dashboard/coindDownModal/coindDownModal.scss

@ -0,0 +1,24 @@
.coind-down-modal {
.modal-body {
height: 60vh;
> div {
height: 100%;
}
.form-group {
&.form-material {
&.floating {
height: 80%;
}
}
}
.page-content {
width: 90%;
height: 100%;
textarea {
height: 100%;
}
}
}
}

243
react/src/components/dashboard/importKeyModal/importKeyModal.js

@ -0,0 +1,243 @@
import React from 'react';
import { connect } from 'react-redux';
import ReactDOM from 'react-dom';
import Store from '../../../store';
import {
displayImportKeyModal,
importPrivkey,
triggerToaster,
copyCoinAddress,
getDebugLog,
getDashboardUpdateState
} from '../../../actions/actionCreators';
import { translate } from '../../../translate/translate';
import {
ImportKeyModalRender,
} from './importKeyModal.render';
// import gen komodo keys utils
import '../../../util/crypto/gen/array.map.js';
import '../../../util/crypto/gen/cryptojs.js';
import '../../../util/crypto/gen/cryptojs.sha256.js';
import '../../../util/crypto/gen/cryptojs.pbkdf2.js';
import '../../../util/crypto/gen/cryptojs.hmac.js';
import '../../../util/crypto/gen/cryptojs.aes.js';
import '../../../util/crypto/gen/cryptojs.blockmodes.js';
import '../../../util/crypto/gen/cryptojs.ripemd160.js';
import '../../../util/crypto/gen/securerandom.js';
import '../../../util/crypto/gen/ellipticcurve.js';
import '../../../util/crypto/gen/biginteger.js';
import '../../../util/crypto/gen/crypto-scrypt.js';
import { Bitcoin } from '../../../util/crypto/gen/bitcoin.js';
class ImportKeyModal extends React.Component {
constructor() {
super();
this.state = {
open: false,
wif: '',
wifkeysPassphrase: '',
passphraseWif: null,
passphraseAddress: null,
keyImportResult: null,
importWithRescan: false,
seedInputVisibility: false,
toggleSeedInputVisibility: false,
trimPassphraseTimer: null,
};
this.generateKeysFromPassphrase = this.generateKeysFromPassphrase.bind(this);
this.toggleImportWithRescan = this.toggleImportWithRescan.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this._copyCoinAddress = this._copyCoinAddress.bind(this);
this.showPassphraseAddress = this.showPassphraseAddress.bind(this);
this.importWifAddress = this.importWifAddress.bind(this);
this.updateInput = this.updateInput.bind(this);
this.importFromPassphrase = this.importFromPassphrase.bind(this);
this.importFromWif = this.importFromWif.bind(this);
}
_copyCoinAddress(address) {
Store.dispatch(copyCoinAddress(address));
}
updateInput(e) {
if (e.target.name === 'wifkeysPassphrase') {
// remove any empty chars from the start/end of the string
const newValue = e.target.value;
clearTimeout(this.state.trimPassphraseTimer);
const _trimPassphraseTimer = setTimeout(() => {
this.setState({
wifkeysPassphrase: newValue ? newValue.trim() : '', // hardcoded field name
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name]: newValue,
});
} else {
this.setState({
[e.target.name]: e.target.value,
});
}
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#wifkeysPassphraseTextarea').style.height = '1px';
document.querySelector('#wifkeysPassphraseTextarea').style.height = `${(15 + document.querySelector('#wifkeysPassphraseTextarea').scrollHeight)}px`;
}
}, 100);
}
toggleSeedInputVisibility() {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
});
}
showPassphraseAddress() {
const _address = this.generateKeysFromPassphrase();
if (_address) {
this.setState({
passphraseAddress: _address.address,
passphraseWif: _address.wif,
});
}
}
importFromPassphrase() {
const _address = this.generateKeysFromPassphrase();
if (_address) {
this.importWifAddress(_address.wif, true);
}
}
importFromWif() {
this.importWifAddress(this.state.wif, this.state.importWithRescan);
}
importWifAddress(wif, rescan) {
let _rescanInProgress = true;
if (rescan) {
setTimeout(() => {
if (_rescanInProgress) {
setTimeout(() => {
if (this.props.ActiveCoin.coin === 'KMD') {
Store.dispatch(getDebugLog('komodo', 100));
} else {
Store.dispatch(getDebugLog('komodo', 100, this.props.ActiveCoin.coin));
}
}, 2000);
Store.dispatch(getDashboardUpdateState(null, this.props.ActiveCoin.coin, true));
Store.dispatch(
triggerToaster(
'Address imported. Wallet rescan is in progress. Please wait until it is finished.',
translate('TOASTR.WALLET_NOTIFICATION'),
'info',
false
)
);
this.closeModal();
}
}, 2000);
}
importPrivkey(
this.props.ActiveCoin.coin,
wif,
rescan
).then((json) => {
_rescanInProgress = false;
if (!json.id &&
!json.result &&
!json.error) {
// console.warn('importPrivkey', json);
Store.dispatch(
triggerToaster(
rescan ? 'Wallet rescan finished' : 'Address imported',
translate('TOASTR.WALLET_NOTIFICATION'),
'success',
false
)
);
} else {
Store.dispatch(
triggerToaster(
json.error.message,
'Error',
'error'
)
);
}
});
}
generateKeysFromPassphrase() {
if (this.state.wifkeysPassphrase &&
this.state.wifkeysPassphrase.length) {
const bytes = Crypto.SHA256(this.state.wifkeysPassphrase, { asBytes: true });
// byte flipping to make it compat with iguana core
bytes[0] &= 248;
bytes[31] &= 127;
bytes[31] |= 64;
const btcKey = new Bitcoin.ECKey(bytes).setCompressed(true);
const kmdAddress = btcKey.getBitcoinAddress();
const wifAddress = btcKey.getBitcoinWalletImportFormat();
return {
address: kmdAddress,
wif: wifAddress,
};
} else {
Store.dispatch(
triggerToaster(
'Empty passphrase field',
'Error',
'error'
)
);
return null;
}
}
toggleImportWithRescan() {
this.setState({
importWithRescan: !this.state.importWithRescan,
});
}
closeModal() {
Store.dispatch(displayImportKeyModal(false));
}
render() {
return ImportKeyModalRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
balance: state.ActiveCoin.balance,
},
Dashboard: {
displayImportKeyModal: state.Dashboard.displayImportKeyModal,
},
};
};
export default connect(mapStateToProps)(ImportKeyModal);

136
react/src/components/dashboard/importKeyModal/importKeyModal.render.js

@ -0,0 +1,136 @@
import React from 'react';
import { translate } from '../../../translate/translate';
/*export const _ClaimInterestTableRender = function() {
};*/
export const ImportKeyModalRender = function() {
return (
<span>
<div className={ 'modal modal-import-key modal-3d-sign ' + (this.props.Dashboard.displayImportKeyModal ? 'show in' : 'fade hide') }>
<div className="modal-dialog modal-center modal-sm">
<div className="modal-content">
<div className="modal-header bg-orange-a400 wallet-send-header">
<button
type="button"
className="close white"
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">Import key</h4>
</div>
<div className="modal-body">
<div className="padding-bottom-40">
Two forms below allow you to import either <strong>Iguana Core / ICO</strong> passphrase (seed) or <strong>WIF (Wallet Import Format)</strong> key.
</div>
<div>
<strong>Passphrase / seed</strong>
<p className="margin-top-10">
<strong>Notice:</strong> importing a passphrase will trigger a full wallet rescan.&nbsp;
<span className={ this.props.ActiveCoin.coin === 'KMD' ? '' : 'hide' }>This process can take hours to rescan the whole blockchain.</span>
</p>
<form
className="wifkeys-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="password"
className={ !this.state.seedInputVisibility ? 'form-control' : 'hide' }
name="wifkeysPassphrase"
id="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase } />
<textarea
className={ this.state.seedInputVisibility ? 'form-control' : 'hide' }
id="wifkeysPassphraseTextarea"
name="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase }></textarea>
<i
className={ 'seed-toggle fa fa-eye' + (!this.state.seedInputVisibility ? '-slash' : '') }
onClick={ this.toggleSeedInputVisibility }></i>
<label
className="floating-label"
htmlFor="wifkeysPassphrase">{ translate('INDEX.PASSPHRASE') }</label>
</div>
<div className="text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-right-20"
onClick={ this.importFromPassphrase }>Import</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.showPassphraseAddress }>Show address and WIF</button>
</div>
</form>
{ this.state.passphraseAddress && this.state.passphraseWif &&
<div className="margin-top-60">
<p>
<strong>Address: </strong> { this.state.passphraseAddress }
<button
className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(this.state.passphraseAddress) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</p>
<p>
<strong>WIF: </strong> { this.state.passphraseWif }
<button
className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(this.state.passphraseWif) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</p>
</div>
}
</div>
<div className="line">or</div>
<div>
<strong>WIF (Wallet Import Format)</strong>
<div className="toggle-box padding-top-20">
<span className="pointer">
<label className="switch">
<input
type="checkbox"
checked={ this.state.importWithRescan } />
<div
className="slider"
onClick={ this.toggleImportWithRescan }></div>
</label>
<div
className="toggle-label"
onClick={ this.toggleImportWithRescan }>
Trigger rescan
<i
className="icon fa-question-circle settings-help"
title="Use this option if you want to trigger rescan after WIF is imported. If you have several addresses that you want to import add them one by one and toggle this option on the last address import."></i>
</div>
</span>
</div>
<div className="margin-top-20">
<label htmlFor="wif" className="bold">Wif key</label>
<input
type="text"
className="form-control"
name="wif"
onChange={ this.updateInput }
value={ this.state.wif } />
</div>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-top-10"
onClick={ this.importFromWif }>{ this.state.importWithRescan ? 'Import and rescan' : 'Import' }</button>
</div>
</div>
</div>
</div>
</div>
<div className={ 'modal-backdrop ' + (this.props.Dashboard.displayImportKeyModal ? 'show in' : 'fade hide') }></div>
</span>
);
};

33
react/src/components/dashboard/importKeyModal/importKeyModal.scss

@ -0,0 +1,33 @@
.modal-import-key {
.modal-dialog {
width: 70%;
max-height: 90vh;
overflow-y: auto;
overflow-x: hidden;
}
.line {
padding: 50px 0 40px 0;
text-transform: uppercase;
font-weight: bold;
}
.line:before {
content: '';
display: inline-block;
height: 1px;
width: 47%;
background: #ccc;
margin-right: 10px;
position: relative;
top: -4px;
}
.line:after {
content: '';
display: inline-block;
height: 1px;
width: 47%;
background: #ccc;
margin-left: 10px;
position: relative;
top: -4px;
}
}

29
react/src/components/dashboard/jumblr/jumblr.js

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import {
dashboardChangeActiveCoin,
@ -39,8 +40,8 @@ if (!window.jumblrPasshrase) { // gen jumblr passphrase
}
class Jumblr extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
activeTab: 0,
randomSeed: window.jumblrPasshrase,
@ -127,12 +128,6 @@ class Jumblr extends React.Component {
});
}
/*toggleAddressGenMod() {
this.setState({
jumblrDepositAddressPBased: !this.state.jumblrDepositAddressPBased,
});
}*/
generateJumblrSecretAddress() {
let _jumblrSecretAddress = [];
let _apiSuccessCount = 0;
@ -284,7 +279,9 @@ class Jumblr extends React.Component {
importPrivkey(this.props.ActiveCoin.coin, _genKeys.wif)
.then((json) => {
if (!json.id && !json.result && !json.error) {
if (!json.id &&
!json.result &&
!json.error) {
_jumblrSecretAddress.push(_genKeys);
this.setState(Object.assign({}, this.state, {
jumblrSecretAddressImport: _jumblrSecretAddress,
@ -343,7 +340,9 @@ class Jumblr extends React.Component {
importPrivkey(this.props.ActiveCoin.coin, _genKeys.wif)
.then((json) => {
if (!json.id && !json.result && !json.error) {
if (!json.id &&
!json.result &&
!json.error) {
// console.warn('importPrivkey', json);
setJumblrAddress(
this.props.ActiveCoin.coin,
@ -424,4 +423,12 @@ class Jumblr extends React.Component {
}
}
export default Jumblr;
const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
},
};
};
export default connect(mapStateToProps)(Jumblr);

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

@ -359,7 +359,6 @@ export const JumblrRender = function() {
<p>{ translate('JUMBLR.DEPOSIT_FORM_P1') }</p>
<p className="padding-bottom-20">{ translate('JUMBLR.DEPOSIT_FORM_P2') }</p>
<WalletsNativeSend
{...this.props}
renderFormOnly="true"
activeSection="send" />
</div>
@ -461,7 +460,6 @@ export const JumblrRender = function() {
</div>
<div className={ 'tab-pane' + (this.state.activeTab === 1 ? ' active' : '') }>
<ReceiveCoin
{...this.props.ActiveCoin}
activeSection="receive"
renderTableOnly="true" />
</div>

92
react/src/components/dashboard/jumblr/jumblr.scss

@ -0,0 +1,92 @@
.jumblr {
.alert-info {
width: 100%;
}
p {
width: calc(100% - 100px);
}
.breadcrumb {
padding: 8px 30px;
position: relative;
top: 0;
}
.img-responsive {
position: absolute;
top: -28px;
right: 18px;
.coin {
font-size: 30px;
position: relative;
left: -18px;
top: 4px;
}
.image {
width: 60px;
}
}
.header-easydex-section {
img {
max-width: inherit;
}
}
.copy-string-btn {
position: absolute;
right: 36px;
margin-top: -68px;
}
.btn-next {
position: absolute;
top: 60px;
right: 32px;
}
input.labelauty+label,
input.labelauty+label {
background: #d6d5d5;
color: #504e4e;
}
input.labelauty:checked+label {
color: #fff;
background-color: #3949ab;
}
input.labelauty + label:hover .labelauty-unchecked,
input.labelauty + label .labelauty-unchecked {
color: #504e4e;
}
.nofloat {
float: none;
display: inline-block;
padding-left: 0;
}
}
.jumblr-mode-selector {
.nav-tabs {
li {
cursor: pointer;
&.active {
> a {
cursor: pointer;
color: #fff;
background-color: #62a8ea;
border-color: transparent;
border-bottom-color: #62a8ea;
}
}
}
}
.panel-heading {
background: #f3f3f3;
cursor: pointer;
}
.panel-title {
color: #676767;
}
.jumblr-addresses-list {
.col-xs-3 {
padding: 0;
}
}
}

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

@ -1,7 +1,7 @@
import React from 'react';
import { translate } from '../../../translate/translate';
const LoginModalRender = function () {
const LoginModalRender = function() {
return (
<div>
<div

9
react/src/components/dashboard/loginSettingsModal/loginSettingsModal.js

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import { getCoinTitle } from '../../../util/coinHelper';
import { translate } from '../../../translate/translate';
import { toggleLoginSettingsModal } from '../../../actions/actionCreators';
@ -29,4 +30,10 @@ class LoginSettingsModal extends React.Component {
}
}
export default LoginSettingsModal;
const mapStateToProps = (state) => {
return {
Main: state.Main,
};
};
export default connect(mapStateToProps)(LoginSettingsModal);

3
react/src/components/dashboard/loginSettingsModal/loginSettingsModal.render.js

@ -6,13 +6,12 @@ import Settings from '../settings/settings';
export const LoginSettingsModalRender = function() {
return (
<div>
<div className="modal show login-settings-modal">
<div className="modal show login-settings-modal ff">
<div className="modal-dialog modal-center modal-lg">
<div className="modal-content">
<div className="modal-body modal-body-container">
{ this.props.section === 'settings' &&
<Settings
{...this.props}
disableWalletSpecificUI="true" />
}
{ this.props.section === 'about' &&

7
react/src/components/dashboard/loginSettingsModal/loginSettingsModal.scss

@ -0,0 +1,7 @@
.login-settings-modal {
form {
width: 100%;
margin: 0;
margin-top: 25px;
}
}

17
react/src/components/dashboard/main/dashboard.js

@ -1,9 +1,10 @@
import React from 'react';
import { connect } from 'react-redux';
import DashboardRender from './dashboard.render';
class Dashboard extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
};
this.renderDashboard = this.renderDashboard.bind(this);
@ -38,4 +39,14 @@ class Dashboard extends React.Component {
}
}
export default Dashboard;
const mapStateToProps = (state) => {
return {
Main: state.Main,
ActiveCoin: {
mode: state.ActiveCoin.mode,
},
Dashboard: state.Dashboard,
};
};
export default connect(mapStateToProps)(Dashboard);

36
react/src/components/dashboard/main/dashboard.render.js

@ -16,6 +16,7 @@ import About from '../about/about';
import WalletsNative from '../walletsNative/walletsNative';
import WalletsTxInfo from '../walletsTxInfo/walletsTxInfo';
import CoindDownModal from '../coindDownModal/coindDownModal';
import ImportKeyModal from '../importKeyModal/importKeyModal';
const DashboardRender = function() {
return (
@ -23,33 +24,36 @@ const DashboardRender = function() {
<div
className={ this.isSectionActive('wallets') ? 'page-main' : '' }
id="section-dashboard">
<Navbar {...this.props} />
<CoindDownModal {...this.props} />
<Navbar />
<CoindDownModal />
{ this.props.Dashboard.displayImportKeyModal &&
<ImportKeyModal />
}
<div className={ this.isSectionActive('wallets') ? 'show' : 'hide' }>
<CoinTile {...this.props} />
<WalletsNav {...this.props} />
{ !this.isNativeMode() && <WalletsProgress {...this.props} /> }
{ !this.isNativeMode() && <WalletsBalance {...this.props} />}
<SendCoin {...this.props} />
{ !this.isNativeMode() && <ReceiveCoin {...this.props.ActiveCoin} /> }
{ !this.isNativeMode() && <WalletsData {...this.props} /> }
<WalletsTxInfo {...this.props} />
<WalletsNative {...this.props} />
<CoinTile />
<WalletsNav />
{ !this.isNativeMode() && <WalletsProgress /> }
{ !this.isNativeMode() && <WalletsBalance />}
<SendCoin />
{ !this.isNativeMode() && <ReceiveCoin /> }
{ !this.isNativeMode() && <WalletsData /> }
<WalletsTxInfo />
<WalletsNative />
</div>
{ this.isSectionActive('edex') &&
<EDEX {...this.props} />
<EDEX />
}
{ this.isSectionActive('atomic') &&
<Atomic {...this.props} />
<Atomic />
}
{ this.isSectionActive('jumblr') &&
<Jumblr {...this.props} />
<Jumblr />
}
{ this.isSectionActive('settings') &&
<Settings {...this.props} />
<Settings disableWalletSpecificUI={false} />
}
{ this.isSectionActive('about') &&
<About {...this.props} />
<About />
}
</div>
</div>

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

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import {
dashboardChangeSection,
toggleAddcoinModal,
@ -6,6 +7,7 @@ import {
startInterval,
toggleSyncOnlyModal,
getSyncOnlyForks,
displayImportKeyModal,
logout,
} from '../../../actions/actionCreators';
import Store from '../../../store';
@ -15,11 +17,12 @@ import { checkAC } from '../../addcoin/payload';
import NavbarRender from './navbar.render';
class Navbar extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
openDropMenu: false,
nativeOnly: Config.iguanaLessMode,
isExperimentalOn: false,
};
this.openDropMenu = this.openDropMenu.bind(this);
this.logout = this.logout.bind(this);
@ -33,6 +36,16 @@ class Navbar extends React.Component {
this.handleClickOutside,
false
);
let appConfig;
try {
appConfig = window.require('electron').remote.getCurrentWindow().appConfig;
} catch (e) {}
this.setState({
isExperimentalOn: appConfig.experimentalFeatures,
});
}
componentWillUnmount() {
@ -55,6 +68,10 @@ class Navbar extends React.Component {
}
}
openImportKeyModal() {
Store.dispatch(displayImportKeyModal(true));
}
openDropMenu() {
this.setState(Object.assign({}, this.state, {
openDropMenu: !this.state.openDropMenu,
@ -115,4 +132,21 @@ class Navbar extends React.Component {
}
}
export default Navbar;
const mapStateToProps = (state) => {
return {
ActiveCoin: {
mode: state.ActiveCoin.mode,
coin: state.ActiveCoin.coin,
},
Dashboard: {
activeSection: state.Dashboard.activeSection,
},
Interval: {
interval: state.Interval.interval,
},
nativeOnly: Config.iguanaLessMode,
};
};
export default connect(mapStateToProps)(Navbar);

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

@ -57,13 +57,20 @@ const NavbarRender = function() {
<i className="site-menu-icon"></i> BarterDEX
</a>
</li>
{ this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native' && (this._checkAC() || this.props.ActiveCoin.coin === 'KMD') &&
{ this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native' && (/*this._checkAC() || */this.props.ActiveCoin.coin === 'KMD') &&
<li className={ this.isSectionActive('jumblr') ? 'active nav-top-menu' : 'nav-top-menu' }>
<a onClick={ () => this.dashboardChangeSection('jumblr') }>
<i className="site-menu-icon"></i> Jumblr
</a>
</li>
}
{ this.state.nativeOnly &&
<li className="nav-top-menu">
<a onClick={ this.openImportKeyModal }>
<i className="site-menu-icon"></i> Import key
</a>
</li>
}
<li className={ this.state.nativeOnly ? 'hide' : (this.isSectionActive('atomic') ? 'active nav-top-menu' : 'nav-top-menu') }>
<a onClick={ () => this.dashboardChangeSection('atomic') }>
<i className="site-menu-icon"></i> Atomic Explorer
@ -99,14 +106,14 @@ const NavbarRender = function() {
<i className="icon md-settings"></i> { translate('INDEX.SETTINGS') }
</a>
</li>
<li className={ this.state.nativeOnly ? 'hide' : '' }>
<li className={ this.state.nativeOnly || !this.state.isExperimentalOn ? 'hide' : '' }>
<a onClick={ () => this.openSyncOnlyModal() }>
<i className="icon fa-cubes"></i> { translate('ADD_COIN.SYNC_ONLY') }
</a>
</li>
<li>
<a onClick={ () => this.dashboardChangeSection('about') }>
<i className="icon fa-users"></i> { translate('INDEX.ABOUT_IGUANA') }
<i className="icon fa-users"></i> { translate('ABOUT.ABOUT_AGAMA') }
</a>
</li>
<li className={ this.state.nativeOnly ? 'hide' : 'divider' }></li>

110
react/src/components/dashboard/notifications/notifications.js

@ -1,110 +0,0 @@
import React from 'react';
import { sortByDate } from '../../../util/sort';
import Config from '../../../config';
import {
NotificationsByTypeRender,
NotificationsModalRender,
NotificationsRender
} from './notifications.render';
class Notifications extends React.Component {
constructor(props) {
super(props);
this.state = {
displayModal: false,
calls: {
total: 0,
error: 0,
success: 0,
pending: 0,
},
activeTab: 2,
guiLog: null,
debug: Config.debug,
};
this.toggleNotificationsModal = this.toggleNotificationsModal.bind(this);
}
openTab(tab) {
this.setState(Object.assign({}, this.state, {
activeTab: tab,
}));
}
componentWillReceiveProps(props) {
// get total number of calls per type
if (this.props.Dashboard &&
this.props.Dashboard.guiLog) {
const _guiLog = this.props.Dashboard.guiLog;
let _callsLength = {
total: Object.keys(_guiLog).length,
error: 0,
success: 0,
pending: 0,
}
let guiLogToArray = [];
for (let timestamp in _guiLog) {
guiLogToArray.push(_guiLog[timestamp]);
_callsLength[_guiLog[timestamp].status]++;
}
this.setState(Object.assign({}, this.state, {
calls: {
total: _callsLength.total,
error: _callsLength.error,
success: _callsLength.success,
pending: _callsLength.pending,
},
guiLog: guiLogToArray,
}));
}
}
renderNotificationsByType(type) {
// get total number of calls per type
if (this.state.guiLog &&
this.state.guiLog.length) {
let _guiLog = this.state.guiLog;
let items = [];
_guiLog = sortByDate(_guiLog);
for (let i = 0; i < _guiLog.length; i++) {
if (_guiLog[i].status === type) {
const _logItem = _guiLog[i];
items.push(
NotificationsByTypeRender.call(
this,
_logItem,
type,
i
)
);
}
}
return items;
}
}
renderNotificationsModal() {
if (this.state.displayModal) {
return NotificationsModalRender.call(this);
}
return null;
}
toggleNotificationsModal() {
this.setState(Object.assign({}, this.state, {
displayModal: !this.state.displayModal,
}));
}
render() {
return NotificationsRender.call(this);
}
}
export default Notifications;

116
react/src/components/dashboard/notifications/notifications.render.js

@ -1,116 +0,0 @@
import React from 'react';
import {
secondsToString
} from '../../../util/time';
import { translate } from '../../../translate/translate';
export const NotificationsByTypeRender = function(logItem, type, index) {
return (
<div key={ logItem.timestamp }>
<div>{ index + 1 }.</div>
<div>
<strong>Time:</strong> { secondsToString(logItem.timestamp, true, true) }
</div>
<div>
<strong>GUI Function:</strong> { logItem.function }
</div>
<div>
<strong>HTTP:</strong> { logItem.httpMethod.toUpperCase() }
</div>
<div>
<strong>URL:</strong> { logItem.url }
</div>
<div>
<strong>Payload:</strong> { JSON.stringify(logItem.payload, null, '\t') }
</div>
<div className={ type !== 'pending' ? '' : 'hide' }>
<strong>Response:</strong> { JSON.stringify(logItem.response, null, '\t') }
</div>
<hr />
</div>
);
}
export const NotificationsModalRender = function() {
return (
<div onKeyDown={ (event) => this.handleKeydown(event) }>
<div className="modal show notifications-modal">
<div className="modal-dialog modal-center modal-lg">
<div className="modal-content">
<div className="modal-body modal-body-container">
<div className="panel nav-tabs-horizontal">
<ul className="nav nav-tabs nav-tabs-line">
<li className={ this.state.activeTab === 0 ? 'active' : 'pointer' }>
<a onClick={ () => this.openTab(0) }>
<i className="icon fa fa-thumbs-o-up"></i> Success ({ this.state.calls.success })
</a>
</li>
<li className={ this.state.activeTab === 1 ? 'active' : 'pointer' }>
<a onClick={ () => this.openTab(1) }>
<i className="icon fa fa-exclamation-triangle"></i> Error ({ this.state.calls.error })
</a>
</li>
<li className={ this.state.activeTab === 2 ? 'active' : 'pointer' }>
<a onClick={ () => this.openTab(2) }>
<i className="icon fa fa-clock-o"></i> Pending ({ this.state.calls.pending })
</a>
</li>
</ul>
<div className="panel-body panel-body-container">
<div className="tab-content">
<div className={ 'tab-pane' + (this.state.activeTab === 0 ? ' active' : '') }>
{ this.renderNotificationsByType('success') }
</div>
<div className={ 'tab-pane' + (this.state.activeTab === 1 ? ' active' : '') }>
{ this.renderNotificationsByType('error') }
</div>
<div className={ 'tab-pane' + (this.state.activeTab === 2 ? ' active' : '') }>
{ this.renderNotificationsByType('pending') }
</div>
</div>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-default"
onClick={ this.toggleNotificationsModal }>
{ translate('INDEX.CLOSE') }
</button>
</div>
</div>
</div>
</div>
<div className="modal-backdrop show in"></div>
</div>
);
};
export const NotificationsRender = function() {
return (
<div>
<div
className={ 'notifications-badge' + (this.props.Dashboard.activeHandle && this.props.Dashboard.activeHandle.status === 'unlocked' ? ' stick-to-top' : '') }
onClick={ this.state.debug ? this.toggleNotificationsModal : null }>
<span className={ this.state.debug ? 'badge success' : 'hide' }>
{ this.state.calls.success }
</span>
<span className={ this.state.debug ? 'badge error' : 'hide' }>
{ this.state.calls.error }
</span>
<span className={ this.state.debug ? 'badge pending' : 'hide' }>
{ this.state.calls.pending }
</span>
<div className={ 'spinner' + (this.state.calls.pending === 0 ? ' spinner-hide' : '') }>
<div className="rect1"></div>
<div className="rect2"></div>
<div className="rect3"></div>
<div className="rect4"></div>
<div className="rect5"></div>
</div>
</div>
{ this.renderNotificationsModal() }
</div>
);
};

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

@ -14,6 +14,7 @@ class QRModal extends React.Component {
this.state = {
modalIsOpen: false,
error: null,
errorShown: false,
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
@ -45,7 +46,7 @@ class QRModal extends React.Component {
openModal() {
this.setState({
modalIsOpen: true
modalIsOpen: true,
});
if (this.props.mode === 'scan') {
@ -65,6 +66,7 @@ class QRModal extends React.Component {
closeModal() {
this.setState({
modalIsOpen: false,
errorShown: this.state.error ? true : false,
});
}

76
react/src/components/dashboard/qrModal/qrModal.render.js

@ -2,7 +2,7 @@ import React from 'react';
import { translate } from '../../../translate/translate';
import QRCode from 'qrcode.react';
export const QRModalRender = function () {
export const QRModalRender = function() {
return (
<span>
<span className="label label-default margin-left-10 action"
@ -41,48 +41,46 @@ export const QRModalRender = function () {
);
};
export const QRModalReaderRender = function () {
return (
<span>
<button type="button"
className="btn btn-default"
onClick={ this.openModal }>
<i className="icon fa-qrcode"></i>
{ translate('INDEX.SCAN_QRCODE_WEBCAM') }
</button>
<div
className={ 'modal modal-3d-sign ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }
id="QRReadModal">
<div className="modal-dialog modal-center modal-md">
<div className="modal-content">
<div className="modal-header bg-orange-a400 wallet-send-header">
<button
type="button"
className="close white"
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">{ translate('INDEX.SCAN_QRCODE_WEBCAM') }</h4>
</div>
<div className="modal-body">
<div className="animsition vertical-align fade-in">
<div
className="page-content vertical-align-middle"
style={{
width: '100%',
textAlign: 'center',
fontSize: '16px'
}}>
<div id="webcam">
{ this.state.error }
export const QRModalReaderRender = function() {
if (!this.state.errorShown) {
return (
<span>
<button type="button"
className="btn btn-default"
onClick={ this.openModal }>
<i className="icon fa-qrcode"></i>
{ translate('INDEX.SCAN_QRCODE_WEBCAM') }
</button>
<div
className={ 'modal modal-3d-sign ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }
id="QRReadModal">
<div className="modal-dialog modal-center modal-md">
<div className="modal-content">
<div className="modal-header bg-orange-a400 wallet-send-header">
<button
type="button"
className="close white"
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">{ translate('INDEX.SCAN_QRCODE_WEBCAM') }</h4>
</div>
<div className="modal-body">
<div className="animsition vertical-align fade-in">
<div className="page-content vertical-align-middle webcam-frame">
<div id="webcam">
{ this.state.error }
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className={ 'modal-backdrop ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }></div>
</span>
);
<div className={ 'modal-backdrop ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }></div>
</span>
);
} else {
return null;
}
};

11
react/src/components/dashboard/qrModal/qrModal.scss

@ -0,0 +1,11 @@
.qr-modal-send-block {
position: absolute;
top: 15px;
right: 30px;
}
.webcam-frame {
width: 100%;
text-align: center;
font-size: 16px;
}

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

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import {
copyCoinAddress,
checkAddressBasilisk,
@ -18,8 +19,8 @@ import {
// TODO: fallback to localstorage/stores data in case iguana is taking too long to respond
class ReceiveCoin extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
openDropMenu: false,
@ -217,4 +218,26 @@ class ReceiveCoin extends React.Component {
}
}
export default ReceiveCoin;
const mapStateToProps = (state, props) => {
let _mappedProps = {
coin: state.ActiveCoin.coin,
mode: state.ActiveCoin.mode,
receive: state.ActiveCoin.receive,
balance: state.ActiveCoin.balance,
cache: state.ActiveCoin.cache,
activeSection: state.ActiveCoin.activeSection,
activeAddress: state.ActiveCoin.activeAddress,
addresses: state.ActiveCoin.addresses,
};
if (props &&
props.activeSection &&
props.renderTableOnly) {
_mappedProps.activeSection = props.activeSection;
_mappedProps.renderTableOnly = props.renderTableOnly;
}
return _mappedProps;
};
export default connect(mapStateToProps)(ReceiveCoin);

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

@ -1,4 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import Config from '../../../config';
import { translate } from '../../../translate/translate';
import { checkTimestamp } from '../../../util/time';
@ -9,7 +10,6 @@ import {
import {
resolveOpenAliasAddress,
triggerToaster,
basiliskRefresh,
shepherdGroomPostPromise,
edexGetTransaction,
getCacheFile,
@ -41,7 +41,7 @@ class SendCoin extends React.Component {
super(props);
this.state = {
currentStep: 0,
sendFrom: this.props.Dashboard && this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : null,
sendFrom: this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : null,
sendFromAmount: 0,
sendTo: '',
sendToOA: null,
@ -127,13 +127,6 @@ class SendCoin extends React.Component {
currentStackLength: data.message.shepherd.iguanaAPI.currentStackLength,
}));
}
if (data &&
data.message &&
data.message.shepherd.method &&
data.message.shepherd.method === 'cache-one' &&
data.message.shepherd.status === 'done') {
Store.dispatch(basiliskRefresh(false));
}
}
_fetchNewUTXOData() {
@ -764,7 +757,7 @@ class SendCoin extends React.Component {
}
// TODO same as in walletsNav and receiveCoin, find a way to reuse it?
checkTotalBalance() {
checkBalance() {
let _balance = '0';
const _mode = this.props.ActiveCoin.mode;
@ -784,21 +777,16 @@ class SendCoin extends React.Component {
(_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;
const _regInterest = _cache[_coin][_address].getbalance.data.interest ? _cache[_coin][_address].getbalance.data.interest : 0;
_balance = _regBalance + _regInterest;
_balance = _regBalance;
}
}
} else if (_mode === 'native') {
if (this.props.ActiveCoin.balance &&
this.props.ActiveCoin.balance.total) {
_balance = this.props.ActiveCoin.balance.total;
}
}
return +_balance;
return _balance;
}
// TODO: reduce to a single toast
validateSendFormData() {
let valid = true;
if (!this.state.sendTo || this.state.sendTo.length < 34) {
@ -845,7 +833,8 @@ class SendCoin extends React.Component {
valid = false;
}
if (this.state.amount > this.checkTotalBalance()) {
/*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'),
@ -854,7 +843,7 @@ class SendCoin extends React.Component {
)
);
valid = false;
}
}*/
return valid;
}
@ -874,4 +863,23 @@ class SendCoin extends React.Component {
}
}
export default SendCoin;
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);

180
react/src/components/dashboard/settings/settings.addNodePanel.js

@ -0,0 +1,180 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
import {
addPeerNode,
getPeersList,
getPeersListState,
} from '../../../actions/actionCreators';
import Store from '../../../store';
import AddCoinOptionsCrypto from '../../addcoin/addcoinOptionsCrypto';
import AddCoinOptionsAC from '../../addcoin/addcoinOptionsAC';
import AddCoinOptionsACFiat from '../../addcoin/addcoinOptionsACFiat';
class AddNodePanel extends React.Component {
constructor() {
super();
this.state = {
addNodeCoin: null,
addPeerIP: null,
getPeersCoin: null,
trimPassphraseTimer: null,
wifkeysPassphrase:'',
};
this.renderSNPeersList = this.renderSNPeersList.bind(this);
this.renderPeersList = this.renderPeersList.bind(this);
this.checkNodes = this.checkNodes.bind(this);
this.addNode = this.addNode.bind(this);
this.updateInput = this.updateInput.bind(this);
}
renderSNPeersList() {
if (this.state.getPeersCoin) {
const _getPeersCoin = this.state.getPeersCoin;
const _supernetPeers = this.props.Settings.supernetPeers;
const coin = _getPeersCoin.split('|')[0];
if (_supernetPeers &&
_getPeersCoin &&
_supernetPeers[coin]) {
return _supernetPeers[coin].map((ip) =>
<div key={ ip }>{ ip }</div>
);
} else {
return null;
}
} else {
return null;
}
}
renderPeersList() {
if (this.state.getPeersCoin) {
const _getPeersCoin = this.state.getPeersCoin;
const _rawPeers = this.props.Settings.rawPeers;
const coin = _getPeersCoin.split('|')[0];
if (_rawPeers &&
_getPeersCoin &&
_rawPeers[coin]) {
return _rawPeers[coin].map((ip) =>
<div key={ ip }>{ ip }</div>
);
} else {
return null;
}
} else {
return null;
}
}
checkNodes() {
if (this.state.getPeersCoin) {
console.warn(this.state.getPeersCoin.split('|')[0]);
Store.dispatch(getPeersList(this.state.getPeersCoin.split('|')[0]));
}
}
addNode() {
if (this.state.addNodeCoin && this.state.addPeerIP) {
Store.dispatch(
addPeerNode(
this.state.addNodeCoin.split('|')[0],
this.state.addPeerIP
)
);
}
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div className="panel-body">
<div className="row">
<div className="col-sm-6">
<div className="col-sm-12">
<p>{ translate('INDEX.USE_THIS_SECTION') }</p>
</div>
<div className="col-sm-8 col-xs-12">
<div className="form-group">
<select
className="form-control form-material"
name="getPeersCoin"
onChange={ this.updateInput }>
<option>{ translate('INDEX.SELECT_COIN') }</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
</div>
<div className="col-sm-4 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.checkNodes }>{ translate('INDEX.CHECK_NODES') }</button>
</div>
<div className="col-sm-12">
<h5>
SuperNET Peers:
</h5>
<div>{ this.renderSNPeersList() }</div>
<h5>
Raw Peers:
</h5>
<div>{ this.renderPeersList() }</div>
</div>
</div>
<div className="col-sm-6">
<div className="col-sm-12">
<p>{ translate('INDEX.USE_THIS_SECTION_PEER') }</p>
</div>
<div className="col-sm-8 col-xs-12">
<div className="form-group">
<select
className="form-control form-material"
name="addNodeCoin"
onChange={ this.updateInput }>
<option>{ translate('INDEX.SELECT_COIN') }</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
<div className="form-group">
<input
type="text"
className="form-control"
name="addPeerIP"
placeholder={ translate('SETTINGS.ADD_PEER_IP') }
onChange={ this.updateInput } />
</div>
</div>
<div className="col-sm-4 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.addNode }>{ translate('INDEX.ADD_NODE') }</button>
</div>
</div>
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(AddNodePanel);

90
react/src/components/dashboard/settings/settings.appInfoPanel.js

@ -0,0 +1,90 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
class AppInfoPanel extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="panel-body">
<div className="col-sm-12 padding-top-15">
<div className="row">
<h5>{ translate('SETTINGS.APP_RELEASE') }</h5>
<div>
{ translate('SETTINGS.NAME') }: { this.props.Settings.appInfo.releaseInfo.name }
</div>
<div>
{ translate('SETTINGS.VERSION') }: { `${this.props.Settings.appInfo.releaseInfo.version.replace('version=', '')}-beta` }
</div>
<div>
{ translate('SETTINGS.APP_SESSION') }: { this.props.Settings.appInfo.appSession }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
<h5>{ translate('SETTINGS.SYS_INFO') }</h5>
<div>
{ translate('SETTINGS.ARCH') }: { this.props.Settings.appInfo.sysInfo.arch }
</div>
<div>
{ translate('SETTINGS.OS_TYPE') }: { this.props.Settings.appInfo.sysInfo.os_type }
</div>
<div>
{ translate('SETTINGS.OS_PLATFORM') }: { this.props.Settings.appInfo.sysInfo.platform }
</div>
<div>
{ translate('SETTINGS.OS_RELEASE') }: { this.props.Settings.appInfo.sysInfo.os_release }
</div>
<div>
{ translate('SETTINGS.CPU') }: { this.props.Settings.appInfo.sysInfo.cpu }
</div>
<div>
{ translate('SETTINGS.CPU_CORES') }: { this.props.Settings.appInfo.sysInfo.cpu_cores }
</div>
<div>
{ translate('SETTINGS.MEM') }: { this.props.Settings.appInfo.sysInfo.totalmem_readable }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
<h5>{ translate('SETTINGS.LOCATIONS') }</h5>
<div>
{ translate('SETTINGS.CACHE') }: { this.props.Settings.appInfo.dirs.cacheLocation }
</div>
<div>
{ translate('SETTINGS.CONFIG') }: { this.props.Settings.appInfo.dirs.configLocation }
</div>
<div>
Iguana { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.iguanaBin }
</div>
<div>
Iguana { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.iguanaDir }
</div>
<div>
Komodo { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.komododBin }
</div>
<div>
Komodo { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
<div>
Komodo wallet.dat: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
</div>
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(AppInfoPanel);

321
react/src/components/dashboard/settings/settings.appSettingsPanel.js

@ -0,0 +1,321 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import Config from '../../../config';
import {
iguanaActiveHandle,
getAppConfig,
getAppInfo,
resetAppConfig,
saveAppConfig,
skipFullDashboardUpdate,
triggerToaster,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class AppSettingsPanel extends React.Component {
constructor() {
super();
this.state = {
appSettings: {},
appConfigSchema: {},
};
this._saveAppConfig = this._saveAppConfig.bind(this);
this._resetAppConfig = this._resetAppConfig.bind(this);
this._skipFullDashboardUpdate = this._skipFullDashboardUpdate.bind(this);
this.updateInput = this.updateInput.bind(this);
}
componentWillMount() {
try {
const _appConfigSchema = window.require('electron').remote.getCurrentWindow().appConfigSchema;
const _appSettings = this.props.Settings.appSettings ? this.props.Settings.appSettings : Object.assign({}, window.require('electron').remote.getCurrentWindow().appConfig);
this.setState(Object.assign({}, this.state, {
appConfigSchema: _appConfigSchema,
appSettings: _appSettings,
}));
} catch(e) {}
}
componentDidMount(props) {
if (!this.props.disableWalletSpecificUI) {
Store.dispatch(iguanaActiveHandle());
}
Store.dispatch(getAppConfig());
Store.dispatch(getAppInfo());
}
_skipFullDashboardUpdate() {
Store.dispatch(skipFullDashboardUpdate(!this.props.Dashboard.skipFullDashboardUpdate));
}
_resetAppConfig() {
Store.dispatch(resetAppConfig());
}
_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] && this.state.appConfigSchema[key].type === 'number' ? Number(_appSettings[key]) : _appSettings[key];
if (this.state.appConfigSchema[key] && 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];
}
}
if (!saveAfterPathCheck) {
Store.dispatch(saveAppConfig(_appSettingsPristine));
}
}
renderConfigEditForm() {
let items = [];
const _appConfig = this.state.appSettings;
for (let key in _appConfig) {
if (this.state.appConfigSchema[key] && typeof _appConfig[key] === 'object') {
if (this.state.appConfigSchema[key].display) {
items.push(
<tr key={ `app-settings-${key}` }>
<td className="padding-15">
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key }
{ this.state.appConfigSchema[key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key].info }></i>
}
</td>
<td className="padding-15"></td>
</tr>
);
for (let _key in _appConfig[key]) {
items.push(
<tr key={ `app-settings-${key}-${_key}` }>
<td className="padding-15 padding-left-30">
{ this.state.appConfigSchema[key][_key].displayName ? this.state.appConfigSchema[key][_key].displayName : _key }
{ this.state.appConfigSchema[key][_key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key][_key].info }></i>
}
</td>
<td className="padding-15">
{ this.state.appConfigSchema[key][_key].type === 'number' &&
<input
type="number"
pattern="[0-9]*"
name={ `${key}__${_key}` }
value={ _appConfig[key][_key] }
onChange={ (event) => this.updateInputSettings(event, key, _key) } />
}
{ (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' &&
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `${key}__${_key}` }
value={ _appConfig[key] }
checked={ _appConfig[key][_key] } />
<div
className="slider"
onClick={ (event) => this.updateInputSettings(event, key, _key) }></div>
</label>
</span>
}
</td>
</tr>
);
}
}
} else {
if (this.state.appConfigSchema[key] && this.state.appConfigSchema[key].display) {
items.push(
<tr key={ `app-settings-${key}` }>
<td className="padding-15">
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key }
{ this.state.appConfigSchema[key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key].info }></i>
}
</td>
<td className="padding-15">
{ this.state.appConfigSchema[key].type === 'number' &&
<input
type="number"
pattern="[0-9]*"
name={ `${key}` }
value={ _appConfig[key] }
onChange={ (event) => this.updateInputSettings(event, key) } />
}
{ (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' &&
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `${key}` }
value={ _appConfig[key] }
checked={ _appConfig[key] } />
<div
className="slider"
onClick={ (event) => this.updateInputSettings(event, key) }></div>
</label>
</span>
}
</td>
</tr>
);
}
}
}
items.push(
<tr key={ `kmd-main-sync-only` }>
<td className="padding-15">
KMD main sync only
<i
className="icon fa-question-circle settings-help"
title="Fetch block synchronization data only. Skip any other requests that can deteriorate sync speed."></i>
</td>
<td className="padding-15">
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `kmd-main-sync-only` }
value={ this.props.Dashboard.skipFullDashboardUpdate }
checked={ this.props.Dashboard.skipFullDashboardUpdate } />
<div
className="slider"
onClick={ this._skipFullDashboardUpdate }></div>
</label>
</span>
</td>
</tr>
);
return items;
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
updateInputSettings(e, parentKey, childKey) {
let _appSettings = this.state.appSettings;
let _appSettingsPrev = Object.assign({}, _appSettings);
if (!childKey && this.state.appConfigSchema[parentKey].type === 'boolean') {
_appSettings[parentKey] = typeof _appSettings[parentKey] !== undefined ? !_appSettings[parentKey] : !this.state.appSettings[parentKey];
} else if (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'boolean') {
_appSettings[parentKey][childKey] = typeof _appSettings[parentKey][childKey] !== undefined ? !_appSettings[parentKey][childKey] : !this.state.appSettings[parentKey][childKey];
} else if ((!childKey && this.state.appConfigSchema[parentKey].type === 'number') || (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'number')) {
if (e.target.value === '') {
_appSettings[e.target.name] = _appSettingsPrev[e.target.name];
} else {
_appSettings[e.target.name] = e.target.value.replace(/[^0-9]+/g, '');
}
} else {
_appSettings[e.target.name] = e.target.value;
}
this.setState({
appSettings: _appSettings,
});
}
render() {
return (
<div className="panel-body">
<p>
<strong>{ translate('SETTINGS.CONFIG_RESTART_REQUIRED') }</strong>
</p>
<div className="col-sm-12 padding-top-15">
<table>
<tbody>
{ this.renderConfigEditForm() }
</tbody>
</table>
</div>
<div className="col-sm-12 col-xs-12 text-align-center padding-top-35 padding-bottom-30">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this._saveAppConfig }>{ translate('SETTINGS.SAVE_APP_CONFIG') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-30"
onClick={ this._resetAppConfig }>Reset to default</button>
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
Dashboard: {
skipFullDashboardUpdate: state.Dashboard.skipFullDashboardUpdate,
},
};
};
export default connect(mapStateToProps)(AppSettingsPanel);

151
react/src/components/dashboard/settings/settings.appUpdatePanel.js

@ -0,0 +1,151 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
import Config from '../../../config';
import {
getPeersList,
checkForUpdateUIPromise,
updateUIPromise,
} from '../../../actions/actionCreators';
import { SocketProvider } from 'socket.io-react';
import io from 'socket.io-client';
const socket = io.connect(`http://127.0.0.1:${Config.agamaPort}`);
let updateProgressBar = {
patch: -1,
};
class AppUpdatePanel extends React.Component {
constructor() {
super();
this.state = {
updatePatch: null,
updateLog: [],
updateProgressPatch: null,
updatePatch: null,
updateBins: null,
};
this._checkForUpdateUIPromise = this._checkForUpdateUIPromise.bind(this);
this._updateUIPromise = this._updateUIPromise.bind(this);
this.checkNodes = this.checkNodes.bind(this);
}
componentWillMount() {
socket.on('patch', msg => this.updateSocketsData = (msg) => {});
}
componentWillUnmount() {
socket.removeAllListeners('patch', msg => this.updateSocketsData(msg));
}
checkNodes() {
if (this.state.getPeersCoin) {
Store.dispatch(getPeersList(this.state.getPeersCoin.split('|')[0]));
}
}
_updateUIPromise() {
updateProgressBar.patch = 0;
let _updateLog = [];
_updateLog.push(`${translate('INDEX.DOWNLOADING_UI_UPDATE')}...`);
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
updateUIPromise();
}
_checkForUpdateUIPromise() {
let _updateLog = [];
_updateLog.push(translate('INDEX.CHECKING_UI_UPDATE'));
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
checkForUpdateUIPromise()
.then((res) => {
let _updateLog = this.state.updateLog;
_updateLog.push(res.result === 'update' ? (`${translate('INDEX.NEW_UI_UPDATE')} ${res.version.remote}`) : translate('INDEX.YOU_HAVE_LATEST_UI'));
this.setState(Object.assign({}, this.state, {
updatePatch: res.result === 'update' ? true : false,
updateLog: _updateLog,
}));
});
}
renderUpdateStatus() {
let items = [];
let patchProgressBar = null;
const _updateLogLength = this.state.updateLog.length;
for (let i = 0; i < _updateLogLength; i++) {
items.push(
<div key={ `settings-update-log-${i}` }>{ this.state.updateLog[i] }</div>
);
}
if (_updateLogLength) {
return (
<div style={{ minHeight: '200px' }}>
<hr />
<h5>{ translate('SETTINGS.PROGRESS') }:</h5>
<div className="padding-bottom-15">{ items }</div>
<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}%` }}>
</div>
</div>
</div>
);
} else {
return null;
}
}
render() {
return (
<div className="panel-body">
<div className="col-sm-4 padding-top-15">
<h5>{ translate('INDEX.UI_UPDATE') }</h5>
<div className="padding-top-15">
<button
type="button"
className="btn btn-info waves-effect waves-light"
onClick={ this._checkForUpdateUIPromise }>{ translate('INDEX.CHECK_FOR_UPDATE') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-20"
onClick={ this._updateUIPromise }
disabled={ !this.state.updatePatch }>{ translate('INDEX.UPDATE_UI_NOW') }</button>
</div>
</div>
<div className="col-sm-4 padding-top-15 hide">
<h5>{ translate('INDEX.BINS_UPDATE') }</h5>
<div className="padding-top-15">
<button
type="button"
className="btn btn-info waves-effect waves-light"
onClick={ this._checkForUpdateUIPromise }>{ translate('INDEX.CHECK_FOR_UPDATE') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-20"
onClick={ this.checkNodes }>{ translate('INDEX.UPDATE_BINS_NOW') }</button>
</div>
</div>
<div className="col-sm-12 padding-top-15">
{ this.renderUpdateStatus() }
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(AppUpdatePanel);

206
react/src/components/dashboard/settings/settings.cliPanel.js

@ -0,0 +1,206 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import {
shepherdCli,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class CliPanel extends React.Component {
constructor() {
super();
this.state = {
cliCmdString: '',
cliCoin: null,
cliResponse: null,
};
}
renderActiveCoinsList(mode) {
const modes = [
'native',
'basilisk',
'full'
];
const allCoins = this.props.Main.coins;
let items = [];
if (allCoins) {
if (mode === 'all') {
modes.map(function(mode) {
allCoins[mode].map(function(coin) {
items.push(
<option
value={ coin }
key={ coin }>
{ coin } ({ mode })
</option>
);
});
});
} else {
allCoins[mode].map(function(coin) {
items.push(
<option
value={ coin }
key={ coin }>
{ coin } ({ mode })
</option>
);
});
}
return items;
} else {
return null;
}
}
// TODO: rerender only if prop is changed
renderCliResponse() {
const _cliResponse = this.props.Settings.cli;
let _items = [];
if (_cliResponse) {
let _cliResponseParsed;
let responseType;
try {
_cliResponseParsed = JSON.parse(_cliResponse.result);
} catch(e) {
_cliResponseParsed = _cliResponse.result;
}
if (Object.prototype.toString.call(_cliResponseParsed) === '[object Array]') {
responseType = 'array';
for (let i = 0; i < _cliResponseParsed.length; i++) {
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed[i], null, '\t') }</div>
);
}
}
if (Object.prototype.toString.call(_cliResponseParsed) === '[object]' ||
typeof _cliResponseParsed === 'object') {
responseType = 'object';
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed, null, '\t') }</div>
);
}
if (Object.prototype.toString.call(_cliResponseParsed) === 'number' ||
typeof _cliResponseParsed === 'boolean' ||
_cliResponseParsed === 'wrong cli string format') {
responseType = 'number';
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed.toString() }</div>
);
}
if (responseType !== 'number' &&
responseType !== 'array' &&
responseType !== 'object' &&
_cliResponseParsed.indexOf('\n') > -1) {
_cliResponseParsed = _cliResponseParsed.split('\n');
for (let i = 0; i < _cliResponseParsed.length; i++) {
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed[i] }</div>
);
}
}
return (
<div>
<div>
<strong>{ translate('SETTINGS.CLI_RESPONSE') }:</strong>
</div>
{ _items }
</div>
);
} else {
return null;
}
}
execCliCmd() {
Store.dispatch(
shepherdCli(
'passthru',
this.state.cliCoin,
this.state.cliCmdString
)
);
}
updateInput = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div className="panel-body">
<p>{ translate('INDEX.CLI_SELECT_A_COIN') }</p>
<div className="col-sm-12"></div>
<form
className="execute-cli-cmd-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<select
className="form-control form-material"
name="cliCoin"
id="settingsCliOptions"
onChange={ this.updateInput }>
<option>{ translate('INDEX.CLI_NATIVE_COIN') }</option>
{ this.renderActiveCoinsList('native') }
</select>
<label
className="floating-label"
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.COIN') }</label>
</div>
<div className="form-group form-material floating">
<textarea
type="text"
className="form-control"
name="cliCmdString"
id="cliCmd"
value={ this.state.cliCmdString }
onChange={ this.updateInput }></textarea>
<label
className="floating-label"
htmlFor="readDebugLogLines">{ translate('INDEX.TYPE_CLI_CMD') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
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">
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">
{ this.renderCliResponse() }
</div>
</div>
</form>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Main: {
coins: state.Main.coins,
},
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(CliPanel);

180
react/src/components/dashboard/settings/settings.debugLogPanel.js

@ -0,0 +1,180 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import Config from '../../../config';
import { secondsToString } from '../../../util/time';
import {
getDebugLog,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class DebugLogPanel extends React.Component {
constructor() {
super();
this.state = {
appRuntimeLog: [],
debugLinesCount: 10,
debugTarget: 'iguana',
nativeOnly: Config.iguanaLessMode,
toggleAppRuntimeLog: false,
};
this.readDebugLog = this.readDebugLog.bind(this);
this.updateInput = this.updateInput.bind(this);
this.getAppRuntimeLog = this.getAppRuntimeLog.bind(this);
this.toggleAppRuntimeLog = this.toggleAppRuntimeLog.bind(this);
this.renderAppRuntimeLog = this.renderAppRuntimeLog.bind(this);
}
readDebugLog() {
Store.dispatch(
getDebugLog(
this.state.debugTarget,
this.state.debugLinesCount
)
);
}
renderAppRuntimeLog() {
let _items = [];
const _appRuntimeLog = this.state.appRuntimeLog;
for (let i = 0; i < _appRuntimeLog.length; i++) {
_items.push(
<p key={ `app-runtime-log-entry-${i}` }>
<span>{ secondsToString(_appRuntimeLog[i].time, true) }</span>
<span className="padding-left-30">{ JSON.stringify(_appRuntimeLog[i].msg, null, '') }</span>
</p>
);
}
return _items;
}
toggleAppRuntimeLog() {
this.setState(Object.assign({}, this.state, {
toggleAppRuntimeLog: !this.state.toggleAppRuntimeLog,
}));
this.getAppRuntimeLog();
}
getAppRuntimeLog() {
let _appRuntimeLog;
try {
_appRuntimeLog = window.require('electron').remote.getCurrentWindow().getAppRuntimeLog;
} catch (e) {}
_appRuntimeLog()
.then((json) => {
this.setState(Object.assign({}, this.state, {
appRuntimeLog: json,
}));
});
}
renderDebugLogData() {
if (this.props.Settings.debugLog) {
const _debugLogDataRows = this.props.Settings.debugLog.split('\n');
if (_debugLogDataRows &&
_debugLogDataRows.length) {
return _debugLogDataRows.map((_row) =>
<div
key={ `settings-debuglog-${Math.random(0, 9) * 10}` }
className="padding-bottom-5">{ _row }</div>
);
} else {
return (
<span>{ translate('INDEX.EMPTY_DEBUG_LOG') }</span>
);
}
} else {
return null;
}
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div className="panel-body">
<p>{ translate('INDEX.DEBUG_LOG_DESC') }</p>
<div className="margin-top-30">
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name="settings-app-debug-toggle"
value={ this.state.toggleAppRuntimeLog }
checked={ this.state.toggleAppRuntimeLog } />
<div
className="slider"
onClick={ this.toggleAppRuntimeLog }></div>
</label>
<span
className="title"
onClick={ this.toggleAppRuntimeLog }>Show app runtime log</span>
</span>
</div>
{ !this.state.toggleAppRuntimeLog &&
<form
className="read-debug-log-import-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="text"
className="form-control"
name="debugLinesCount"
id="readDebugLogLines"
value={ this.state.debugLinesCount }
onChange={ this.updateInput } />
<label
className="floating-label"
htmlFor="readDebugLogLines">{ translate('INDEX.DEBUG_LOG_LINES') }</label>
</div>
<div className="form-group form-material floating">
<select
className="form-control form-material"
name="debugTarget"
id="settingsDelectDebugLogOptions"
onChange={ this.updateInput }>
<option value="iguana" className={ this.state.nativeOnly ? 'hide' : '' }>Iguana</option>
<option value="komodo">Komodo</option>
</select>
<label
className="floating-label"
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.TARGET') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.readDebugLog }>{ translate('INDEX.LOAD_DEBUG_LOG') }</button>
</div>
<div className="col-sm-12 col-xs-12 text-align-left">
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">{ this.renderDebugLogData() }</div>
</div>
</form>
}
{ this.state.toggleAppRuntimeLog &&
<div className="margin-top-20">{ this.renderAppRuntimeLog() }</div>
}
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(DebugLogPanel);

235
react/src/components/dashboard/settings/settings.exportKeysPanel.js

@ -0,0 +1,235 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
import {
encryptWallet,
settingsWifkeyState,
copyCoinAddress,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class ExportKeysPanel extends React.Component {
constructor() {
super();
this.state = {
exportWifKeysRaw: false,
seedInputVisibility: false,
trimPassphraseTimer: null,
wifkeysPassphrase: '',
};
this.exportWifKeys = this.exportWifKeys.bind(this);
this.exportWifKeysRaw = this.exportWifKeysRaw.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this._copyCoinAddress = this._copyCoinAddress.bind(this);
this.updateInput = this.updateInput.bind(this);
}
exportWifKeys() {
Store.dispatch(
encryptWallet(
this.state.wifkeysPassphrase,
settingsWifkeyState,
this.props.ActiveCoin.coin
)
);
}
exportWifKeysRaw() {
this.setState(Object.assign({}, this.state, {
exportWifKeysRaw: !this.state.exportWifKeysRaw,
}));
}
toggleSeedInputVisibility() {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
});
}
renderExportWifKeysRaw() {
const _wifKeysResponse = this.props.Settings.wifkey;
if (_wifKeysResponse &&
this.state.exportWifKeysRaw) {
return (
<div className="padding-bottom-30 padding-top-30">
{ JSON.stringify(_wifKeysResponse, null, '\t') }
</div>
);
} else {
return null;
}
}
_copyCoinAddress(address) {
Store.dispatch(copyCoinAddress(address));
}
renderWifKeys() {
let items = [];
if (this.props.Settings.wifkey) {
const _wifKeys = this.props.Settings.wifkey;
for (let i = 0; i < 2; i++) {
items.push(
<tr key={ `wif-export-table-header-${i}` }>
<td className="padding-bottom-10 padding-top-10">
<strong>{ i === 0 ? translate('SETTINGS.ADDRESS_LIST') : translate('SETTINGS.WIF_KEY_LIST') }</strong>
</td>
<td className="padding-bottom-10 padding-top-10"></td>
</tr>
);
for (let _key in _wifKeys) {
if ((i === 0 && _key.length === 3 && _key !== 'tag') ||
(i === 1 && _key.indexOf('wif') > -1)) {
items.push(
<tr key={ _key }>
<td className="padding-bottom-20">{ _key.replace('wif', ' WIF') }</td>
<td className="padding-bottom-20 padding-left-15">
{ _wifKeys[_key] }
<button
className="btn btn-default btn-xs clipboard-edexaddr margin-left-10"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(_wifKeys[_key]) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</td>
</tr>
);
}
}
}
return items;
} else {
return null;
}
}
updateInput(e) {
if (e.target.name === 'wifkeysPassphrase') {
// remove any empty chars from the start/end of the string
const newValue = e.target.value;
clearTimeout(this.state.trimPassphraseTimer);
const _trimPassphraseTimer = setTimeout(() => {
this.setState({
wifkeysPassphrase: newValue ? newValue.trim() : '', // hardcoded field name
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name]: newValue,
});
} else {
this.setState({
[e.target.name]: e.target.value,
});
}
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#wifkeysPassphraseTextarea').style.height = '1px';
document.querySelector('#wifkeysPassphraseTextarea').style.height = `${(15 + document.querySelector('#wifkeysPassphraseTextarea').scrollHeight)}px`;
}
}, 100);
}
renderLB(_translationID) {
const _translationComponents = translate(_translationID).split('<br>');
return _translationComponents.map((_translation) =>
<span key={ `settings-label-${Math.random(0, 9) * 10}` }>
{ _translation }
<br />
</span>
);
}
render() {
return (
<div className="panel-body">
<div>
<div className="padding-bottom-20">{ this.renderLB('INDEX.ONLY_ACTIVE_WIF_KEYS') }</div>
<div className="padding-bottom-20">
<i>{ this.renderLB('SETTINGS.EXPORT_KEYS_NOTE') }</i>
</div>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
<form
className="wifkeys-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="password"
className={ !this.state.seedInputVisibility ? 'form-control' : 'hide' }
name="wifkeysPassphrase"
id="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase } />
<textarea
className={ this.state.seedInputVisibility ? 'form-control' : 'hide' }
id="wifkeysPassphraseTextarea"
name="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase }></textarea>
<i
className={ 'seed-toggle fa fa-eye' + (!this.state.seedInputVisibility ? '-slash' : '') }
onClick={ this.toggleSeedInputVisibility }></i>
<label
className="floating-label"
htmlFor="wifkeysPassphrase">{ translate('INDEX.PASSPHRASE') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.exportWifKeys }>{ translate('INDEX.GET_WIF_KEYS') }</button>
</div>
</form>
<div className="col-sm-12 padding-top-15">
<div className="row">
<table className="table">
{ this.renderWifKeys() }
</table>
<div className={ this.props.wifkey ? 'col-sm-12 col-xs-12 text-align-center' : 'hide' }>
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.exportWifKeysRaw }>{ this.state.exportWifKeysRaw ? 'Hide' : 'Show' } raw data</button>
</div>
<div className={ this.state.exportWifKeysRaw ? 'col-sm-12 col-xs-12 text-align-center' : 'hide' }>
{ this.renderExportWifKeysRaw() }
</div>
</div>
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
},
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(ExportKeysPanel);

23
react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js

@ -0,0 +1,23 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
class FiatCurrencyPanel extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="panel-body">Fiat currency settings section to be updated soon.</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(FiatCurrencyPanel);

67
react/src/components/dashboard/settings/settings.importKeysPanel.js

@ -0,0 +1,67 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import {
importPrivKey,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class ImportKeysPanel extends React.Component {
constructor() {
super();
this.state = {
importWifKey: '',
};
this.importWifKey = this.importWifKey.bind(this);
}
importWifKey() {
Store.dispatch(importPrivKey(this.state.importWifKey));
}
updateInput = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div className="panel-body">
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P1') }</div><br/>
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P2') }</div><br/>
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P3') }</div><br/>
<div>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
<form
className="wifkeys-import-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="text"
className="form-control"
name="importWifKey"
id="importWifkey"
onChange={ this.updateInput } />
<label
className="floating-label"
htmlFor="importWifkey">{ translate('INDEX.INPUT_PRIV_KEY') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.importWifKey }>{ translate('INDEX.IMPORT_PRIV_KEY') }</button>
</div>
</form>
</div>
);
}
}
export default ImportKeysPanel;

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

@ -1,38 +1,34 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import Config from '../../../config';
import {
iguanaActiveHandle,
encryptWallet,
settingsWifkeyState,
importPrivKey,
getDebugLog,
getAppConfig,
getPeersList,
addPeerNode,
getAppConfig,
saveAppConfig,
resetAppConfig,
getAppInfo,
shepherdCli,
checkForUpdateUIPromise,
updateUIPromise,
triggerToaster,
} from '../../../actions/actionCreators';
import Store from '../../../store';
import {
AppInfoTabRender,
SettingsRender,
AppUpdateTabRender,
} from './settings.render';
import { SocketProvider } from 'socket.io-react';
import io from 'socket.io-client';
const socket = io.connect(`http://127.0.0.1:${Config.agamaPort}`);
let updateProgressBar = {
patch: -1,
};
import AppUpdatePanel from './settings.appUpdatePanel';
import AppInfoPanel from './settings.appInfoPanel';
import AddNodePanel from './settings.addNodePanel';
import AppSettingsPanel from './settings.appSettingsPanel';
import CliPanel from './settings.cliPanel';
import DebugLogPanel from './settings.debugLogPanel';
import FiatCurrencyPanel from './settings.fiatCurrencyPanel';
import ExportKeysPanel from './settings.exportKeysPanel';
import ImportKeysPanel from './settings.importKeysPanel';
import SupportPanel from './settings.supportPanel';
import WalletInfoPanel from './settings.walletInfoPanel';
import WalletBackupPanel from './settings.walletBackupPanel';
/*
TODO:
@ -42,803 +38,103 @@ let updateProgressBar = {
4) batch export/import wallet addresses
*/
class Settings extends React.Component {
constructor(props) {
super(props);
constructor() {
super();
this.state = {
activeTab: 0,
debugLinesCount: 10,
debugTarget: 'iguana',
activeTabHeight: '0',
appSettings: {},
appConfigSchema: {},
tabElId: null,
cliCmdString: '',
cliCoin: null,
cliResponse: null,
exportWifKeysRaw: false,
seedInputVisibility: false,
nativeOnly: Config.iguanaLessMode,
updatePatch: null,
updateBins: null,
updateLog: [],
updateProgressPatch: null,
wifkeysPassphrase: '',
trimPassphraseTimer: null,
disableWalletSpecificUI: null,
disableWalletSpecificUI: false,
};
this.exportWifKeys = this.exportWifKeys.bind(this);
this.updateInput = this.updateInput.bind(this);
// this.updateInputSettings = this.updateInputSettings.bind(this);
this.importWifKey = this.importWifKey.bind(this);
this.readDebugLog = this.readDebugLog.bind(this);
this.checkNodes = this.checkNodes.bind(this);
this.addNode = this.addNode.bind(this);
this.renderPeersList = this.renderPeersList.bind(this);
this.renderSNPeersList = this.renderSNPeersList.bind(this);
this._saveAppConfig = this._saveAppConfig.bind(this);
this._resetAppConfig = this._resetAppConfig.bind(this);
this.exportWifKeysRaw = this.exportWifKeysRaw.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this._checkForUpdateUIPromise = this._checkForUpdateUIPromise.bind(this);
this._updateUIPromise = this._updateUIPromise.bind(this);
this.updateTabDimensions = this.updateTabDimensions.bind(this);
}
updateTabDimensions() {
setTimeout(() => {
const _height = document.querySelector(`#${this.state.tabElId} .panel-collapse .panel-body`).offsetHeight;
this.setState(Object.assign({}, this.state, {
activeTabHeight: _height,
}));
}, 100);
}
componentWillMount() {
socket.on('patch', msg => this.updateSocketsData(msg));
window.addEventListener('resize', this.updateTabDimensions);
try {
const _appConfigSchema = window.require('electron').remote.getCurrentWindow().appConfigSchema;
const _appSettings = this.props.Settings.appSettings ? this.props.Settings.appSettings : Object.assign({}, window.require('electron').remote.getCurrentWindow().appConfig);
this.setState(Object.assign({}, this.state, {
appConfigSchema: _appConfigSchema,
appSettings: _appSettings,
}));
} catch(e) {}
}
componentWillUnmount() {
socket.removeAllListeners('patch', msg => this.updateSocketsData(msg));
window.removeEventListener('resize', this.updateTabDimensions);
if (!this.state.disableWalletSpecificUI) {
document.documentElement.style.height = '100%';
document.body.style.height = '100%';
}
}
componentDidMount() {
componentDidMount(props) {
if (!this.props.disableWalletSpecificUI) {
Store.dispatch(iguanaActiveHandle());
}
Store.dispatch(getAppConfig());
Store.dispatch(getAppInfo());
document.getElementById('section-iguana-wallet-settings').setAttribute('style', 'height:auto; min-height: 100%');
}
componentWillReceiveProps(props) {
if (this.state.tabElId) {
const _height = document.querySelector(`#${this.state.tabElId} .panel-collapse .panel-body`).offsetHeight;
this.setState(Object.assign({}, this.state, {
activeTab: this.state.activeTab,
activeTabHeight: _height,
tabElId: this.state.tabElId,
disableWalletSpecificUI: props.disableWalletSpecificUI,
disableWalletSpecificUI: this.props.disableWalletSpecificUI,
}));
}
}
openExternalWindow(url) {
const remote = window.require('electron').remote;
const BrowserWindow = remote.BrowserWindow;
const externalWindow = new BrowserWindow({
width: 1280,
height: 800,
title: `${translate('INDEX.LOADING')}...`,
icon: remote.getCurrentWindow().iguanaIcon,
});
externalWindow.loadURL(url);
externalWindow.webContents.on('did-finish-load', function() {
setTimeout(function() {
externalWindow.show();
}, 40);
});
}
_resetAppConfig() {
Store.dispatch(resetAppConfig());
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#wifkeysPassphraseTextarea').style.height = '1px';
document.querySelector('#wifkeysPassphraseTextarea').style.height = `${(15 + document.querySelector('#wifkeysPassphraseTextarea').scrollHeight)}px`;
}
}, 100);
}
updateSocketsData(data) {
if (data &&
data.msg &&
data.msg.type === 'ui') {
if (data.msg.status === 'progress' &&
data.msg.progress &&
data.msg.progress < 100) {
this.setState(Object.assign({}, this.state, {
updateProgressPatch: data.msg.progress,
}));
updateProgressBar.patch = data.msg.progress;
} else {
if (data.msg.status === 'progress' &&
data.msg.progress &&
data.msg.progress === 100) {
let _updateLog = [];
_updateLog.push(`${translate('INDEX.UI_UPDATE_DOWNLOADED')}...`);
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
updateProgressBar.patch = 100;
}
if (data.msg.status === 'done') {
let _updateLog = [];
_updateLog.push(translate('INDEX.UI_UPDATED'));
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
updatePatch: null,
}));
updateProgressBar.patch = -1;
}
if (data.msg.status === 'error') {
let _updateLog = [];
_updateLog.push(translate('INDEX.UI_UPDATE_ERROR'));
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
updateProgressBar.patch = -1;
}
}
} else {
if (data &&
data.msg) {
let _updateLog = this.state.updateLog;
_updateLog.push(data.msg);
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
}
}
}
_checkForUpdateUIPromise() {
let _updateLog = [];
_updateLog.push(translate('INDEX.CHECKING_UI_UPDATE'));
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
checkForUpdateUIPromise()
.then((res) => {
let _updateLog = this.state.updateLog;
_updateLog.push(res.result === 'update' ? (`${translate('INDEX.NEW_UI_UPDATE')} ${res.version.remote}`) : translate('INDEX.YOU_HAVE_LATEST_UI'));
this.setState(Object.assign({}, this.state, {
updatePatch: res.result === 'update' ? true : false,
updateLog: _updateLog,
}));
});
}
_updateUIPromise() {
updateProgressBar.patch = 0;
let _updateLog = [];
_updateLog.push(`${translate('INDEX.DOWNLOADING_UI_UPDATE')}...`);
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
openTab(elemId, tab) {
this.setState(Object.assign({}, this.state, {
activeTab: tab,
tabElId: elemId,
}));
updateUIPromise();
}
renderUpdateStatus() {
let items = [];
let patchProgressBar = null;
const _updateLogLength = this.state.updateLog.length;
for (let i = 0; i < _updateLogLength; i++) {
items.push(
<div key={ `settings-update-log-${i}` }>{ this.state.updateLog[i] }</div>
);
}
if (_updateLogLength) {
return (
<div style={{ minHeight: '200px' }}>
<hr />
<h5>{ translate('SETTINGS.PROGRESS') }:</h5>
<div className="padding-bottom-15">{ items }</div>
<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}%` }}>
</div>
</div>
</div>
);
} else {
return null;
}
}
toggleSeedInputVisibility() {
updateInput(e) {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
[e.target.name]: e.target.value,
});
}
execCliCmd() {
Store.dispatch(
shepherdCli(
'passthru',
this.state.cliCoin,
this.state.cliCmdString
)
);
}
openTab(elemId, tab) {
setTimeout(() => {
const _height = document.querySelector(`#${elemId} .panel-collapse .panel-body`).offsetHeight;
this.setState(Object.assign({}, this.state, {
activeTab: tab,
activeTabHeight: _height,
tabElId: elemId,
}));
// body size hack
if (!this.state.disableWalletSpecificUI) {
document.documentElement.style.height = '100%';
document.body.style.height = '100%';
setTimeout(() => {
document.documentElement.style.height = _height <= 200 ? '100%' : 'inherit';
document.body.style.height = _height <= 200 ? '100%' : 'inherit';
}, 100);
}
}, 100);
}
exportWifKeys() {
Store.dispatch(
encryptWallet(
this.state.wifkeysPassphrase,
settingsWifkeyState,
this.props.ActiveCoin.coin
)
);
}
importWifKey() {
Store.dispatch(importPrivKey(this.state.importWifKey));
}
readDebugLog() {
Store.dispatch(
getDebugLog(
this.state.debugTarget,
this.state.debugLinesCount
)
);
}
checkNodes() {
if (this.state.getPeersCoin) {
Store.dispatch(getPeersList(this.state.getPeersCoin.split('|')[0]));
}
}
addNode() {
if (this.state.addNodeCoin) {
Store.dispatch(
addPeerNode(
this.state.addNodeCoin.split('|')[0],
this.state.addPeerIP
)
);
}
}
renderPeersList() {
if (this.state.getPeersCoin) {
const _getPeersCoin = this.state.getPeersCoin;
const _rawPeers = this.props.Settings.rawPeers;
const coin = _getPeersCoin.split('|')[0];
if (_rawPeers &&
_getPeersCoin &&
_rawPeers[coin]) {
return _rawPeers[coin].map((ip) =>
<div key={ ip }>{ ip }</div>
);
} else {
return null;
}
} else {
return null;
}
}
renderAppInfoTab() {
const releaseInfo = this.props.Settings.appInfo && this.props.Settings.appInfo.releaseInfo;
if (releaseInfo) {
return AppInfoTabRender.call(this);
return <AppInfoPanel />
}
return null;
}
renderAppUpdateTab() {
return AppUpdateTabRender.call(this);
return <AppUpdatePanel />
}
renderSNPeersList() {
if (this.state.getPeersCoin) {
const _getPeersCoin = this.state.getPeersCoin;
const _supernetPeers = this.props.Settings.supernetPeers;
const coin = _getPeersCoin.split('|')[0];
if (_supernetPeers &&
_getPeersCoin &&
_supernetPeers[coin]) {
return _supernetPeers[coin].map((ip) =>
<div key={ ip }>{ ip }</div>
);
} else {
return null;
}
} else {
return null;
}
renderWalletInfo() {
return <WalletInfoPanel />
}
updateInputSettings(e, parentKey, childKey) {
let _appSettings = this.state.appSettings;
let _appSettingsPrev = Object.assign({}, _appSettings);
if (!childKey && this.state.appConfigSchema[parentKey].type === 'boolean') {
_appSettings[parentKey] = typeof _appSettings[parentKey] !== undefined ? !_appSettings[parentKey] : !this.state.appSettings[parentKey];
} else if (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'boolean') {
_appSettings[parentKey][childKey] = typeof _appSettings[parentKey][childKey] !== undefined ? !_appSettings[parentKey][childKey] : !this.state.appSettings[parentKey][childKey];
} else if ((!childKey && this.state.appConfigSchema[parentKey].type === 'number') || (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'number')) {
if (e.target.value === '') {
_appSettings[e.target.name] = _appSettingsPrev[e.target.name];
} else {
_appSettings[e.target.name] = e.target.value.replace(/[^0-9]+/g, '');
}
} else {
_appSettings[e.target.name] = e.target.value;
}
this.setState({
appSettings: _appSettings,
});
renderAddNode() {
return <AddNodePanel />
}
_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];
}
}
if (!saveAfterPathCheck) {
Store.dispatch(saveAppConfig(_appSettingsPristine));
}
renderWalletBackup() {
return <WalletBackupPanel />
}
renderConfigEditForm() {
let items = [];
const _appConfig = this.state.appSettings;
for (let key in _appConfig) {
if (typeof _appConfig[key] === 'object') {
if (this.state.appConfigSchema[key].display) {
items.push(
<tr key={ `app-settings-${key}` }>
<td className="padding-15">
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key }
{ this.state.appConfigSchema[key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key].info }></i>
}
</td>
<td className="padding-15"></td>
</tr>
);
for (let _key in _appConfig[key]) {
items.push(
<tr key={ `app-settings-${key}-${_key}` }>
<td className="padding-15 padding-left-30">
{ this.state.appConfigSchema[key][_key].displayName ? this.state.appConfigSchema[key][_key].displayName : _key }
{ this.state.appConfigSchema[key][_key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key][_key].info }></i>
}
</td>
<td className="padding-15">
{ this.state.appConfigSchema[key][_key].type === 'number' &&
<input
type="number"
pattern="[0-9]*"
type="text"
name={ `${key}__${_key}` }
value={ _appConfig[key][_key] }
onChange={ (event) => this.updateInputSettings(event, key, _key) } />
}
{ (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' &&
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `${key}__${_key}` }
value={ _appConfig[key] }
checked={ _appConfig[key][_key] } />
<div
className="slider"
onClick={ (event) => this.updateInputSettings(event, key, _key) }></div>
</label>
</span>
}
</td>
</tr>
);
}
}
} else {
if (this.state.appConfigSchema[key].display) {
items.push(
<tr key={ `app-settings-${key}` }>
<td className="padding-15">
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key }
{ this.state.appConfigSchema[key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key].info }></i>
}
</td>
<td className="padding-15">
{ this.state.appConfigSchema[key].type === 'number' &&
<input
type="number"
pattern="[0-9]*"
name={ `${key}` }
value={ _appConfig[key] }
onChange={ (event) => this.updateInputSettings(event, key) } />
}
{ (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' &&
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `${key}` }
value={ _appConfig[key] }
checked={ _appConfig[key] } />
<div
className="slider"
onClick={ (event) => this.updateInputSettings(event, key) }></div>
</label>
</span>
}
</td>
</tr>
);
}
}
}
return items;
renderFiatCurrency() {
return <FiatCurrencyPanel />
}
updateInput(e) {
if (e.target.name === 'wifkeysPassphrase') {
// remove any empty chars from the start/end of the string
const newValue = e.target.value;
clearTimeout(this.state.trimPassphraseTimer);
const _trimPassphraseTimer = setTimeout(() => {
this.setState({
wifkeysPassphrase: newValue ? newValue.trim() : '', // hardcoded field name
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name]: newValue,
});
} else {
this.setState({
[e.target.name]: e.target.value,
});
}
renderExportKeys() {
return <ExportKeysPanel />
}
renderDebugLogData() {
if (this.props.Settings.debugLog) {
const _debugLogDataRows = this.props.Settings.debugLog.split('\n');
if (_debugLogDataRows &&
_debugLogDataRows.length) {
return _debugLogDataRows.map((_row) =>
<div
key={ `settings-debuglog-${Math.random(0, 9) * 10}` }
className="padding-bottom-5">{ _row }</div>
);
} else {
return (
<span>{ translate('INDEX.EMPTY_DEBUG_LOG') }</span>
);
}
} else {
return null;
}
renderImportKeys() {
return <ImportKeysPanel />
}
renderLB(_translationID) {
const _translationComponents = translate(_translationID).split('<br>');
return _translationComponents.map((_translation) =>
<span key={ `settings-label-${Math.random(0, 9) * 10}` }>
{ _translation }
<br />
</span>
);
renderDebugLog() {
return <DebugLogPanel />
}
// TODO: rerender only if prop is changed
renderCliResponse() {
const _cliResponse = this.props.Settings.cli;
let _items = [];
if (_cliResponse) {
let _cliResponseParsed;
let responseType;
try {
_cliResponseParsed = JSON.parse(_cliResponse.result);
} catch(e) {
_cliResponseParsed = _cliResponse.result;
}
if (Object.prototype.toString.call(_cliResponseParsed) === '[object Array]') {
responseType = 'array';
for (let i = 0; i < _cliResponseParsed.length; i++) {
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed[i], null, '\t') }</div>
);
}
}
if (Object.prototype.toString.call(_cliResponseParsed) === '[object]' ||
typeof _cliResponseParsed === 'object') {
responseType = 'object';
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed, null, '\t') }</div>
);
}
if (Object.prototype.toString.call(_cliResponseParsed) === 'number' ||
typeof _cliResponseParsed === 'boolean' ||
_cliResponseParsed === 'wrong cli string format') {
responseType = 'number';
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed.toString() }</div>
);
}
if (responseType !== 'number' &&
responseType !== 'array' &&
responseType !== 'object' &&
_cliResponseParsed.indexOf('\n') > -1) {
_cliResponseParsed = _cliResponseParsed.split('\n');
for (let i = 0; i < _cliResponseParsed.length; i++) {
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed[i] }</div>
);
}
}
return (
<div>
<div>
<strong>{ translate('SETTINGS.CLI_RESPONSE') }:</strong>
</div>
{ _items }
</div>
);
} else {
return null;
}
renderAppSettings() {
return <AppSettingsPanel />
}
renderActiveCoinsList(mode) {
const modes = [
'native',
'basilisk',
'full'
];
const allCoins = this.props.Main.coins;
let items = [];
if (allCoins) {
if (mode === 'all') {
modes.map(function(mode) {
allCoins[mode].map(function(coin) {
items.push(
<option
value={ coin }
key={ coin }>
{ coin } ({ mode })
</option>
);
});
});
} else {
allCoins[mode].map(function(coin) {
items.push(
<option
value={ coin }
key={ coin }>
{ coin } ({ mode })
</option>
);
});
}
return items;
} else {
return null;
}
}
renderExportWifKeysRaw() {
const _wifKeysResponse = this.props.Settings.wifkey;
if (_wifKeysResponse &&
this.state.exportWifKeysRaw) {
return (
<div className="padding-bottom-30 padding-top-30">
{ JSON.stringify(_wifKeysResponse, null, '\t') }
</div>
);
} else {
return null;
}
}
renderWifKeys() {
let items = [];
if (this.props.Settings.wifkey) {
const _wifKeys = this.props.Settings.wifkey;
for (let i = 0; i < 2; i++) {
items.push(
<tr key={ `wif-export-table-header-${i}` }>
<td className="padding-bottom-10 padding-top-10">
<strong>{ i === 0 ? translate('SETTINGS.ADDRESS_LIST') : translate('SETTINGS.WIF_KEY_LIST') }</strong>
</td>
<td className="padding-bottom-10 padding-top-10"></td>
</tr>
);
for (let _key in _wifKeys) {
if ((i === 0 && _key.length === 3 && _key !== 'tag') ||
(i === 1 && _key.indexOf('wif') > -1)) {
items.push(
<tr key={ _key }>
<td>{ _key }</td>
<td className="padding-left-15">{ _wifKeys[_key] }</td>
</tr>
);
}
}
}
return items;
} else {
return null;
}
renderCliPanel() {
return <CliPanel />
}
exportWifKeysRaw() {
this.setState(Object.assign({}, this.state, {
exportWifKeysRaw: !this.state.exportWifKeysRaw,
}));
renderSupportPanel() {
return <SupportPanel />
}
render() {
@ -846,4 +142,18 @@ class Settings extends React.Component {
}
}
export default Settings;
const mapStateToProps = (state) => {
return {
Main: {
coins: state.Main.coins,
activeHandle: state.Main.activeHandle,
},
ActiveCoin: {
coin: state.ActiveCoin.coin,
},
Settings: state.Settings,
Dashboard: state.Dashboard,
};
};
export default connect(mapStateToProps)(Settings);

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

@ -1,146 +1,5 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import AddCoinOptionsCrypto from '../../addcoin/addcoinOptionsCrypto';
import AddCoinOptionsAC from '../../addcoin/addcoinOptionsAC';
import AddCoinOptionsACFiat from '../../addcoin/addcoinOptionsACFiat';
export const AppUpdateTabRender = function() {
return (
<div
className="panel"
id="AppUpdate"
onClick={ () => this.openTab('AppUpdate', 10) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 10 ? '' : ' collapsed') }>
<i className="icon fa fa-cloud-download"></i> { translate('INDEX.UPDATE') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 10 ? ' in' : '') }
style={{ height: this.state.activeTab === 10 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div className="col-sm-4 padding-top-15">
<h5>{ translate('INDEX.UI_UPDATE') }</h5>
<div className="padding-top-15">
<button
type="button"
className="btn btn-info waves-effect waves-light"
onClick={ this._checkForUpdateUIPromise }>{ translate('INDEX.CHECK_FOR_UPDATE') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-20"
onClick={ this._updateUIPromise }
disabled={ !this.state.updatePatch }>{ translate('INDEX.UPDATE_UI_NOW') }</button>
</div>
</div>
<div className="col-sm-4 padding-top-15 hide">
<h5>{ translate('INDEX.BINS_UPDATE') }</h5>
<div className="padding-top-15">
<button
type="button"
className="btn btn-info waves-effect waves-light"
onClick={ this._checkForUpdateUIPromise }>{ translate('INDEX.CHECK_FOR_UPDATE') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-20"
onClick={ this.checkNodes }>{ translate('INDEX.UPDATE_BINS_NOW') }</button>
</div>
</div>
<div className="col-sm-12 padding-top-15">
{ this.renderUpdateStatus() }
</div>
</div>
</div>
</div>
);
};
export const AppInfoTabRender = function() {
return (
<div
className="panel"
id="AppInfo"
onClick={ () => this.openTab('AppInfo', 8) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 8 ? '' : ' collapsed') }>
<i className="icon md-info"></i>{ translate('SETTINGS.APP_INFO') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 8 ? ' in' : '') }
style={{ height: this.state.activeTab === 8 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div className="col-sm-12 padding-top-15">
<div className="row">
<h5>{ translate('SETTINGS.APP_RELEASE') }</h5>
<div>
{ translate('SETTINGS.NAME') }: { this.props.Settings.appInfo.releaseInfo.name }
</div>
<div>
{ translate('SETTINGS.VERSION') }: { `${this.props.Settings.appInfo.releaseInfo.version.replace('version=', '')}-beta` }
</div>
<div>
{ translate('SETTINGS.APP_SESSION') }: { this.props.Settings.appInfo.appSession }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
<h5>{ translate('SETTINGS.SYS_INFO') }</h5>
<div>
{ translate('SETTINGS.ARCH') }: { this.props.Settings.appInfo.sysInfo.arch }
</div>
<div>
{ translate('SETTINGS.OS_TYPE') }: { this.props.Settings.appInfo.sysInfo.os_type }
</div>
<div>
{ translate('SETTINGS.OS_PLATFORM') }: { this.props.Settings.appInfo.sysInfo.platform }
</div>
<div>
{ translate('SETTINGS.OS_RELEASE') }: { this.props.Settings.appInfo.sysInfo.os_release }
</div>
<div>
{ translate('SETTINGS.CPU') }: { this.props.Settings.appInfo.sysInfo.cpu }
</div>
<div>
{ translate('SETTINGS.CPU_CORES') }: { this.props.Settings.appInfo.sysInfo.cpu_cores }
</div>
<div>
{ translate('SETTINGS.MEM') }: { this.props.Settings.appInfo.sysInfo.totalmem_readable }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
<h5>{ translate('SETTINGS.LOCATIONS') }</h5>
<div>
{ translate('SETTINGS.CACHE') }: { this.props.Settings.appInfo.dirs.cacheLocation }
</div>
<div>
{ translate('SETTINGS.CONFIG') }: { this.props.Settings.appInfo.dirs.configLocation }
</div>
<div>
Iguana { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.iguanaBin }
</div>
<div>
Iguana { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.iguanaDir }
</div>
<div>
Komodo { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.komododBin }
</div>
<div>
Komodo { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
<div>
Komodo wallet.dat: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export const SettingsRender = function() {
return (
@ -156,6 +15,7 @@ export const SettingsRender = function() {
<div
className="panel-group"
id="SettingsAccordion">
{ !this.props.disableWalletSpecificUI &&
<div
id="WalletInfo"
@ -168,43 +28,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 0 ? ' in' : '') }
style={{ height: this.state.activeTab === 0 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<table className="table">
<thead>
<tr>
<th width="10%">{ translate('INDEX.KEY') }</th>
<th>{ translate('INDEX.VALUE') }</th>
</tr>
</thead>
<tbody>
<tr>
<td className="wallet-info-key">pubkey</td>
<td>{ this.props.Main.activeHandle.pubkey }</td>
</tr>
<tr>
<td className="wallet-info-key">btcpubkey</td>
<td>{ this.props.Main.activeHandle.btcpubkey }</td>
</tr>
<tr>
<td className="wallet-info-key">rmd160</td>
<td>{ this.props.Main.activeHandle.rmd160 }</td>
</tr>
<tr>
<td className="wallet-info-key">NXT</td>
<td>{ this.props.Main.activeHandle.NXT }</td>
</tr>
<tr>
<td className="wallet-info-key">notary</td>
<td>{ this.props.Main.activeHandle.notary }</td>
</tr>
<tr>
<td className="wallet-info-key">status</td>
<td>{ this.props.Main.activeHandle.status }</td>
</tr>
</tbody>
</table>
</div>
style={{ height: this.state.activeTab === 0 ? `auto` : '0' }}>
{ this.renderWalletInfo() }
</div>
</div>
}
@ -220,78 +45,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 1 ? ' in' : '') }
style={{ height: this.state.activeTab === 1 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div className="row">
<div className="col-sm-6">
<div className="col-sm-12">
<p>{ translate('INDEX.USE_THIS_SECTION') }</p>
</div>
<div className="col-sm-8 col-xs-12">
<div className="form-group">
<select
className="form-control form-material"
name="getPeersCoin"
onChange={ this.updateInput }>
<option>{ translate('INDEX.SELECT_COIN') }</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
</div>
<div className="col-sm-4 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.checkNodes }>{ translate('INDEX.CHECK_NODES') }</button>
</div>
<div className="col-sm-12">
<h5>
SuperNET Peers:
</h5>
<p>{ this.renderSNPeersList() }</p>
<h5>
Raw Peers:
</h5>
<p>{ this.renderPeersList() }</p>
</div>
</div>
<div className="col-sm-6">
<div className="col-sm-12">
<p>{ translate('INDEX.USE_THIS_SECTION_PEER') }</p>
</div>
<div className="col-sm-8 col-xs-12">
<div className="form-group">
<select
className="form-control form-material"
name="addNodeCoin"
onChange={ this.updateInput }>
<option>{ translate('INDEX.SELECT_COIN') }</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
<div className="form-group">
<input
type="text"
className="form-control"
name="addPeerIP"
placeholder={ translate('SETTINGS.ADD_PEER_IP') }
onChange={ this.updateInput } />
</div>
</div>
<div className="col-sm-4 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.addNode }>{ translate('INDEX.ADD_NODE') }</button>
</div>
</div>
</div>
</div>
style={{ height: this.state.activeTab === 1 ? `auto` : '0' }}>
{ this.renderAddNode() }
</div>
</div>
}
@ -299,7 +54,7 @@ export const SettingsRender = function() {
<div
id="DumpWallet"
onClick={ () => this.openTab('DumpWallet', 2) }
className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }>
className={ 'hide panel' + (this.state.nativeOnly ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 2 ? '' : ' collapsed') }>
<i className="icon wb-briefcase"></i>{ translate('INDEX.WALLET_BACKUP') }
@ -307,8 +62,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 2 ? ' in' : '') }
style={{ height: this.state.activeTab === 2 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">Wallet Backup section to be updated soon.</div>
style={{ height: this.state.activeTab === 2 ? `auto` : '0' }}>
{ this.renderWalletBackup() }
</div>
</div>
}
@ -316,7 +71,7 @@ export const SettingsRender = function() {
<div
id="FiatCurrencySettings"
onClick={ () => this.openTab('FiatCurrencySettings', 3) }
className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }>
className={ 'hide panel' + (this.state.nativeOnly ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 3 ? '' : ' collapsed') }>
<i className="icon fa-money"></i>{ translate('INDEX.FIAT_CURRENCY') }
@ -324,8 +79,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 3 ? ' in' : '') }
style={{ height: this.state.activeTab === 3 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">Fiat currency settings section to be updated soon.</div>
style={{ height: this.state.activeTab === 3 ? `auto` : '0' }}>
{ this.renderFiatCurrency() }
</div>
</div>
}
@ -341,69 +96,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 4 ? ' in' : '') }
style={{ height: this.state.activeTab === 4 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div>
<div className="padding-bottom-20">{ this.renderLB('INDEX.ONLY_ACTIVE_WIF_KEYS') }</div>
<div className="padding-bottom-20">
<i>{ this.renderLB('SETTINGS.EXPORT_KEYS_NOTE') }</i>
</div>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
<form
className="wifkeys-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="password"
className={ !this.state.seedInputVisibility ? 'form-control' : 'hide' }
name="wifkeysPassphrase"
id="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase } />
<textarea
className={ this.state.seedInputVisibility ? 'form-control' : 'hide' }
id="wifkeysPassphraseTextarea"
name="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase }></textarea>
<i
className={ 'seed-toggle fa fa-eye' + (!this.state.seedInputVisibility ? '-slash' : '') }
onClick={ this.toggleSeedInputVisibility }></i>
<label
className="floating-label"
htmlFor="wifkeysPassphrase">{ translate('INDEX.PASSPHRASE') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.exportWifKeys }>{ translate('INDEX.GET_WIF_KEYS') }</button>
</div>
</form>
<div className="col-sm-12 padding-top-15">
<div className="row">
<table className="table">
{ this.renderWifKeys() }
</table>
<div className={ this.props.Settings.wifkey ? 'col-sm-12 col-xs-12 text-align-center' : 'hide' }>
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.exportWifKeysRaw }>{ this.state.exportWifKeysRaw ? 'Hide' : 'Show' } raw data</button>
</div>
<div className={ this.state.exportWifKeysRaw ? 'col-sm-12 col-xs-12 text-align-center' : 'hide' }>
{ this.renderExportWifKeysRaw() }
</div>
</div>
</div>
</div>
style={{ height: this.state.activeTab === 4 ? `auto` : '0' }}>
{ this.renderExportKeys() }
</div>
</div>
}
@ -419,41 +113,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 5 ? ' in' : '') }
style={{ height: this.state.activeTab === 5 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P1') }</div><br/>
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P2') }</div><br/>
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P3') }</div><br/>
<div>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
<form
className="wifkeys-import-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="text"
className="form-control"
name="importWifKey"
id="importWifkey"
onChange={ this.updateInput } />
<label
className="floating-label"
htmlFor="importWifkey">{ translate('INDEX.INPUT_PRIV_KEY') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.importWifKey }>{ translate('INDEX.IMPORT_PRIV_KEY') }</button>
</div>
</form>
</div>
style={{ height: this.state.activeTab === 5 ? `auto` : '0' }}>
{ this.renderImportKeys() }
</div>
</div>
}
@ -469,51 +130,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 6 ? ' in' : '') }
style={{ height: this.state.activeTab === 6 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<p>{ translate('INDEX.DEBUG_LOG_DESC') }</p>
<div className="col-sm-12"></div>
<form
className="read-debug-log-import-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="text"
className="form-control"
name="debugLinesCount"
id="readDebugLogLines"
value={ this.state.debugLinesCount }
onChange={ this.updateInput } />
<label
className="floating-label"
htmlFor="readDebugLogLines">{ translate('INDEX.DEBUG_LOG_LINES') }</label>
</div>
<div className="form-group form-material floating">
<select
className="form-control form-material"
name="debugTarget"
id="settingsDelectDebugLogOptions"
onChange={ this.updateInput }>
<option value="iguana" className={ this.state.nativeOnly ? 'hide' : '' }>Iguana</option>
<option value="komodo">Komodo</option>
</select>
<label
className="floating-label"
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.TARGET') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.readDebugLog }>{ translate('INDEX.LOAD_DEBUG_LOG') }</button>
</div>
<div className="col-sm-12 col-xs-12 text-align-left">
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">{ this.renderDebugLogData() }</div>
</div>
</form>
</div>
style={{ height: this.state.activeTab === 6 ? `auto` : '0' }}>
{ this.renderDebugLog() }
</div>
</div>
@ -528,32 +146,26 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 7 ? ' in' : '') }
style={{ height: this.state.activeTab === 7 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<p>
<strong>{ translate('SETTINGS.CONFIG_RESTART_REQUIRED') }</strong>
</p>
<div className="col-sm-12 padding-top-15">
<table>
<tbody>
{ this.renderConfigEditForm() }
</tbody>
</table>
</div>
<div className="col-sm-12 col-xs-12 text-align-center padding-top-35 padding-bottom-30">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this._saveAppConfig }>{ translate('SETTINGS.SAVE_APP_CONFIG') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-30"
onClick={ this._resetAppConfig }>Reset to default</button>
</div>
</div>
style={{ height: this.state.activeTab === 7 ? `auto` : '0' }}>
{ this.renderAppSettings() }
</div>
</div>
<div
className="panel"
id="AppInfo"
onClick={ () => this.openTab('AppInfo', 8) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 8 ? '' : ' collapsed') }>
<i className="icon md-info"></i>{ translate('SETTINGS.APP_INFO') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 8 ? ' in' : '') }
style={{ height: this.state.activeTab === 8 ? `auto` : '0' }}>
{ this.renderAppInfoTab() }
</div>
</div>
{ this.renderAppInfoTab() }
{ this.props.Main && this.props.Main.coins.native &&
<div
@ -567,59 +179,27 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 9 ? ' in' : '') }
style={{ height: this.state.activeTab === 9 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<p>{ translate('INDEX.CLI_SELECT_A_COIN') }</p>
<div className="col-sm-12"></div>
<form
className="execute-cli-cmd-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<select
className="form-control form-material"
name="cliCoin"
id="settingsCliOptions"
onChange={ this.updateInput }>
<option>{ translate('INDEX.CLI_NATIVE_COIN') }</option>
{ this.renderActiveCoinsList('native') }
</select>
<label
className="floating-label"
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.COIN') }</label>
</div>
<div className="form-group form-material floating">
<textarea
type="text"
className="form-control"
name="cliCmdString"
id="cliCmd"
value={ this.state.cliCmdString }
onChange={ this.updateInput }></textarea>
<label
className="floating-label"
htmlFor="readDebugLogLines">{ translate('INDEX.TYPE_CLI_CMD') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
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">
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">
{ this.renderCliResponse() }
</div>
</div>
</form>
</div>
style={{ height: this.state.activeTab === 9 ? `auto` : '0' }}>
{ this.renderCliPanel() }
</div>
</div>
}
{ this.renderAppUpdateTab() }
<div
className="panel"
id="AppUpdate"
onClick={ () => this.openTab('AppUpdate', 10) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 10 ? '' : ' collapsed') }>
<i className="icon fa fa-cloud-download"></i> { translate('INDEX.UPDATE') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 10 ? ' in' : '') }
style={{ height: this.state.activeTab === 10 ? `auto` : '0' }}>
{ this.renderAppUpdateTab() }
</div>
</div>
<div
className="panel"
@ -632,55 +212,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 11 ? ' in' : '') }
style={{ height: this.state.activeTab === 11 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div className="col-sm-12 no-padding-left">
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('http://support.supernet.org') }>
<img
src="assets/images/cryptologo/supernet.png"
alt="Support tickets" />
<div className="support-box-title">{ translate('SETTINGS.SUPPORT_TICKETS') }</div>
<div className="support-box-link">support.supernet.org</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('https://sprnt.slack.com') }>
<img
src="assets/images/support/slack-icon.png"
alt="Slack" />
<div className="support-box-title">Slack</div>
<div className="support-box-link">sprnt.slack.com</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('http://slackinvite.supernet.org') }>
<img
src="assets/images/support/slack-invite-icon.png"
alt="Slack invite" />
<div className="support-box-title">{ translate('SETTINGS.GET_SLACK_INVITE') }</div>
<div className="support-box-link">slackinvite.supernet.org</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('https://github.com/SuperNETorg/Agama') }>
<img
src="assets/images/support/github-icon.png"
alt="Github" />
<div className="support-box-title">Github</div>
<div className="support-box-link">github.com/SuperNETorg/Agama</div>
</div>
</div>
</div>
</div>
style={{ height: this.state.activeTab === 11 ? `auto` : '0' }}>
{ this.renderSupportPanel() }
</div>
</div>
</div>

121
react/src/components/dashboard/settings/settings.scss

@ -0,0 +1,121 @@
.support-box {
padding: 15px 20px;
width: 220px;
display: inline-block;
cursor: pointer;
&-title {
font-weight: bold;
padding-top: 12px;
padding-bottom: 3px;
}
img {
height: 50px;
}
}
.support-box-wrapper {
display: inline-block;
margin-right: 50px;
&:last-child, {
margin-right: 0;
}
}
.support-box:hover {
.support-box-link {
color: #5683ad;
font-weight: 500;
}
}
.login-settings-modal {
#AppUpdate {
.col-sm-4 {
width: 100%;
}
}
.modal-dialog {
width: 80%;
}
.modal-body {
background: #f3f4f5;
border-radius: 4px;
}
.modal-footer {
margin-top: 15px;
}
.page-content {
padding-top: 0;
}
.support-box-wrapper {
.support-box {
margin: 0;
margin-bottom: 20px;
}
}
}
.settings-help {
font-size: 20px;
position: relative;
top: 2px;
left: 10px;
color: #5683ad;
}
#SettingsAccordion {
.toggle {
position: relative;
top: 4px;
.title {
position: relative;
top: -12px;
left: 12px;
}
}
table {
width: 100%;
td {
&:first-child {
width: 40%;
}
&:last-child {
width: 60%;
}
}
}
}
#SettingsAccordion {
.panel {
.panel-collapse {
transition: all .3s;
&.collapse {
height: 0;
}
}
}
}
#section-iguana-wallet-settings {
background: #f3f4f5;
.panel-title {
cursor: pointer;
cursor: hand;
&:before {
content: '\F273';
}
&.collapsed {
&:before {
content: '\F278';
}
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save