Browse Source

Merge pull request #176 from SuperNETorg/redux

Redux
v0.25
pbca26 7 years ago
committed by GitHub
parent
commit
192372766d
  1. 8
      react/src/actions/actionCreators.js
  2. 110
      react/src/actions/actions/pin.js
  3. 1
      react/src/actions/storeType.js
  4. 1
      react/src/components/app/app.js
  5. 32
      react/src/components/dashboard/bodyBottom/bodyBottom.js
  6. 140
      react/src/components/dashboard/invoiceModal/invoiceModal.js
  7. 107
      react/src/components/dashboard/invoiceModal/invoiceModal.render.js
  8. 10
      react/src/components/dashboard/qrModal/qrModal.js
  9. 3
      react/src/components/dashboard/receiveCoin/receiveCoin.render.js
  10. 22
      react/src/components/dashboard/sendCoin/sendCoin.js
  11. 2
      react/src/components/dashboard/settings/settings.addNodePanel.js
  12. 72
      react/src/components/dashboard/settings/settings.appInfoPanel.js
  13. 8
      react/src/components/dashboard/settings/settings.appSettingsPanel.js
  14. 2
      react/src/components/dashboard/settings/settings.appUpdatePanel.js
  15. 5
      react/src/components/dashboard/settings/settings.cliPanel.js
  16. 6
      react/src/components/dashboard/settings/settings.debugLogPanel.js
  17. 12
      react/src/components/dashboard/settings/settings.exportKeysPanel.js
  18. 6
      react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js
  19. 17
      react/src/components/dashboard/settings/settings.importKeysPanel.js
  20. 113
      react/src/components/dashboard/settings/settings.js
  21. 86
      react/src/components/dashboard/settings/settings.panel.js
  22. 89
      react/src/components/dashboard/settings/settings.panelBody.js
  23. 48
      react/src/components/dashboard/settings/settings.panelUtils.js
  24. 284
      react/src/components/dashboard/settings/settings.render.js
  25. 30
      react/src/components/dashboard/settings/settings.scss
  26. 2
      react/src/components/dashboard/settings/settings.supportPanel.js
  27. 6
      react/src/components/dashboard/settings/settings.walletBackupPanel.js
  28. 2
      react/src/components/dashboard/settings/settings.walletInfoPanel.js
  29. 29
      react/src/components/dashboard/walletsNativeSend/walletsNativeSend.js
  30. 70
      react/src/components/login/login.js
  31. 93
      react/src/components/login/login.render.js
  32. 5
      react/src/components/login/login.scss
  33. 2
      react/src/reducers/index.js
  34. 18
      react/src/reducers/login.js
  35. 8
      react/src/translate/en.js

8
react/src/actions/actionCreators.js

