diff --git a/react/src/actions/actionCreators.js b/react/src/actions/actionCreators.js index 2086541..f6e8629 100644 --- a/react/src/actions/actionCreators.js +++ b/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, diff --git a/react/src/actions/actions/pin.js b/react/src/actions/actions/pin.js new file mode 100644 index 0000000..58d600e --- /dev/null +++ b/react/src/actions/actions/pin.js @@ -0,0 +1,106 @@ +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) + ) + }) + } +} \ No newline at end of file diff --git a/react/src/actions/storeType.js b/react/src/actions/storeType.js index 7a7bdfb..e7e1444 100644 --- a/react/src/actions/storeType.js +++ b/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'; \ No newline at end of file diff --git a/react/src/components/app/app.js b/react/src/components/app/app.js index 75b3992..5fa20d0 100644 --- a/react/src/components/app/app.js +++ b/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, diff --git a/react/src/components/dashboard/settings/settings.addNodePanel.js b/react/src/components/dashboard/settings/settings.addNodePanel.js index 67ac130..b75f3f2 100644 --- a/react/src/components/dashboard/settings/settings.addNodePanel.js +++ b/react/src/components/dashboard/settings/settings.addNodePanel.js @@ -96,75 +96,73 @@ class AddNodePanel extends React.Component { render() { return ( -
-
-
-
-

{ translate('INDEX.USE_THIS_SECTION') }

-
-
-
- -
-
-
- -
-
-
- SuperNET Peers: -
-
{ this.renderSNPeersList() }
-
- Raw Peers: -
-
{ this.renderPeersList() }
+
+
+
+

{ translate('INDEX.USE_THIS_SECTION') }

+
+
+
+
+
+ +
+
+
+ SuperNET Peers: +
+
{ this.renderSNPeersList() }
+
+ Raw Peers: +
+
{ this.renderPeersList() }
+
+
-
-
-

{ translate('INDEX.USE_THIS_SECTION_PEER') }

-
-
-
- -
-
- -
+
+
+

{ translate('INDEX.USE_THIS_SECTION_PEER') }

