Merge pull request #36 from Permissionless-Software-Foundation/dh-back-ends

feat(backends): Started the implementation of select multiple backends
This commit is contained in:
Chris Troutner
2020-07-10 08:35:43 -07:00
committed by GitHub
6 changed files with 398 additions and 24 deletions
+14 -3
View File
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import { Content, Row, Col, Box, Inputs, Button } from 'adminlte-2-react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import BchWallet from 'minimal-slp-wallet'
import Servers from './servers'
const { Text } = Inputs
let _this
@@ -104,6 +104,11 @@ class Configure extends React.Component {
</Box>
</Col>
</Row>
<Servers
setWalletInfo={_this.props.setWalletInfo}
walletInfo={_this.props.walletInfo}
setBchWallet={_this.props.setBchWallet}
/>
</Content>
)
}
@@ -130,13 +135,19 @@ class Configure extends React.Component {
async handleUpdateJWT () {
try {
const { mnemonic } = _this.props.walletInfo
const { mnemonic, selectedServer } = _this.props.walletInfo
const apiToken = _this.state.JWT
// Update instance with JWT
if (mnemonic && apiToken) {
const bchjsOptions = { apiToken: apiToken }
if (selectedServer) {
bchjsOptions.restURL = selectedServer
}
console.log('bchjs options : ', bchjsOptions)
const bchWalletLib = new _this.BchWallet(mnemonic)
bchWalletLib.bchjs = new bchWalletLib.BCHJS({ apiToken: apiToken })
bchWalletLib.bchjs = new bchWalletLib.BCHJS(bchjsOptions)
_this.props.setBchWallet(bchWalletLib)
}
@@ -0,0 +1,271 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Row, Col, Box, Inputs, Button } from 'adminlte-2-react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import BchWallet from 'minimal-slp-wallet'
const { Text, Select } = Inputs
let _this
class Servers extends React.Component {
constructor (props) {
super(props)
_this = this
this.state = {
selectOptions: [],
errMsg: '',
selectedServer: '',
showAddField: false,
newServer: ''
}
_this.BchWallet = BchWallet
}
render () {
return (
<Row>
<Col sm={12}>
<Box className='hover-shadow border-none mt-2'>
<Row>
<Col sm={12} className='text-center'>
<h1>
<FontAwesomeIcon
className='title-icon'
size='xs'
icon='server'
/>
<span>Back End Server</span>
</h1>
<Box className='border-none'>
<Row>
<Col xs={12}>
{_this.state.showAddField ? (
<Text
id='newServer'
name='newServer'
placeholder='Add New Server url'
label='Add New Server Url'
labelPosition='above'
onChange={_this.handleUpdate}
value={_this.state.newServer}
buttonRight={
<Button
text={_this.state.newServer ? ' ADD ' : 'CLOSE'}
type='primary'
onClick={_this.handleNewServerUrl}
/>
}
/>
) : (
<Select
name='selectedServer'
label='Select Server Url'
labelPosition='above'
options={_this.state.selectOptions}
value={_this.state.selectedServer}
onChange={_this.handleUpdate}
buttonRight={
<Button
icon='fa-plus'
onClick={_this.handleTextField}
/>
}
/>
)}
</Col>
<Col sm={12} />
</Row>
<Button
text='Update'
type='primary'
className='btn-lg'
onClick={_this.handleUpdateServer}
/>
</Box>
</Col>
<Col sm={12} className='text-center'>
{_this.state.errMsg && (
<p className='error-color'>{_this.state.errMsg}</p>
)}
</Col>
</Row>
</Box>
</Col>
</Row>
)
}
// turn on / off text field
handleTextField () {
_this.setState({
showAddField: !_this.state.showAddField
})
}
// Add the new server value to the select field
handleNewServerUrl () {
_this.setState({
errMsg: ''
})
const { newServer, selectOptions } = _this.state
try {
if (newServer) {
if (newServer.match(' ')) {
throw new Error('backend url must have no spaces')
}
const alreadyExist = selectOptions.find(val => {
return val.value === newServer
})
// Prevent duplicate options
if (alreadyExist) {
_this.setState({
showAddField: false,
selectedServer: newServer
})
_this.resetForm()
return
}
const option = {
value: newServer,
text: newServer
}
// add the new select option
selectOptions.push(option)
}
_this.setState({
selectOptions,
showAddField: false,
selectedServer: newServer || _this.state.selectedServer
})
_this.resetForm()
} catch (error) {
_this.setState({
errMsg: error.message
})
}
}
// populate select field with select options from localstorage
populateSelect () {
try {
const walletInfo = _this.props.walletInfo
const selectOptions = []
// populate select field with data from localstorage
for (let i = 0; i < walletInfo.servers.length; i++) {
const option = {
value: walletInfo.servers[i],
text: walletInfo.servers[i]
}
selectOptions.push(option)
}
_this.setState({
selectOptions,
selectedServer: walletInfo.selectedServer
})
} catch (error) {
console.warn(error)
}
}
componentDidMount () {
_this.populateSelect()
}
handleUpdate (event) {
const value = event.target.value
_this.setState({
[event.target.name]: value
})
}
handleUpdateServer () {
_this.handleNewServerUrl()
// await for state update delay
setTimeout(() => {
_this.updateWalletInstance()
}, 500)
}
// Update the wallet instance state
updateWalletInstance () {
try {
const { mnemonic, JWT } = _this.props.walletInfo
const apiToken = JWT
const restURL = _this.state.selectedServer
// Update instance with the selected url
if (mnemonic) {
const bchjsOptions = {}
if (apiToken) {
bchjsOptions.apiToken = apiToken
}
bchjsOptions.restURL = restURL
console.log('bchjs options : ', bchjsOptions)
const bchWalletLib = new _this.BchWallet(mnemonic)
bchWalletLib.bchjs = new bchWalletLib.BCHJS(bchjsOptions)
_this.props.setBchWallet(bchWalletLib)
}
_this.saveServer()
} catch (error) {
console.warn(error)
_this.setState({
errMsg: error.message
})
}
}
// store servers in the localstorage
saveServer () {
try {
// store the new server in the localstorage if it does not exist
const walletInfo = _this.props.walletInfo
const { servers } = walletInfo
const selectedValue = _this.state.selectedServer
if (!selectedValue) {
return
}
const alreadyExist = servers.find(val => {
return val === selectedValue
})
// Prevent duplicate values
if (!alreadyExist) {
servers.push(selectedValue)
}
walletInfo.servers = servers
walletInfo.selectedServer = selectedValue
_this.props.setWalletInfo(walletInfo)
} catch (error) {
console.warn(error)
}
}
// clean the text form field
resetForm () {
_this.setState({
newServer: ''
})
}
}
Servers.propTypes = {
setWalletInfo: PropTypes.func.isRequired,
walletInfo: PropTypes.object.isRequired,
setBchWallet: PropTypes.func.isRequired
}
export default Servers
+38 -2
View File
@@ -4,7 +4,6 @@ import Configure from './configure'
import Tokens from './tokens'
import Wallet from './wallet'
import siteConfig from '../site-config'
// import Audit from "./audit"
import AdminLTE, { Sidebar, Navbar } from 'adminlte-2-react'
@@ -52,7 +51,11 @@ class AdminLTEPage extends React.Component {
render () {
return (
<>
<AdminLTE title={[siteConfig.title]} titleShort={[siteConfig.titleShort]} theme='blue'>
<AdminLTE
title={[siteConfig.title]}
titleShort={[siteConfig.titleShort]}
theme='blue'
>
<Sidebar.Core>
<Item key='Balance' text='Balance' icon={siteConfig.balanceIcon}>
<div className='sidebar-balance'>
@@ -146,6 +149,8 @@ class AdminLTEPage extends React.Component {
_this.activeItemById('Wallet')
_this.setDefaultServers()
await _this.updateState()
setTimeout(() => {
_this.dropDownBalance()
@@ -306,6 +311,37 @@ class AdminLTEPage extends React.Component {
</li>
)
}
// Define backends servers configuration by default
setDefaultServers () {
try {
const walletInfo = _this.props.walletInfo
const accessLocation = window.location.hostname
console.log('accessLocation', accessLocation)
// return if servers configurations exist
if (walletInfo.selectedServer) return null
const server1 = 'https://api.fullstack.cash/v3/'
const server2 = 'https://free-api.fullstack.cash/v3/'
const servers = [server1, server2]
let selectedServer = server1
// Assign the second server if the url path
// is different of 'wallet.fullstack.cash'
if (accessLocation !== 'wallet.fullstack.cash') {
selectedServer = server2
}
walletInfo.selectedServer = selectedServer
walletInfo.servers = servers
_this.props.setWalletInfo(walletInfo)
} catch (error) {
console.warn(error)
}
}
}
// Props prvided by redux
AdminLTEPage.propTypes = {
+31 -6
View File
@@ -9,7 +9,9 @@ class NewWallet extends React.Component {
constructor (props) {
super(props)
_this = this
this.state = {}
this.state = {
inFetch: false
}
_this.BchWallet = BchWallet
}
@@ -20,7 +22,10 @@ class NewWallet extends React.Component {
<Row>
<Col sm={2} />
<Col sm={8}>
<Box className='hover-shadow border-none mt-2'>
<Box
className='hover-shadow border-none mt-2'
loaded={!_this.state.inFetch}
>
<Row>
<Col sm={12} className='text-center'>
<h1>
@@ -60,12 +65,23 @@ class NewWallet extends React.Component {
* it will get overwritten
*/
}
_this.setState({
inFetch: true
})
const bchWalletLib = new _this.BchWallet()
const apiToken = currentWallet.JWT
const restURL = currentWallet.selectedServer
if (apiToken) {
bchWalletLib.bchjs = new bchWalletLib.BCHJS({ apiToken: apiToken })
if (apiToken || restURL) {
const bchjsOptions = {}
if (apiToken) {
bchjsOptions.apiToken = apiToken
}
if (restURL) {
bchjsOptions.restURL = restURL
}
console.log('bchjs options : ', bchjsOptions)
bchWalletLib.bchjs = new bchWalletLib.BCHJS(bchjsOptions)
}
await bchWalletLib.walletInfoPromise // Wait for wallet to be created.
@@ -73,14 +89,23 @@ class NewWallet extends React.Component {
const walletInfo = bchWalletLib.walletInfo
walletInfo.from = 'created'
Object.assign(currentWallet, walletInfo)
const myBalance = await bchWalletLib.getBalance()
// Update redux state
_this.props.setWalletInfo(walletInfo)
_this.props.setWalletInfo(currentWallet)
_this.props.updateBalance(myBalance)
_this.props.setBchWallet(bchWalletLib)
_this.setState({
inFetch: false
})
} catch (error) {
console.error(error)
_this.setState({
inFetch: false
})
}
}
}
+29 -7
View File
@@ -16,7 +16,9 @@ class ImportWallet extends React.Component {
this.state = {
mnemonic: '',
privateKey: '',
errMsg: ''
errMsg: '',
inFetch: false
}
_this.BchWallet = BchWallet
}
@@ -26,7 +28,10 @@ class ImportWallet extends React.Component {
<Row className=''>
<Col sm={2} />
<Col sm={8}>
<Box className='hover-shadow border-none mt-2'>
<Box
className='hover-shadow border-none mt-2'
loaded={!_this.state.inFetch}
>
<Row>
<Col sm={12} className='text-center'>
<h1>
@@ -112,32 +117,49 @@ class ImportWallet extends React.Component {
* and it will get overwritten
*/
}
_this.setState({
inFetch: true
})
const bchWalletLib = new _this.BchWallet(_this.state.mnemonic)
const apiToken = currentWallet.JWT
const restURL = currentWallet.selectedServer
if (apiToken) {
bchWalletLib.bchjs = new bchWalletLib.BCHJS({ apiToken: apiToken })
if (apiToken || restURL) {
const bchjsOptions = {}
if (apiToken) {
bchjsOptions.apiToken = apiToken
}
if (restURL) {
bchjsOptions.restURL = restURL
}
console.log('bchjs options : ', bchjsOptions)
bchWalletLib.bchjs = new bchWalletLib.BCHJS(bchjsOptions)
}
await bchWalletLib.walletInfoPromise // Wait for wallet to be created.
const walletInfo = bchWalletLib.walletInfo
walletInfo.from = 'imported'
Object.assign(currentWallet, walletInfo)
const myBalance = await bchWalletLib.getBalance()
// Update redux state
_this.props.setWalletInfo(walletInfo)
_this.props.setWalletInfo(currentWallet)
_this.props.updateBalance(myBalance)
_this.props.setBchWallet(bchWalletLib)
// Reset form and component state
_this.resetValues()
_this.setState({
inFetch: false
})
} catch (error) {
console.warn(error)
_this.setState({
errMsg: error.message
errMsg: error.message,
inFetch: false
})
}
}
+15 -6
View File
@@ -41,28 +41,37 @@ const reducer = (state, action) => {
}
// Wallet info from local storage
const localWallet = getWalletInfo()
const localStorageInfo = getWalletInfo()
// Creates an instance of minimal-slp-wallet, with
// the local storage information if it exists
const instanceWallet = () => {
try {
if (!localWallet.mnemonic) return null
if (!localStorageInfo.mnemonic) return null
const bchWalletLib = new BchWallet(localWallet.mnemonic)
const bchWalletLib = new BchWallet(localStorageInfo.mnemonic)
const jwtToken = localStorageInfo.JWT
const restURL = localStorageInfo.selectedServer
const bchjsOptions = {}
const jwtToken = localWallet.JWT
if (jwtToken) {
bchWalletLib.bchjs = new bchWalletLib.BCHJS({ apiToken: jwtToken })
bchjsOptions.apiToken = jwtToken
}
if (restURL) {
bchjsOptions.restURL = restURL
}
bchWalletLib.bchjs = new bchWalletLib.BCHJS(bchjsOptions)
return bchWalletLib
} catch (error) {
console.warn(error)
}
}
// initial state
const initialState = {
walletInfo: localWallet.mnemonic ? localWallet : {}, // Object wallet info
walletInfo: localStorageInfo, // Object wallet info
bchBalance: 0, // Wallet Balance
bchWallet: instanceWallet() // minimal-slp-wallet instance
}