pbca26
7 years ago
committed by
GitHub
35 changed files with 1290 additions and 633 deletions
@ -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) |
|||
); |
|||
}) |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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); |
@ -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> |
|||
{ 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)}...` } |
|||
(Balance: { address.amount }) |
|||
</option> |
|||
); |
|||
}; |
@ -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; |
@ -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; |
@ -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, |
|||
}; |
|||
} |
@ -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; |
Loading…
Reference in new issue