+
+
+
+
-
- +
+
+
+ +
); diff --git a/react/src/components/dashboard/settings/settings.appInfoPanel.js b/react/src/components/dashboard/settings/settings.appInfoPanel.js index 030caf4..ebb0a09 100644 --- a/react/src/components/dashboard/settings/settings.appInfoPanel.js +++ b/react/src/components/dashboard/settings/settings.appInfoPanel.js @@ -8,76 +8,58 @@ class AppInfoPanel extends React.Component { } render() { - return ( -
-
-
+ const releaseInfo = this.props.Settings.appInfo && this.props.Settings.appInfo.releaseInfo; + + if (!releaseInfo) { + return null + } else { + return ( +
+
{ translate('SETTINGS.APP_RELEASE') }
-
+

{ translate('SETTINGS.NAME') }: { this.props.Settings.appInfo.releaseInfo.name } -

-
+
{ translate('SETTINGS.VERSION') }: { `${this.props.Settings.appInfo.releaseInfo.version.replace('version=', '')}-beta` } -
-
+
{ translate('SETTINGS.APP_SESSION') }: { this.props.Settings.appInfo.appSession } -
-
-
-
-
+

{ translate('SETTINGS.SYS_INFO') }
-
+

{ translate('SETTINGS.ARCH') }: { this.props.Settings.appInfo.sysInfo.arch } -

-
+
{ translate('SETTINGS.OS_TYPE') }: { this.props.Settings.appInfo.sysInfo.os_type } -
-
+
{ translate('SETTINGS.OS_PLATFORM') }: { this.props.Settings.appInfo.sysInfo.platform } -
-
+
{ translate('SETTINGS.OS_RELEASE') }: { this.props.Settings.appInfo.sysInfo.os_release } -
-
+
{ translate('SETTINGS.CPU') }: { this.props.Settings.appInfo.sysInfo.cpu } -
-
+
{ translate('SETTINGS.CPU_CORES') }: { this.props.Settings.appInfo.sysInfo.cpu_cores } -
-
+
{ translate('SETTINGS.MEM') }: { this.props.Settings.appInfo.sysInfo.totalmem_readable } -
-
-
-
-
+

{ translate('SETTINGS.LOCATIONS') }
-
+

{ translate('SETTINGS.CACHE') }: { this.props.Settings.appInfo.dirs.cacheLocation } -

-
+
{ translate('SETTINGS.CONFIG') }: { this.props.Settings.appInfo.dirs.configLocation } -
-
+
Iguana { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.iguanaBin } -
-
+
Iguana { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.iguanaDir } -
-
+
Komodo { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.komododBin } -
-
+
Komodo { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.komodoDir } -
-
+
Komodo wallet.dat: { this.props.Settings.appInfo.dirs.komodoDir } -
+

-
- ); + ); + } }; } diff --git a/react/src/components/dashboard/settings/settings.appSettingsPanel.js b/react/src/components/dashboard/settings/settings.appSettingsPanel.js index 77b982f..ac80dc2 100644 --- a/react/src/components/dashboard/settings/settings.appSettingsPanel.js +++ b/react/src/components/dashboard/settings/settings.appSettingsPanel.js @@ -283,26 +283,30 @@ class AppSettingsPanel extends React.Component { render() { return ( -
-

- { translate('SETTINGS.CONFIG_RESTART_REQUIRED') } -

-
- - - { this.renderConfigEditForm() } - -
+
+
+
+

+ { translate('SETTINGS.CONFIG_RESTART_REQUIRED') } +

+ + + { this.renderConfigEditForm() } + +
+
-
- - +
+
+ + +
); diff --git a/react/src/components/dashboard/settings/settings.appUpdatePanel.js b/react/src/components/dashboard/settings/settings.appUpdatePanel.js index b7230b0..16bc272 100644 --- a/react/src/components/dashboard/settings/settings.appUpdatePanel.js +++ b/react/src/components/dashboard/settings/settings.appUpdatePanel.js @@ -107,7 +107,7 @@ class AppUpdatePanel extends React.Component { render() { return ( -
+
{ translate('INDEX.UI_UPDATE') }
diff --git a/react/src/components/dashboard/settings/settings.cliPanel.js b/react/src/components/dashboard/settings/settings.cliPanel.js index 312dcb2..7298076 100644 --- a/react/src/components/dashboard/settings/settings.cliPanel.js +++ b/react/src/components/dashboard/settings/settings.cliPanel.js @@ -143,9 +143,9 @@ class CliPanel extends React.Component { render() { return ( -
+
+

{ translate('INDEX.CLI_SELECT_A_COIN') }

-
+
); }; diff --git a/react/src/components/dashboard/settings/settings.debugLogPanel.js b/react/src/components/dashboard/settings/settings.debugLogPanel.js index e0b89c5..f651bf2 100644 --- a/react/src/components/dashboard/settings/settings.debugLogPanel.js +++ b/react/src/components/dashboard/settings/settings.debugLogPanel.js @@ -102,70 +102,74 @@ class DebugLogPanel extends React.Component { render() { return ( -
-

{ translate('INDEX.DEBUG_LOG_DESC') }

-
- - - Show app runtime log - +
+
+

{ translate('INDEX.DEBUG_LOG_DESC') }

+
+ + + Show app runtime log + +
+ { !this.state.toggleAppRuntimeLog && +
+
+ + +
+
+ + +
+
+ +
+
+
+
{ this.renderDebugLogData() }
+
+
+
+ } + { this.state.toggleAppRuntimeLog && +
{ this.renderAppRuntimeLog() }
+ }
- { !this.state.toggleAppRuntimeLog && -
-
- - -
-
- - -
-
- -
-
-
{ this.renderDebugLogData() }
-
-
- } - { this.state.toggleAppRuntimeLog && -
{ this.renderAppRuntimeLog() }
- }
); }; diff --git a/react/src/components/dashboard/settings/settings.exportKeysPanel.js b/react/src/components/dashboard/settings/settings.exportKeysPanel.js index 7c59ea5..2991e47 100644 --- a/react/src/components/dashboard/settings/settings.exportKeysPanel.js +++ b/react/src/components/dashboard/settings/settings.exportKeysPanel.js @@ -157,53 +157,57 @@ class ExportKeysPanel extends React.Component { render() { return ( -
-
-
{ this.renderLB('INDEX.ONLY_ACTIVE_WIF_KEYS') }
-
- { this.renderLB('SETTINGS.EXPORT_KEYS_NOTE') } +
+
+
+
{ this.renderLB('INDEX.ONLY_ACTIVE_WIF_KEYS') }
+
+ { this.renderLB('SETTINGS.EXPORT_KEYS_NOTE') } +
+ + { translate('INDEX.PLEASE_KEEP_KEYS_SAFE') } +
- - { translate('INDEX.PLEASE_KEEP_KEYS_SAFE') } -
-
-
-
- - - - -
-
- +
+
+ +
+ + + + +
+
+ +
+
- - -
-
+
+
+
{ this.renderWifKeys() }
diff --git a/react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js b/react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js index ad61436..a08fbf4 100644 --- a/react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js +++ b/react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js @@ -9,7 +9,11 @@ class FiatCurrencyPanel extends React.Component { render() { return ( -
Fiat currency settings section to be updated soon.
+
+
+

Fiat currency settings section to be updated soon.

+
+
); }; } diff --git a/react/src/components/dashboard/settings/settings.importKeysPanel.js b/react/src/components/dashboard/settings/settings.importKeysPanel.js index e395871..b4622bd 100644 --- a/react/src/components/dashboard/settings/settings.importKeysPanel.js +++ b/react/src/components/dashboard/settings/settings.importKeysPanel.js @@ -26,39 +26,46 @@ class ImportKeysPanel extends React.Component { render() { return ( -
-
{ translate('INDEX.IMPORT_KEYS_DESC_P1') }

-
{ translate('INDEX.IMPORT_KEYS_DESC_P2') }

-
{ translate('INDEX.IMPORT_KEYS_DESC_P3') }

-
- - { translate('INDEX.PLEASE_KEEP_KEYS_SAFE') } - -
-
-
-
- - +
+
+
+

{ translate('INDEX.IMPORT_KEYS_DESC_P1') }

+

{ translate('INDEX.IMPORT_KEYS_DESC_P2') }

+

{ translate('INDEX.IMPORT_KEYS_DESC_P3') }

+

+ + { translate('INDEX.PLEASE_KEEP_KEYS_SAFE') } + +

-
- +
+
+
+ +
+ + +
+
+ +
+
- +
); } diff --git a/react/src/components/dashboard/settings/settings.js b/react/src/components/dashboard/settings/settings.js index 32c276d..25a37e2 100644 --- a/react/src/components/dashboard/settings/settings.js +++ b/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 - } - - return null; - } - - renderAppUpdateTab() { - return - } - - renderWalletInfo() { - return - } - renderAddNode() { - return - } - - renderWalletBackup() { - return - } - - renderFiatCurrency() { - return - } - - renderExportKeys() { - return - } - - renderImportKeys() { - return - } - - renderDebugLog() { - return - } - - renderAppSettings() { - return - } - - renderCliPanel() { - return - } - - renderSupportPanel() { - return - } - 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, }; }; diff --git a/react/src/components/dashboard/settings/settings.panel.js b/react/src/components/dashboard/settings/settings.panel.js new file mode 100644 index 0000000..44f8370 --- /dev/null +++ b/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( +
+ {childrenWithProps} +
+ ); + } +} + +export default Panel; \ No newline at end of file diff --git a/react/src/components/dashboard/settings/settings.panelBody.js b/react/src/components/dashboard/settings/settings.panelBody.js new file mode 100644 index 0000000..84a52fe --- /dev/null +++ b/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( +
this.toggleSection()}> + +
this.accordionContent = ref}> +
+ {children} +
+
+
+ ); + } +} + +export default PanelSection; diff --git a/react/src/components/dashboard/settings/settings.panelUtils.js b/react/src/components/dashboard/settings/settings.panelUtils.js new file mode 100644 index 0000000..e07614f --- /dev/null +++ b/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, + }; +} \ No newline at end of file diff --git a/react/src/components/dashboard/settings/settings.render.js b/react/src/components/dashboard/settings/settings.render.js index 5a999d1..95fcf70 100644 --- a/react/src/components/dashboard/settings/settings.render.js +++ b/react/src/components/dashboard/settings/settings.render.js @@ -1,227 +1,111 @@ 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 ( -
-
+
-
-
-
-

{ translate('INDEX.WALLET_SETTINGS') }

-
- - { !this.props.disableWalletSpecificUI && -
this.openTab('WalletInfo', 0) } - className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }> - -
- { this.renderWalletInfo() } -
-
- } - { !this.props.disableWalletSpecificUI && -
this.openTab('AddNodeforCoin', 1) } - className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }> - -
- { this.renderAddNode() } -
-
- } - { !this.props.disableWalletSpecificUI && -
this.openTab('DumpWallet', 2) } - className={ 'hide panel' + (this.state.nativeOnly ? ' hide' : '') }> - -
- { this.renderWalletBackup() } -
-
- } - { !this.props.disableWalletSpecificUI && -
this.openTab('FiatCurrencySettings', 3) } - className={ 'hide panel' + (this.state.nativeOnly ? ' hide' : '') }> - -
- { this.renderFiatCurrency() } -
-
- } - { !this.props.disableWalletSpecificUI && -
this.openTab('ExportKeys', 4) } - className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }> - -
- { this.renderExportKeys() } -
-
- } - { !this.props.disableWalletSpecificUI && -
this.openTab('ImportKeys', 5) } - className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }> - -
- { this.renderImportKeys() } -
-
- } - -
this.openTab('DebugLog', 6) }> - -
- { this.renderDebugLog() } -
-
- -
this.openTab('AppSettings', 7) }> - -
- { this.renderAppSettings() } -
-
- -
this.openTab('AppInfo', 8) }> - -
- { this.renderAppInfoTab() } -
-
- - { this.props.Main && this.props.Main.coins.native && -
this.openTab('Cli', 9) } - className={ 'panel' + (!this.props.Main.coins.native.length ? ' hide' : '') }> - -
- { this.renderCliPanel() } -
-
- } - -
this.openTab('AppUpdate', 10) }> - -
- { this.renderAppUpdateTab() } -
-
- -
this.openTab('Support', 11) }> - -
- { this.renderSupportPanel() } -
-
-
-
-
+
+