@ -29,6 +29,7 @@ import {
DISPLAY_CLAIM_INTEREST_MODAL,
START_INTERVAL,
STOP_INTERVAL,
GET_PIN_LIST,
DASHBOARD_SYNC_ONLY_UPDATE,
DISPLAY_IMPORT_KEY_MODAL,
} from './storeType';
@ -345,6 +346,13 @@ export function toggleClaimInterestModal(display) {
}
}
export function getPinList(pinList) {
return {
type: GET_PIN_LIST,
pinList: pinList,
}
}
export function skipFullDashboardUpdate(skip) {
return {
type: DASHBOARD_SYNC_ONLY_UPDATE,

110
react/src/actions/actions/pin.js

@ -0,0 +1,110 @@
import Config from '../../config';
import {
getDecryptedPassphrase,
getPinList,
triggerToaster
} from '../actionCreators';
import { iguanaWalletPassphrase } from './walletAuth';
export function encryptPassphrase(passphrase, key, pubKey) {
const payload = {
string: passphrase,
key: key,
pubkey: pubKey,
};
return dispatch => {
return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/encryptkey`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
.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,
};
return dispatch => {
return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/decryptkey`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'decryptKey',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
dispatch(iguanaWalletPassphrase(json.result));
})
}
}
export function loadPinList() {
return dispatch => {
return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/getpinlist`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.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)
);
})
}
}

1
react/src/actions/storeType.js

@ -46,4 +46,5 @@ 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 DISPLAY_IMPORT_KEY_MODAL = 'DISPLAY_IMPORT_KEY_MODAL';

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

@ -5,6 +5,7 @@ import Main from '../main/main';
function mapStateToProps(state) {
return {
login: state.login,
toaster: state.toaster,
AddCoin: state.AddCoin,
Main: state.Main,

32
react/src/components/dashboard/bodyBottom/bodyBottom.js

@ -0,0 +1,32 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
export default class BodyEnd extends React.PureComponent {
static propTypes = {
children: PropTypes.node,
};
componentDidMount() {
this._popup = document.createElement('div');
document.body.appendChild(this._popup);
this._render();
}
componentDidUpdate() {
this._render();
}
componentWillUnmount() {
ReactDOM.unmountComponentAtNode(this._popup);
document.body.removeChild(this._popup);
}
_render() {
ReactDOM.render(this.props.children, this._popup);
}
render() {
return null;
}
}

140
react/src/components/dashboard/invoiceModal/invoiceModal.js

@ -0,0 +1,140 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import Store from '../../../store';
import { translate } from '../../../translate/translate';
import BodyEnd from '../bodyBottom/bodyBottom';
import {
InvoiceModalRender,
InvoiceModalButtonRender,
AddressItemRender,
} from './invoiceModal.render';
class InvoiceModal extends React.Component {
constructor() {
super();
this.state = {
modalIsOpen: false,
content: '',
qrAddress: '',
qrAmount: 0,
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.updateInput = this.updateInput.bind(this);
this.renderAddressList = this.renderAddressList.bind(this);
this.updateQRContent = this.updateQRContent.bind(this);
}
openModal() {
this.setState({
modalIsOpen: true
});
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value
}, this.updateQRContent);
}
updateQRContent() {
this.setState({
content: JSON.stringify({
address: this.state.qrAddress,
amount: this.state.qrAmount,
coin: this.props.ActiveCoin.coin,
}),
});
}
closeModal() {
this.setState({
modalIsOpen: false,
});
}
hasNoAmount(address) {
return address.amount === 'N/A' || address.amount === 0;
}
hasNoInterest(address) {
return address.interest === 'N/A' || address.interest === 0 || !address.interest;
}
isBasiliskMode() {
return this.props.ActiveCoin.mode === 'basilisk';
}
isNativeMode() {
return this.props.ActiveCoin.mode == 'native';
}
renderAddressList(type) {
const _addresses = this.props.ActiveCoin.addresses;
const _cache = this.props.ActiveCoin.cache;
const _coin = this.props.ActiveCoin.coin;
if (_addresses &&
_addresses[type] &&
_addresses[type].length) {
let items = [];
for (let i = 0; i < _addresses[type].length; i++) {
let address = _addresses[type][i];
if (this.isBasiliskMode() &&
this.hasNoAmount(address)) {
address.amount = _cache && _cache[_coin][address.address] &&
_cache[_coin][address.address].getbalance &&
_cache[_coin][address.address].getbalance.data &&
_cache[_coin][address.address].getbalance.data.balance ? _cache[_coin][address.address].getbalance.data.balance : 'N/A';
}
if (this.isBasiliskMode() &&
this.hasNoInterest(address)) {
address.interest = _cache && _cache[_coin][address.address] &&
_cache[_coin][address.address].getbalance &&
_cache[_coin][address.address].getbalance.data &&
_cache[_coin][address.address].getbalance.data.interest ? _cache[_coin][address.address].getbalance.data.interest : 'N/A';
}
items.push(
AddressItemRender.call(this, address, type)
);
}
return items;
} else {
return null;
}
}
render() {
if (this.state.modalIsOpen) {
return <BodyEnd>{ InvoiceModalRender.call(this) }</BodyEnd>
} else {
return InvoiceModalButtonRender.call(this);
}
}
}
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)(InvoiceModal);

107
react/src/components/dashboard/invoiceModal/invoiceModal.render.js

@ -0,0 +1,107 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import QRCode from 'qrcode.react';
export const InvoiceModalRender = function () {
return (
<span>
<div
className={ 'modal modal-3d-sign ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }
id="QRModal">
<div className="modal-dialog modal-center modal-lg">
<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.CREATE_INVOICE_QR') }</h4>
</div>
<div className="modal-body">
<div className="animsition fade-in">
<div className="page-content">
<div className="row">
<div className="col-lg-8 form-group form-material vertical-align-middle">
<form>
<label
className="control-label"
htmlFor="qrAddress">
{ translate('INDEX.RECEIVING_ADDRESS') }
</label>
<select
className="form-control"
name="qrAddress"
id="qrAddress"
value={ this.state.qrAddress }
onChange={ this.updateInput }>
<option value="-1">
{ translate('INDEX.CHOOSE_RECEIVING_ADDRESS') }
</option>
{ this.renderAddressList('public') }
{ this.isNativeMode() && this.renderAddressList('private') }
</select>
<label
className="control-label margin-top-20"
htmlFor="qrCoinAmount">
{ this.props.ActiveCoin.coin }
</label>
<input
type="number"
min="0"
className="form-control"
id="qrCoinAmount"
name="qrAmount"
placeholder="0"
autoComplete="off"
value={ this.state.qrAmount }
onChange={ this.updateInput } />
</form>
</div>
<div className="col-lg-4">
<QRCode
value={ this.state.content }
size={ 198 } />
</div>
</div>
<div className="row hide">
<div className="col-lg-12">
<p className="help-block">
{ translate('INDEX.QR_CONTENT') }:<br />
{ this.state.content }
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className={ 'modal-backdrop ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }></div>
</span>
);
};
export const InvoiceModalButtonRender = function () {
return (
<span>
<button type="button"
className="btn btn-success waves-effect waves-light margin-right-10"
onClick={ this.openModal }>
<i className="icon fa-file-text-o"></i>&nbsp;
{ translate('INDEX.CREATE_INVOICE') }
</button>
</span>
);
};
export const AddressItemRender = function(address, type) {
return (
<option key={ address.address } value={ address.address }>
{ type === 'public' ? address.address : `${address.address.substring(0, 34)}...` }
&nbsp; (Balance: { address.amount })
</option>
);
};

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

@ -33,16 +33,10 @@ class QRModal extends React.Component {
}
handleError(err) {
if (err.name === 'NoVideoInputDevicesError') {
this.setState({
error: translate('DASHBOARD.QR_ERR_NO_VIDEO_DEVICE'),
});
} else {
this.setState({
error: translate('DASHBOARD.QR_ERR_UNKNOWN'),
error: err.name === 'NoVideoInputDevicesError' ? translate('DASHBOARD.QR_ERR_NO_VIDEO_DEVICE') : translate('DASHBOARD.QR_ERR_UNKNOWN'),
});
}
}
openModal() {
this.setState({
@ -68,6 +62,8 @@ class QRModal extends React.Component {
modalIsOpen: false,
errorShown: this.state.error ? true : false,
});
ReactDOM.unmountComponentAtNode(document.getElementById('webcam'));
}
render() {

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

@ -1,6 +1,7 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import QRModal from '../qrModal/qrModal';
import InvoiceModal from '../invoiceModal/invoiceModal';
export const AddressActionsBasiliskModeRender = function(address) {
return (
@ -69,6 +70,7 @@ export const _ReceiveCoinTableRender = function() {
<label className="switch">
<input
type="checkbox"
value="on"
checked={ this.state.hideZeroAddresses } />
<div
className="slider"
@ -139,6 +141,7 @@ export const ReceiveCoinRender = function() {
<header className="panel-heading">
{ this.isNativeMode() &&
<div className="panel-actions">
<InvoiceModal />
<div
className={ 'dropdown' + (this.state.openDropMenu ? ' open' : '') }
onClick={ this.openDropMenu }>

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

@ -67,9 +67,29 @@ class SendCoin extends React.Component {
}
setRecieverFromScan(receiver) {
try {
const recObj = JSON.parse(receiver);
if (recObj &&
typeof recObj === 'object') {
if (recObj.coin === this.props.ActiveCoin.coin) {
if (recObj.amount) {
this.setState({
amount: recObj.amount,
});
}
if (recObj.address) {
this.setState({
sendTo: recObj.address,
});
}
}
}
} catch (e) {
this.setState({
sendTo: receiver
sendTo: receiver,
});
}
document.getElementById('edexcoinSendTo').focus();
}

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

@ -96,7 +96,6 @@ class AddNodePanel extends React.Component {
render() {
return (
<div className="panel-body">
<div className="row">
<div className="col-sm-6">
<div className="col-sm-12">
@ -166,7 +165,6 @@ class AddNodePanel extends React.Component {
</div>
</div>
</div>
</div>
);
};
}

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

@ -8,76 +8,58 @@ class AppInfoPanel extends React.Component {
}
render() {
const releaseInfo = this.props.Settings.appInfo && this.props.Settings.appInfo.releaseInfo;
if (!releaseInfo) {
return null
} else {
return (
<div className="panel-body">
<div className="col-sm-12 padding-top-15">
<div className="row">
<div className="col-sm-12 padding-top-15">
<h5>{ translate('SETTINGS.APP_RELEASE') }</h5>
<div>
<p>
{ translate('SETTINGS.NAME') }: { this.props.Settings.appInfo.releaseInfo.name }
</div>
<div>
<br />
{ translate('SETTINGS.VERSION') }: { `${this.props.Settings.appInfo.releaseInfo.version.replace('version=', '')}-beta` }
</div>
<div>
<br />
{ translate('SETTINGS.APP_SESSION') }: { this.props.Settings.appInfo.appSession }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
</p>
<h5>{ translate('SETTINGS.SYS_INFO') }</h5>
<div>
<p>
{ translate('SETTINGS.ARCH') }: { this.props.Settings.appInfo.sysInfo.arch }
</div>
<div>
<br />
{ translate('SETTINGS.OS_TYPE') }: { this.props.Settings.appInfo.sysInfo.os_type }
</div>
<div>
<br />
{ translate('SETTINGS.OS_PLATFORM') }: { this.props.Settings.appInfo.sysInfo.platform }
</div>
<div>
<br />
{ translate('SETTINGS.OS_RELEASE') }: { this.props.Settings.appInfo.sysInfo.os_release }
</div>
<div>
<br />
{ translate('SETTINGS.CPU') }: { this.props.Settings.appInfo.sysInfo.cpu }
</div>
<div>
<br />
{ translate('SETTINGS.CPU_CORES') }: { this.props.Settings.appInfo.sysInfo.cpu_cores }
</div>
<div>
<br />
{ translate('SETTINGS.MEM') }: { this.props.Settings.appInfo.sysInfo.totalmem_readable }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
</p>
<h5>{ translate('SETTINGS.LOCATIONS') }</h5>
<div>
<p>
{ translate('SETTINGS.CACHE') }: { this.props.Settings.appInfo.dirs.cacheLocation }
</div>
<div>
<br />
{ translate('SETTINGS.CONFIG') }: { this.props.Settings.appInfo.dirs.configLocation }
</div>
<div>
<br />
Iguana { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.iguanaBin }
</div>
<div>
<br />
Iguana { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.iguanaDir }
</div>
<div>
<br />
Komodo { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.komododBin }
</div>
<div>
<br />
Komodo { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
<div>
<br />
Komodo wallet.dat: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
</div>
</p>
</div>
</div>
);
}
};
}

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

@ -283,17 +283,20 @@ class AppSettingsPanel extends React.Component {
render() {
return (
<div className="panel-body">
<div>
<div className="row">
<div className="col-sm-12 padding-top-15">
<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>
<div className="row">
<div className="col-sm-12 col-xs-12 text-align-center padding-top-35 padding-bottom-30">
<button
type="button"
@ -305,6 +308,7 @@ class AppSettingsPanel extends React.Component {
onClick={ this._resetAppConfig }>Reset to default</button>
</div>
</div>
</div>
);
};
}

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

@ -107,7 +107,7 @@ class AppUpdatePanel extends React.Component {
render() {
return (
<div className="panel-body">
<div className="row">
<div className="col-sm-4 padding-top-15">
<h5>{ translate('INDEX.UI_UPDATE') }</h5>
<div className="padding-top-15">

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

@ -143,9 +143,9 @@ class CliPanel extends React.Component {
render() {
return (
<div className="panel-body">
<div className="row">
<div className="col-sm-12">
<p>{ translate('INDEX.CLI_SELECT_A_COIN') }</p>
<div className="col-sm-12"></div>
<form
className="execute-cli-cmd-form"
method="post"
@ -190,6 +190,7 @@ class CliPanel extends React.Component {
</div>
</form>
</div>
</div>
);
};
}

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

@ -102,7 +102,8 @@ class DebugLogPanel extends React.Component {
render() {
return (
<div className="panel-body">
<div className="row">
<div className="col-sm-12">
<p>{ translate('INDEX.DEBUG_LOG_DESC') }</p>
<div className="margin-top-30">
<span className="pointer toggle">
@ -158,15 +159,18 @@ class DebugLogPanel extends React.Component {
className="btn btn-primary waves-effect waves-light"
onClick={ this.readDebugLog }>{ translate('INDEX.LOAD_DEBUG_LOG') }</button>
</div>
<div className="row">
<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>
</div>
</form>
}
{ this.state.toggleAppRuntimeLog &&
<div className="margin-top-20">{ this.renderAppRuntimeLog() }</div>
}
</div>
</div>
);
};
}

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

@ -157,8 +157,9 @@ class ExportKeysPanel extends React.Component {
render() {
return (
<div className="panel-body">
<div>
<div className="row">
<div className="col-sm-12">
<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>
@ -167,7 +168,9 @@ class ExportKeysPanel extends React.Component {
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
</div>
<div className="row">
<div className="col-sm-12">
<form
className="wifkeys-form"
method="post"
@ -201,9 +204,10 @@ class ExportKeysPanel extends React.Component {
onClick={ this.exportWifKeys }>{ translate('INDEX.GET_WIF_KEYS') }</button>
</div>
</form>
<div className="col-sm-12 padding-top-15">
</div>
</div>
<div className="row">
<div className="col-sm-12 padding-top-15">
<table className="table">
{ this.renderWifKeys() }
</table>

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

@ -9,7 +9,11 @@ class FiatCurrencyPanel extends React.Component {
render() {
return (
<div className="panel-body">Fiat currency settings section to be updated soon.</div>
<div className="row">
<div className="col-sm-12">
<p>Fiat currency settings section to be updated soon.</p>
</div>
</div>
);
};
}

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

@ -26,16 +26,21 @@ class ImportKeysPanel extends React.Component {
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>
<div className="row">
<div className="col-sm-12">
<p>{ translate('INDEX.IMPORT_KEYS_DESC_P1') }</p>
<p>{ translate('INDEX.IMPORT_KEYS_DESC_P2') }</p>
<p>{ translate('INDEX.IMPORT_KEYS_DESC_P3') }</p>
<p>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</p>
</div>
<div className="col-sm-12"></div>
</div>
<div className="row">
<div className="col-sm-12">
<form
className="wifkeys-import-form"
method="post"
@ -60,6 +65,8 @@ class ImportKeysPanel extends React.Component {
</div>
</form>
</div>
</div>
</div>
);
}
}

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

@ -1,15 +1,10 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import Config from '../../../config';
import {
iguanaActiveHandle,
getAppConfig,
getPeersList,
addPeerNode,
getAppInfo,
shepherdCli,
triggerToaster,
} from '../../../actions/actionCreators';
import Store from '../../../store';
@ -17,19 +12,6 @@ import {
SettingsRender,
} from './settings.render';
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:
1) pre-select active coin in add node tab
@ -38,105 +20,20 @@ import WalletBackupPanel from './settings.walletBackupPanel';
4) batch export/import wallet addresses
*/
class Settings extends React.Component {
constructor() {
super();
this.state = {
activeTab: 0,
tabElId: null,
seedInputVisibility: false,
nativeOnly: Config.iguanaLessMode,
disableWalletSpecificUI: false,
};
this.updateInput = this.updateInput.bind(this);
constructor(props) {
super(props);
}
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) {
this.setState(Object.assign({}, this.state, {
activeTab: this.state.activeTab,
tabElId: this.state.tabElId,
disableWalletSpecificUI: this.props.disableWalletSpecificUI,
}));
}
}
openTab(elemId, tab) {
this.setState(Object.assign({}, this.state, {
activeTab: tab,
tabElId: elemId,
}));
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
renderAppInfoTab() {
const releaseInfo = this.props.Settings.appInfo && this.props.Settings.appInfo.releaseInfo;
if (releaseInfo) {
return <AppInfoPanel />
}
return null;
}
renderAppUpdateTab() {
return <AppUpdatePanel />
}
renderWalletInfo() {
return <WalletInfoPanel />
}
renderAddNode() {
return <AddNodePanel />
}
renderWalletBackup() {
return <WalletBackupPanel />
}
renderFiatCurrency() {
return <FiatCurrencyPanel />
}
renderExportKeys() {
return <ExportKeysPanel />
}
renderImportKeys() {
return <ImportKeysPanel />
}
renderDebugLog() {
return <DebugLogPanel />
}
renderAppSettings() {
return <AppSettingsPanel />
}
renderCliPanel() {
return <CliPanel />
}
renderSupportPanel() {
return <SupportPanel />
}
render() {
return SettingsRender.call(this);
}
@ -146,13 +43,7 @@ const mapStateToProps = (state) => {
return {
Main: {
coins: state.Main.coins,
activeHandle: state.Main.activeHandle,
},
ActiveCoin: {
coin: state.ActiveCoin.coin,
},
Settings: state.Settings,
Dashboard: state.Dashboard,
};
};

86
react/src/components/dashboard/settings/settings.panel.js

@ -0,0 +1,86 @@
import React from 'react';
import className from 'classnames';
import * as Utils from './settings.panelUtils';
class Panel extends React.Component {
constructor(props) {
super(props);
this.toggleSection = this.toggleSection.bind(this);
this.state = {
singleOpen: this.props.singleOpen,
openByDefault: this.props.openByDefault,
activeSections: [],
};
}
componentWillMount() {
const {
singleOpen,
openByDefault,
uniqId,
children } = this.props;
const settings = {
singleOpen,
openByDefault,
uniqId,
kids: children
};
const initialStateSections = Utils.setupAccordion(settings).activeSections;
this.setState({ activeSections: initialStateSections });
}
getChildrenWithProps() {
const {
children,
} = this.props;
const kids = React.Children.map(children, (child, i) => {
if(child) {
const unqId = `panel-sec-${i}`;
return React.cloneElement(child, {
toggle: (acId) => this.toggleSection(acId),
key: unqId,
unq: unqId,
active: (this.state.activeSections && this.state.activeSections.lastIndexOf(unqId) !== -1)
});
}
});
return kids;
}
toggleSection(sectionId) {
const newActive = Utils.toggleSection(
sectionId,
this.state.activeSections,
this.state.singleOpen);
this.setState({
activeSections: newActive
});
}
render() {
const {
className: propClasses,
uniqId: propId
} = this.props;
const childrenWithProps = this.getChildrenWithProps();
const accordionClasses = className('panel-group', propClasses);
const uniqId = propId || '';
return(
<div className={accordionClasses} id={uniqId}>
{childrenWithProps}
</div>
);
}
}
export default Panel;

89
react/src/components/dashboard/settings/settings.panelBody.js

@ -0,0 +1,89 @@
import React from 'react';
import className from 'classnames';
class PanelSection extends React.Component {
constructor(props) {
super(props);
this.state = {
sectionHeight: 0,
}
this.toggleSection = this.toggleSection.bind(this);
}
componentDidMount() {
const { active } = this.props;
if (active) this.setState({sectionHeight: this.accordionContent.scrollHeight});
}
componentWillReceiveProps(nextProps) {
if(this.props.active) {
this.setState({
sectionHeight: 'auto',
});
}
if (nextProps.active !== this.props.active) {
this.toggleOpen(nextProps.active);
}
}
getHeight() {
const { active } = this.props;
return (active) ? this.accordionContent.scrollHeight : 0;
}
toggleSection() {
const {
unq,
toggle
} = this.props;
toggle(unq);
}
toggleOpen(active) {
const height = (active) ? `${this.accordionContent.scrollHeight}px` : 0;
this.setState({
sectionHeight: height,
});
}
render() {
const {
title,
icon,
children,
active,
className: propClasses
} = this.props;
const contentStyles = {
height: this.state.sectionHeight,
overflow: 'hidden',
transition: 'height .25s ease',
};
const triggerClasses = className('panel', {
active
});
const contentClasses = className('panel-collapse', {
active
});
return(
<div className={triggerClasses} onClick={() => this.toggleSection()}>
<div className="panel-heading">
<a className='panel-title'>
<i className={icon}></i> {title}
</a>
</div>
<div className={contentClasses} style={contentStyles} ref={(ref) => this.accordionContent = ref}>
<div className="panel-body">
{children}
</div>
</div>
</div>
);
}
}
export default PanelSection;

48
react/src/components/dashboard/settings/settings.panelUtils.js

@ -0,0 +1,48 @@
export function checkUndef(item) {
return (typeof item !== 'undefined');
}
export function toggleSection(sectionId, activeSections, singleOpen) {
let present = null;
let newActiveSections = activeSections;
newActiveSections.map((section) => {
if (section === sectionId) present = true;
return true;
});
if (!singleOpen) {
if (present) {
const pos = newActiveSections.indexOf(sectionId);
newActiveSections.splice(pos, 1);
} else {
newActiveSections.push(sectionId);
}
} else {
newActiveSections = [sectionId];
}
return newActiveSections;
}
export function setupAccordion(info) {
const singleOpen = (checkUndef(info.singleOpen)) ? info.singleOpen : false;
const activeSections = [];
const singleChild = typeof info.kids.length === 'undefined';
if (!singleChild) {
info.kids.forEach((child, i) => {
const { openByDefault } = child ? child.props : false;
if (singleOpen && activeSections.length === 0 && openByDefault) {
activeSections.push(`panel-sec-${i}`);
}
if (!singleOpen && openByDefault) {
activeSections.push(`panel-sec-${i}`);
}
});
}
return {
activeSections,
};
}

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

@ -1,225 +1,109 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import PanelSection from './settings.panelBody';
import Panel from './settings.panel';
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';
export const SettingsRender = function() {
return (
<div className="margin-left-0 full-height">
<div
className="page-content full-height"
id="section-iguana-wallet-settings">
<div className="row">
<div className="col-xlg-12 col-md-12">
id="section-iguana-wallet-settings"
className="padding-30">
<div className="row">
<div className="col-xlg-12 col-md-12">
<div className="col-sm-12">
<h4 className="font-size-14 text-uppercase">{ translate('INDEX.WALLET_SETTINGS') }</h4>
<div
className="panel-group"
id="SettingsAccordion">
<Panel
uniqId={'SettingsAccordion'}
singleOpen={true}>
{ !this.props.disableWalletSpecificUI &&
<div
id="WalletInfo"
onClick={ () => this.openTab('WalletInfo', 0) }
className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 0 ? '' : ' collapsed') }>
<i className="icon md-balance-wallet"></i>{ translate('INDEX.WALLET_INFO') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 0 ? ' in' : '') }
style={{ height: this.state.activeTab === 0 ? `auto` : '0' }}>
{ this.renderWalletInfo() }
</div>
</div>
<PanelSection
title={ translate('INDEX.WALLET_INFO') }
icon="icon md-balance-wallet"
openByDefault={!this.props.disableWalletSpecificUI}>
<WalletInfoPanel />
</PanelSection>
}
{ !this.props.disableWalletSpecificUI &&
<div
id="AddNodeforCoin"
onClick={ () => this.openTab('AddNodeforCoin', 1) }
className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 1 ? '' : ' collapsed') }>
<i className="icon md-plus-square"></i>{ translate('INDEX.ADD_NODE') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 1 ? ' in' : '') }
style={{ height: this.state.activeTab === 1 ? `auto` : '0' }}>
{ this.renderAddNode() }
</div>
</div>
<PanelSection
title={ translate('INDEX.ADD_NODE') }
icon="icon md-plus-square">
<AddNodePanel />
</PanelSection>
}
{ !this.props.disableWalletSpecificUI &&
<div
id="DumpWallet"
onClick={ () => this.openTab('DumpWallet', 2) }
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') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 2 ? ' in' : '') }
style={{ height: this.state.activeTab === 2 ? `auto` : '0' }}>
{ this.renderWalletBackup() }
</div>
</div>
<PanelSection
title={ translate('INDEX.WALLET_BACKUP') }
icon="icon wb-briefcase">
<WalletBackupPanel />
</PanelSection>
}
{ !this.props.disableWalletSpecificUI &&
<div
id="FiatCurrencySettings"
onClick={ () => this.openTab('FiatCurrencySettings', 3) }
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') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 3 ? ' in' : '') }
style={{ height: this.state.activeTab === 3 ? `auto` : '0' }}>
{ this.renderFiatCurrency() }
</div>
</div>
<PanelSection
title={ translate('INDEX.FIAT_CURRENCY') }
icon="icon fa-money">
<FiatCurrencyPanel />
</PanelSection>
}
{ !this.props.disableWalletSpecificUI &&
<div
id="ExportKeys"
onClick={ () => this.openTab('ExportKeys', 4) }
className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 4 ? '' : ' collapsed') }>
<i className="icon md-key"></i>{ translate('INDEX.EXPORT_KEYS') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 4 ? ' in' : '') }
style={{ height: this.state.activeTab === 4 ? `auto` : '0' }}>
{ this.renderExportKeys() }
</div>
</div>
<PanelSection
title={ translate('INDEX.EXPORT_KEYS') }
icon="icon md-key">
<ExportKeysPanel />
</PanelSection>
}
{ !this.props.disableWalletSpecificUI &&
<div
id="ImportKeys"
onClick={ () => this.openTab('ImportKeys', 5) }
className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 5 ? '' : ' collapsed') }>
<i className="icon md-key"></i>{ translate('INDEX.IMPORT_KEYS') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 5 ? ' in' : '') }
style={{ height: this.state.activeTab === 5 ? `auto` : '0' }}>
{ this.renderImportKeys() }
</div>
</div>
<PanelSection
title={ translate('INDEX.IMPORT_KEYS') }
icon="icon md-key">
<ImportKeysPanel />
</PanelSection>
}
<div
className="panel"
id="DebugLog"
onClick={ () => this.openTab('DebugLog', 6) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 6 ? '' : ' collapsed') }>
<i className="icon fa-bug"></i>{ translate('INDEX.DEBUG_LOG') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 6 ? ' in' : '') }
style={{ height: this.state.activeTab === 6 ? `auto` : '0' }}>
{ this.renderDebugLog() }
</div>
</div>
<div
className="panel"
id="AppSettings"
onClick={ () => this.openTab('AppSettings', 7) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 7 ? '' : ' collapsed') }>
<i className="icon fa-wrench"></i>{ translate('SETTINGS.APP_CONFIG') } (config.json)
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 7 ? ' in' : '') }
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>
<PanelSection
title={ translate('INDEX.DEBUG_LOG') }
icon="icon fa-bug"
openByDefault={this.props.disableWalletSpecificUI}>
<DebugLogPanel />
</PanelSection>
<PanelSection
title={ translate('SETTINGS.APP_CONFIG') + ' (config.json)' }
icon="icon fa-bug">
<AppSettingsPanel />
</PanelSection>
<PanelSection
title={ translate('SETTINGS.APP_INFO') }
icon="icon md-info">
<AppInfoPanel />
</PanelSection>
{ this.props.Main && this.props.Main.coins.native &&
<div
id="Cli"
onClick={ () => this.openTab('Cli', 9) }
className={ 'panel' + (!this.props.Main.coins.native.length ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 9 ? '' : ' collapsed') }>
<i className="icon fa-code"></i> CLI
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 9 ? ' in' : '') }
style={{ height: this.state.activeTab === 9 ? `auto` : '0' }}>
{ this.renderCliPanel() }
</div>
</div>
<PanelSection
title="CLI"
icon="icon fa-code">
<CliPanel />
</PanelSection>
}
<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"
id="Support"
onClick={ () => this.openTab('Support', 11) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 11 ? '' : ' collapsed') }>
<i className="icon fa fa-life-ring"></i> Support
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 11 ? ' in' : '') }
style={{ height: this.state.activeTab === 11 ? `auto` : '0' }}>
{ this.renderSupportPanel() }
</div>
</div>
</div>
</div>
</div>
</div>
<PanelSection
title={ translate('INDEX.UPDATE') }
icon="icon fa fa-cloud-download">
<AppUpdatePanel />
</PanelSection>
<PanelSection
title="Support"
icon="icon fa fa-life-ring">
<SupportPanel />
</PanelSection>
</Panel>
</div>
</div>
</div>

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

@ -93,10 +93,17 @@
#SettingsAccordion {
.panel {
.panel-collapse {
transition: all .3s;
&.collapse {
height: 0;
max-height: 0;
overflow: hidden;
}
&.in {
animation-name: max-height;
animation-duration: 1s;
animation-iteration-count: 1;
max-height: none;
}
}
}
@ -110,7 +117,7 @@
cursor: hand;
&:before {
content: '\F273';
content: '\F278';
}
&.collapsed {
&:before {
@ -118,4 +125,21 @@
}
}
}
.panel.active {
.panel-title:before {
content: '\F273';
}
}
}
@keyframes max-height {
from {
max-height: 0;
}
99% {
max-height: 2000px;
}
100% {
max-height: none;
}
}

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

@ -27,7 +27,7 @@ class SupportPanel extends React.Component {
render() {
return (
<div className="panel-body">
<div className="row">
<div className="col-sm-12 no-padding-left">
<div className="support-box-wrapper">
<div

6
react/src/components/dashboard/settings/settings.walletBackupPanel.js

@ -9,7 +9,11 @@ class WalletBackupPanel extends React.Component {
render() {
return (
<div className="panel-body">Wallet Backup section to be updated soon.</div>
<div className="row">
<div className="col-sm-12">
<p>Wallet Backup section to be updated soon.</p>
</div>
</div>
);
};
}

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

@ -9,7 +9,6 @@ class WalletInfoPanel extends React.Component {
render() {
return (
<div className="panel-body">
<table className="table">
<thead>
<tr>
@ -44,7 +43,6 @@ class WalletInfoPanel extends React.Component {
</tr>
</tbody>
</table>
</div>
);
};
}

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

@ -81,10 +81,29 @@ class WalletsNativeSend extends React.Component {
}
setRecieverFromScan(receiver) {
try {
const recObj = JSON.parse(receiver);
if (recObj &&
typeof recObj === 'object') {
if (recObj.coin === this.props.ActiveCoin.coin) {
if (recObj.amount) {
this.setState({
amount: recObj.amount,
});
}
if (recObj.address) {
this.setState({
sendTo: recObj.address,
});
}
}
}
} catch (e) {
this.setState({
sendTo: receiver,
});
}
document.getElementById('kmdWalletSendTo').focus();
}
@ -99,9 +118,11 @@ class WalletsNativeSend extends React.Component {
}
checkZAddressCount() {
if (this.props.ActiveCoin.addresses &&
(!this.props.ActiveCoin.addresses.private ||
this.props.ActiveCoin.addresses.private.length === 0)) {
const _addresses = this.props.ActiveCoin.addresses;
if (_addresses &&
(!_addresses.private ||
_addresses.private.length === 0)) {
this.setState({
renderAddressDropdown: false,
});

70
react/src/components/login/login.js

@ -18,6 +18,11 @@ import { PassPhraseGenerator } from '../../util/crypto/passphrasegenerator';
import SwallModalRender from './swall-modal.render';
import LoginRender from './login.render';
import { translate } from '../../translate/translate';
import {
encryptPassphrase,
loadPinList,
loginWithPin
} from '../../actions/actions/pin';
const IGUNA_ACTIVE_HANDLE_TIMEOUT = 3000;
const IGUNA_ACTIVE_COINS_TIMEOUT = 10000;
@ -45,6 +50,11 @@ class Login extends React.Component {
trimPassphraseTimer: null,
displayLoginSettingsDropdown: false,
displayLoginSettingsDropdownSection: null,
shouldEncryptSeed: false,
encryptKey: '',
pubKey: '',
decryptKey: '',
selectedPin: '',
isExperimentalOn: false,
};
this.toggleActivateCoinForm = this.toggleActivateCoinForm.bind(this);
@ -59,6 +69,10 @@ class Login extends React.Component {
this.execWalletCreate = this.execWalletCreate.bind(this);
this.resizeLoginTextarea = this.resizeLoginTextarea.bind(this);
this.toggleLoginSettingsDropdown = this.toggleLoginSettingsDropdown.bind(this);
this.updateEncryptKey = this.updateEncryptKey.bind(this);
this.updatePubKey = this.updatePubKey.bind(this);
this.updateDecryptKey = this.updateDecryptKey.bind(this);
this.loadPinList = this.loadPinList.bind(this);
}
// the setInterval handler for 'activeCoins'
@ -98,6 +112,35 @@ class Login extends React.Component {
});
}
shouldEncryptSeed() {
return this.state.shouldEncryptSeed;
}
toggleShouldEncryptSeed() {
this.setState({
shouldEncryptSeed: !this.state.shouldEncryptSeed
});
}
updateEncryptKey(e) {
this.setState({
encryptKey: e.target.value
});
}
updatePubKey(e) {
this.setState({
pubKey: e.target.value
});
}
updateDecryptKey(e) {
this.setState({
decryptKey: e.target.value
});
}
openSyncOnlyModal() {
Store.dispatch(getSyncOnlyForks());
@ -119,6 +162,8 @@ class Login extends React.Component {
componentDidMount() {
Store.dispatch(iguanaActiveHandle(true));
// this.loadPinList();
let appConfig;
try {
@ -153,6 +198,9 @@ class Login extends React.Component {
}
componentWillReceiveProps(props) {
if (props.Login.pinList === 'no pins') {
props.Login.pinList = [];
}
if (props &&
props.Main &&
props.Main.isLoggedIn) {
@ -255,10 +303,28 @@ class Login extends React.Component {
loginPassPhraseSeedType: null,
});
if (this.state.shouldEncryptSeed) {
Store.dispatch(encryptPassphrase(this.state.loginPassphrase, this.state.encryptKey, this.state.pubKey));
}
if (this.state.selectedPin) {
Store.dispatch(loginWithPin(this.state.decryptKey, this.state.selectedPin));
} else {
Store.dispatch(
iguanaWalletPassphrase(this.state.loginPassphrase)
);
}
}
loadPinList() {
Store.dispatch(loadPinList());
}
updateSelectedPin(e) {
this.setState({
selectedPin: e.target.value
});
}
getLoginPassPhraseSeedType(passPhrase) {
if (!passPhrase) {
@ -405,9 +471,9 @@ const mapStateToProps = (state) => {
},
Interval: {
interval: state.Interval.interval,
}
},
Login: state.Login,
};
};
export default connect(mapStateToProps)(Login);

93
react/src/components/login/login.render.js

@ -52,6 +52,9 @@ const LoginRender = function () {
<h4 className="color-white">
{ translate('INDEX.WELCOME_LOGIN') }
</h4>
{ this.props.Login.pinList.length > 0 &&
<span>You can login be entering a login seed or by selecting a pin</span>
}
<div className="form-group form-material floating col-sm-12 horizontal-padding-0">
<input
type="password"
@ -81,9 +84,97 @@ const LoginRender = function () {
<div className="placeholder-label">{ this.state.loginPassPhraseSeedType }</div>
</div>
}
{ this.state.loginPassphrase &&
<div className="row">
<div className="toggle-box padding-top-30 col-sm-3">
<span className="pointer">
<label className="switch">
<input
type="checkbox"
checked={ this.shouldEncryptSeed() } />
<div
className="slider"
onClick={ () => this.toggleShouldEncryptSeed() }></div>
</label>
<div
className="toggle-label white"
onClick={ () => this.toggleShouldEncryptSeed() }>
{ translate('LOGIN.ENCRYPT_SEED') }
</div>
</span>
</div>
<div className="col-sm-9">
<div className="form-group form-material floating horizontal-padding-0 margin-5 margin-right-0">
<input
type="text"
className="form-control"
name="encryptKey"
placeholder={ translate('LOGIN.ENCRYPT_KEY') }
onChange={ this.updateEncryptKey }
value={ this.state.encryptKey }
disabled={ !this.shouldEncryptSeed() } />
</div>
<div className="form-group form-material floating horizontal-padding-0 margin-5 margin-right">
<input
type="text"
className="form-control"
name="pubKey"
placeholder={ translate('LOGIN.PUBKEY') }
onChange={ this.updatePubKey }
value={ this.state.pubKey }
disabled={ !this.shouldEncryptSeed() } />
</div>
</div>
</div>
}
{ this.props.Login.pinList.length > 0 &&
<div className="row margin-top-30">
<div className="col-xs-12">
<div style={{width: "10%", float: "left", marginLeft: "38%"}}>
<hr/>
</div>
<div style={{width: "4%", float: "left", marginTop: "10px"}}><span>OR</span></div>
<div style={{width: "10%", float: "left"}}>
<hr/>
</div>
</div>
</div>
}
{ this.props.Login.pinList.length > 0 &&
<div className="row">
<div className="form-group form-material floating col-sm-8 padding-left-10 horizontal-padding-0">
<select
className="form-control form-material"
name="storedPins"
value={ this.state.selectedPin }
onChange={ (event) => this.updateSelectedPin(event) }
autoFocus>
<option className="login-option" value="">{ translate('INDEX.SELECT') }</option>
{this.props.Login.pinList.map(function(pin) {
return <option className="login-option" value={pin} key={pin}>{ pin }</option>
})}
</select>
</div>
<div className="form-group form-material floating col-sm-4 padding-left-10 margin-top-20">
<input
type="text"
className="form-control"
name="decryptKey"
placeholder={ translate('LOGIN.DECRYPT_KEY') }
disabled={ false }
onChange={ this.updateDecryptKey }
value={ this.state.decryptKey } />
</div>
</div>
}
<button
type="button"
className="btn btn-primary btn-block"
className="btn btn-primary btn-block margin-top-20"
onClick={ this.loginSeed }
disabled={ !this.state.loginPassphrase || !this.state.loginPassphrase.length }>{ translate('INDEX.SIGN_IN') }</button>
<div className="form-group form-material floating">

5
react/src/components/login/login.scss

@ -154,6 +154,11 @@ input[type="password"] {
}
}
option.login-option {
background-color: #757575;
color: #fff;
}
.login-form,
.register-form {
width: 540px;

2
react/src/reducers/index.js

@ -10,10 +10,12 @@ import { Atomic } from './atomic';
import { Settings } from './settings';
import { Interval } from './interval';
import { SyncOnly } from './syncOnly';
import { Login } from "./login";
const appReducer = combineReducers({
AddCoin,
toaster,
Login,
Main,
Dashboard,
ActiveCoin,

18
react/src/reducers/login.js

@ -0,0 +1,18 @@
import { GET_PIN_LIST } from "../actions/storeType";
export function Login(state = {
pinList: [],
}, action) {
if (state === null) state = { pinList: [] };
switch (action.type) {
case GET_PIN_LIST:
return Object.assign({}, state, {
pinList: action.pinList,
});
default:
return state;
}
}
export default Login;

8
react/src/translate/en.js

@ -307,6 +307,10 @@ export const _lang = {
'TOGGLE_ZERO_ADDRESSES': 'Toggle empty addresses',
'NEXT_PAGE': 'Next Page',
'PREVIOUS_PAGE': 'Previous Page',
'CREATE_INVOICE': 'Create Invoice',
'CREATE_INVOICE_QR': 'Create Invoice QR Code',
'QR_CONTENT': 'QR Content',
'CHOOSE_RECEIVING_ADDRESS': 'Choose Address',
},
'ATOMIC': {
'RAW_OUTPUT': 'Raw Output',
@ -580,6 +584,10 @@ export const _lang = {
'NXT_SEED': 'NXT',
'SEED_COPIED': 'Seed copied',
'SEED_SUCCESSFULLY_COPIED': 'The seed was successfully copied',
'ENCRYPT_SEED': 'Encrypt login seed',
'PUBKEY': 'pubkey',
'ENCRYPT_KEY': 'Encrypt key',
'DECRYPT_KEY': 'Decrypt key'
},
'SIDEBAR': {
'EDEX_MOTTO': 'Most Secure, Easy and Native Decentralised Exchange',

Loading…
Cancel
Save