{ translate('INDEX.WALLET_SETTINGS') }

+ + { !this.props.disableWalletSpecificUI && + + + + } + { !this.props.disableWalletSpecificUI && + + + + } + { !this.props.disableWalletSpecificUI && + + + + } + { !this.props.disableWalletSpecificUI && + + + + } + { !this.props.disableWalletSpecificUI && + + + + } + { !this.props.disableWalletSpecificUI && + + + + } + + + + + + + + + + { this.props.Main && this.props.Main.coins.native && + + + + } + + + + + + +
-
); }; \ No newline at end of file diff --git a/react/src/components/dashboard/settings/settings.scss b/react/src/components/dashboard/settings/settings.scss index bc1a47c..e3a10c0 100644 --- a/react/src/components/dashboard/settings/settings.scss +++ b/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; + } } \ No newline at end of file diff --git a/react/src/components/dashboard/settings/settings.supportPanel.js b/react/src/components/dashboard/settings/settings.supportPanel.js index a13f89b..be016c5 100644 --- a/react/src/components/dashboard/settings/settings.supportPanel.js +++ b/react/src/components/dashboard/settings/settings.supportPanel.js @@ -27,7 +27,7 @@ class SupportPanel extends React.Component { render() { return ( -
+
Wallet Backup section to be updated soon.
+
+
+

Wallet Backup section to be updated soon.

+
+
); }; } diff --git a/react/src/components/dashboard/settings/settings.walletInfoPanel.js b/react/src/components/dashboard/settings/settings.walletInfoPanel.js index 29fda9d..ad255f9 100644 --- a/react/src/components/dashboard/settings/settings.walletInfoPanel.js +++ b/react/src/components/dashboard/settings/settings.walletInfoPanel.js @@ -9,8 +9,7 @@ class WalletInfoPanel extends React.Component { render() { return ( -
- +
@@ -44,7 +43,6 @@ class WalletInfoPanel extends React.Component {
{ translate('INDEX.KEY') }
-
); }; } diff --git a/react/src/components/login/login.js b/react/src/components/login/login.js index 9739b74..a5a3afb 100644 --- a/react/src/components/login/login.js +++ b/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,9 +303,27 @@ class Login extends React.Component { loginPassPhraseSeedType: null, }); - Store.dispatch( - iguanaWalletPassphrase(this.state.loginPassphrase) - ); + 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) { @@ -405,9 +471,9 @@ const mapStateToProps = (state) => { }, Interval: { interval: state.Interval.interval, - } + }, + Login: state.Login, }; - }; export default connect(mapStateToProps)(Login); diff --git a/react/src/components/login/login.render.js b/react/src/components/login/login.render.js index 0f70929..e6a5af4 100644 --- a/react/src/components/login/login.render.js +++ b/react/src/components/login/login.render.js @@ -52,6 +52,9 @@ const LoginRender = function () {

{ translate('INDEX.WELCOME_LOGIN') }

+ { this.props.Login.pinList.length > 0 && + You can login be entering a login seed or by selecting a pin + }
{ this.state.loginPassPhraseSeedType }
} + + { this.state.loginPassphrase && +
+
+ + +
this.toggleShouldEncryptSeed() }> + { translate('LOGIN.ENCRYPT_SEED') } +
+
+
+ +
+
+ +
+ +
+ +
+
+
+ } + + { this.props.Login.pinList.length > 0 && +
+
+
+
+
+
OR
+
+
+
+
+
+ } + { this.props.Login.pinList.length > 0 && +
+
+ +
+
+ +
+
+ } +
diff --git a/react/src/components/login/login.scss b/react/src/components/login/login.scss index beceabf..3a04ad0 100644 --- a/react/src/components/login/login.scss +++ b/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; diff --git a/react/src/reducers/index.js b/react/src/reducers/index.js index b6c4c76..afe3831 100644 --- a/react/src/reducers/index.js +++ b/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, diff --git a/react/src/reducers/login.js b/react/src/reducers/login.js new file mode 100644 index 0000000..ffaabd9 --- /dev/null +++ b/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; diff --git a/react/src/translate/en.js b/react/src/translate/en.js index 4734dcb..c95fd3f 100644 --- a/react/src/translate/en.js +++ b/react/src/translate/en.js @@ -584,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',