Improve current wallet display

This commit is contained in:
Dennis Reimann 2021-11-28 13:30:57 +01:00
parent eb561570b6
commit c35926e92e
No known key found for this signature in database
GPG key ID: 5009E1797F03F8D0
9 changed files with 217 additions and 216 deletions

View file

@ -227,55 +227,55 @@ export default function App() {
<rb.Navbar.Toggle aria-controls="responsive-rb.Navbar-rb.Nav" className="ms-auto border-0" />
<rb.Navbar.Collapse id="responsive-rb.Navbar-rb.Nav">
<rb.Nav className="text-start">
{currentWallet
? <>
<Link to="/wallets/current" className="nav-link">Wallet</Link>
<Link to="/payment" className="nav-link">Payment</Link>
<Link to="/receive" className="nav-link">Receive</Link>
<Link to="/maker" className="nav-link">Maker</Link>
</>
: null}
{connection === true
? <Link to="/wallets/create" className="nav-link">Create Wallet</Link>
: null}
{currentWallet &&
<>
<Link to="/wallets/current" className="nav-link">Wallet</Link>
<Link to="/payment" className="nav-link">Payment</Link>
<Link to="/receive" className="nav-link">Receive</Link>
<Link to="/maker" className="nav-link">Maker</Link>
</>}
{connection === true &&
<Link to="/wallets/create" className="nav-link">Create Wallet</Link>}
<Link to="/about" className="nav-link">About</Link>
</rb.Nav>
</rb.Navbar.Collapse>
<div className="justify-content-start justify-content-md-end">
<rb.Nav className="flex-row">
<Link to="/" className="nav-link">{walletLoadStatus} ({activeWallet || 'None'} active)</Link> }
<Link to="/" className="nav-link">{walletLoadStatus} ({activeWallet || 'None'} active)</Link>
<rb.Navbar.Text>
{connection === true
? ` · YG ${makerStarted ? 'on' : 'off'}${coinjoinInProcess ? ', Coinjoining' : ''}`
: null}
{connection === true &&
` · YG ${makerStarted ? 'on' : 'off'}${coinjoinInProcess ? ', Coinjoining' : ''}`}
</rb.Navbar.Text>
</rb.Nav>
</div>
</rb.Container>
</rb.Navbar>
<rb.Container as="main" className="py-4">
{connection === false
? <rb.Alert variant="danger">No connection to backend server.</rb.Alert>
: null }
{connection === false &&
<rb.Alert variant="danger">No connection to backend server.</rb.Alert>}
<Switch>
<Route path='/' exact render={props => (
<Wallets currentWallet={currentWallet} activeWallet={activeWallet} walletList={walletList} onDisplay={displayWallet} />
)} />
<Route path='/wallets/current' exact render={props => (
<CurrentWallet currentWallet={currentWallet} activeWallet={activeWallet} onSend={makePayment} listUTXOs={getUTXOs} />
)} />
<Route path='/wallets/create' exact render={props => (
<CreateWallet currentWallet={currentWallet} activeWallet={activeWallet} />
)} />
<Route path='/payment' exact render={props => (
<Payment currentWallet={currentWallet} onPayment={makePayment} onCoinjoin={doCoinjoin} />
)} />
<Route path='/maker' exact render={props => (
<Maker onStart={startMakerService} onStop={stopMakerService} />
)} />
<Route path='/receive' exact render={props => (
<Receive />
)} />
{currentWallet &&
<>
<Route path='/wallets/current' exact render={props => (
<CurrentWallet currentWallet={currentWallet} activeWallet={activeWallet} onSend={makePayment} listUTXOs={getUTXOs} />
)} />
<Route path='/wallets/create' exact render={props => (
<CreateWallet currentWallet={currentWallet} activeWallet={activeWallet} />
)} />
<Route path='/payment' exact render={props => (
<Payment currentWallet={currentWallet} onPayment={makePayment} onCoinjoin={doCoinjoin} />
)} />
<Route path='/maker' exact render={props => (
<Maker onStart={startMakerService} onStop={stopMakerService} />
)} />
<Route path='/receive' exact render={props => (
<Receive />
)} />
</>
}
<Route path='/about' exact render={props => (
<About />
)} />

View file

@ -80,9 +80,7 @@ export default function CreateWallet({ currentWallet, activeWallet }) {
return canCreate
? <rb.Form onSubmit={onSubmit} validated={validated} noValidate>
<h1>Create Wallet</h1>
{alert
? <rb.Alert variant={alert.variant}>{alert.message}</rb.Alert>
: null}
{alert && <rb.Alert variant={alert.variant}>{alert.message}</rb.Alert>}
<rb.Form.Group className="mb-3" controlId="walletName">
<rb.Form.Label>Wallet Name</rb.Form.Label>
<rb.Form.Control name="wallet" style={{ maxWidth: '20em' }} required />

View file

@ -1,13 +1,15 @@
import React from 'react'
import { useState, useEffect } from 'react'
import { Button } from './Button'
import DisplayMixdepth from './DisplayMixdepth'
import * as rb from 'react-bootstrap'
import DisplayMixdepths from './DisplayMixdepths'
import DisplayUTXOs from './DisplayUTXOs'
const CurrentWallet = ({ currentWallet, activeWallet, onSend, listUTXOs }) => {
const [wallet_info, setWalletInfo] = useState([])
const [UTXOHistory, setUTXOHistory] = useState({})
export default function CurrentWallet ({ currentWallet, activeWallet, onSend, listUTXOs }) {
const [wallet_info, setWalletInfo] = useState(null)
const [UTXOHistory, setUTXOHistory] = useState(null)
const [showUTXO, setShowUTXO] = useState(false)
const [alert, setAlert] = useState(null)
const [isLoading, setIsLoading] = useState(false)
const listWalletInfo = async () => {
const { name, token } = currentWallet
@ -16,26 +18,35 @@ const CurrentWallet = ({ currentWallet, activeWallet, onSend, listUTXOs }) => {
return alert(`Please unlock ${name} first`)
}
setAlert(null)
setIsLoading(true)
try {
const res = await fetch(`/api/v1/wallet/${name}/display`, {
headers: {
'Authorization': `Bearer ${token}`
}
})
const { walletinfo } = await res.json()
const balance = walletinfo.total_balance
const mix_depths = walletinfo.accounts
const wallet_info = { balance }
wallet_info[mix_depths[0].account] = mix_depths[0].account_balance
wallet_info[mix_depths[1].account] = mix_depths[1].account_balance
wallet_info[mix_depths[2].account] = mix_depths[2].account_balance
wallet_info[mix_depths[3].account] = mix_depths[3].account_balance
wallet_info[mix_depths[4].account] = mix_depths[4].account_balance
return [walletinfo]
if (res.ok) {
const { walletinfo } = await res.json()
const balance = walletinfo.total_balance
const mix_depths = walletinfo.accounts
const wallet_info = { balance }
wallet_info[mix_depths[0].account] = mix_depths[0].account_balance
wallet_info[mix_depths[1].account] = mix_depths[1].account_balance
wallet_info[mix_depths[2].account] = mix_depths[2].account_balance
wallet_info[mix_depths[3].account] = mix_depths[3].account_balance
wallet_info[mix_depths[4].account] = mix_depths[4].account_balance
return [walletinfo]
} else {
const { message } = await res.json()
setAlert({ variant: 'danger', message })
}
} catch (e) {
console.error(e)
alert('Error while loading.')
setAlert({ variant: 'danger', message: e.message })
} finally {
setIsLoading(false)
}
}
@ -65,14 +76,12 @@ const CurrentWallet = ({ currentWallet, activeWallet, onSend, listUTXOs }) => {
}
const getWalletInfo = async () => {
const wallet_info = await listWalletInfo()
console.log(wallet_info)
setWalletInfo(wallet_info)
}
const getUTXOs = async () => {
const utxos = await listUTXOs()
setUTXOHistory(utxos)
console.log(utxos)
}
getWalletInfo()
@ -82,20 +91,17 @@ const CurrentWallet = ({ currentWallet, activeWallet, onSend, listUTXOs }) => {
return (
<div>
<h1>{activeWallet}</h1>
{wallet_info?.map((walletInfo, index) => {
return <DisplayMixdepth key={index} walletInfo={walletInfo}></DisplayMixdepth>
})}
{alert && <rb.Alert variant={alert.variant}>{alert.message}</rb.Alert>}
{isLoading &&
<>
<rb.Spinner as="span" animation="border" size="sm" role="status" aria-hidden="true" className="me-2" />
Loading
</>}
{wallet_info?.map((walletInfo) => <DisplayMixdepths walletInfo={walletInfo} />)}
<p></p>
<Button onClick={() => { setShowUTXO(!showUTXO) }}>{showUTXO ? 'Hide UTXOs' : 'Show UTXOs'}</Button>
{UTXOHistory && <rb.Button onClick={() => { setShowUTXO(!showUTXO) }}>{showUTXO ? 'Hide UTXOs' : 'Show UTXOs'}</rb.Button>}
<p></p>
{ showUTXO
? Object.entries(UTXOHistory).map(([key, val]) =>
<DisplayUTXOs key={key} utxoID={key} utxo={val}> </DisplayUTXOs>
)
: null
}
{UTXOHistory && showUTXO && <DisplayUTXOs utxos={UTXOHistory} />}
</div>
)
}
export default CurrentWallet

View file

@ -1,18 +0,0 @@
.head {
font-size: small;
}
.address_label {
text-align: right;
padding-right: 7%;
color: rgb(10, 192, 10);
}
.xpub {
text-align: left;
padding-left: 20px;
}
.branch_body{
text-align: left;
}

View file

@ -1,99 +0,0 @@
import React from 'react'
import { Link } from 'react-router-dom'
import * as rb from 'react-bootstrap'
import './DisplayMixdepth.css'
const DisplayMixdepth = ({ walletInfo }) => {
const accounts = []
for (const account_info of walletInfo.accounts) {
accounts.push(account_info)
}
return (
<div>
Total Balance: {walletInfo.total_balance} BTC
<p></p>
<rb.Button href="/maker">Maker Service</rb.Button>
<p></p>
{accounts.map((account, index) => (
<div key={index}>
<rb.Accordion>
<rb.Accordion.Item eventKey={index}>
<rb.Accordion.Header className="head">
<div className="links">
<rb.Container>
<rb.Row>
<rb.Col>
Account {accounts[index].account}
</rb.Col>
<rb.Col>
Balance: {accounts[index].account_balance} BTC
</rb.Col>
<rb.Col>
<Link to={{ pathname: "/payment", state: { account_no: accounts[index].account } }} className="btn btn-primary">Send </Link>{' '}
</rb.Col>
<rb.Col>
<Link to={{ pathname: "/receive", state: { account_no: accounts[index].account } }} className="btn btn-primary">Receive </Link>
</rb.Col>
</rb.Row>
</rb.Container>
</div>
</rb.Accordion.Header>
<rb.Accordion.Body>
<rb.Accordion>
<rb.Accordion.Item eventKey="0">
<rb.Accordion.Header>External Addresses Balance: {accounts[index].branches[0].balance} BTC </rb.Accordion.Header>
<div className="xpub">
Extended Pubkey : {accounts[index].branches[0].branch.split("\t").pop()}
</div>
<rb.Accordion.Body>
{accounts[index].branches[0].entries.map((user, i) => (
<div key={i}>
<rb.Accordion>
<rb.Accordion.Item eventKey="0">
<div className="address_label">
<b>{accounts[index].branches[0].entries[i].labels}</b>
</div>
<rb.Accordion.Header>{accounts[index].branches[0].entries[i].address} {' '} </rb.Accordion.Header>
<rb.Accordion.Body>
<div className="branch-body">
amount: {accounts[index].branches[0].entries[i].amount}
</div>
</rb.Accordion.Body>
</rb.Accordion.Item>
</rb.Accordion>
</div>
))}
</rb.Accordion.Body>
</rb.Accordion.Item>
<rb.Accordion.Item eventKey="1">
<rb.Accordion.Header>Internal Addresses Balance: {accounts[index].branches[1].balance} BTC</rb.Accordion.Header>
<rb.Accordion.Body>
{accounts[index].branches[1].entries.map((user, j) => (
<div key={j}>
<rb.Accordion>
<rb.Accordion.Item eventKey="0">
<rb.Accordion.Header>{accounts[index].branches[0].entries[j].address} {' '} {accounts[index].branches[0].entries[j].labels} </rb.Accordion.Header>
<rb.Accordion.Body>
<div className="branch_body">
amount: {accounts[index].branches[0].entries[j].amount}
</div>
</rb.Accordion.Body>
</rb.Accordion.Item>
</rb.Accordion>
</div>
))}
</rb.Accordion.Body>
</rb.Accordion.Item>
</rb.Accordion>
</rb.Accordion.Body>
</rb.Accordion.Item>
</rb.Accordion>
</div>
))}
</div>
)
}
export default DisplayMixdepth

View file

@ -0,0 +1,94 @@
import React from 'react'
import { Link } from 'react-router-dom'
import * as rb from 'react-bootstrap'
export default function DisplayMixdepths({ walletInfo }) {
const accounts = []
for (const account_info of walletInfo.accounts) {
accounts.push(account_info)
}
return (
<div>
Total Balance: {walletInfo.total_balance} BTC
<p></p>
<rb.Button href="/maker">Maker Service</rb.Button>
<p></p>
<rb.Accordion>
{accounts.map((account, index) => (
<rb.Accordion.Item key={index} eventKey={index}>
<rb.Accordion.Header className="head">
<div className="links">
<rb.Container>
<rb.Row>
<rb.Col>
Account {accounts[index].account}
</rb.Col>
<rb.Col>
Balance: {accounts[index].account_balance} BTC
</rb.Col>
<rb.Col>
<Link to={{ pathname: "/payment", state: { account_no: accounts[index].account } }} className="btn btn-primary">Send </Link>{' '}
</rb.Col>
<rb.Col>
<Link to={{ pathname: "/receive", state: { account_no: accounts[index].account } }} className="btn btn-primary">Receive </Link>
</rb.Col>
</rb.Row>
</rb.Container>
</div>
</rb.Accordion.Header>
<rb.Accordion.Body>
<rb.Accordion>
<rb.Accordion.Item eventKey="0">
<rb.Accordion.Header>External Addresses Balance: {accounts[index].branches[0].balance} BTC </rb.Accordion.Header>
<div className="xpub">
Extended Pubkey : {accounts[index].branches[0].branch.split("\t").pop()}
</div>
<rb.Accordion.Body>
{accounts[index].branches[0].entries.map((user, i) => (
<div key={i}>
<rb.Accordion>
<rb.Accordion.Item eventKey="0">
<div className="address_label">
<b>{accounts[index].branches[0].entries[i].labels}</b>
</div>
<rb.Accordion.Header>{accounts[index].branches[0].entries[i].address} {' '} </rb.Accordion.Header>
<rb.Accordion.Body>
<div className="branch-body">
amount: {accounts[index].branches[0].entries[i].amount}
</div>
</rb.Accordion.Body>
</rb.Accordion.Item>
</rb.Accordion>
</div>
))}
</rb.Accordion.Body>
</rb.Accordion.Item>
<rb.Accordion.Item eventKey="1">
<rb.Accordion.Header>Internal Addresses Balance: {accounts[index].branches[1].balance} BTC</rb.Accordion.Header>
<rb.Accordion.Body>
{accounts[index].branches[1].entries.map((user, j) => (
<div key={j}>
<rb.Accordion>
<rb.Accordion.Item eventKey="0">
<rb.Accordion.Header>{accounts[index].branches[0].entries[j].address} {' '} {accounts[index].branches[0].entries[j].labels} </rb.Accordion.Header>
<rb.Accordion.Body>
<div className="branch_body">
amount: {accounts[index].branches[0].entries[j].amount}
</div>
</rb.Accordion.Body>
</rb.Accordion.Item>
</rb.Accordion>
</div>
))}
</rb.Accordion.Body>
</rb.Accordion.Item>
</rb.Accordion>
</rb.Accordion.Body>
</rb.Accordion.Item>
))}
</rb.Accordion>
</div>
)
}

View file

@ -1,19 +1,42 @@
import React from 'react'
import * as rb from 'react-bootstrap'
const DisplayUTXOs = ({ utxoID, utxo }) => (
<div>
<p></p>
<p></p>
<br></br>
<span>Address: {utxo.address}</span>
<br></br>
<span>Value(Sats): {utxo.value}</span>
<br></br>
<span>Confirmations: {utxo.confirmations}</span>
<br></br>
<span>Mixdepth: {utxo.mixdepth}</span>
<p></p>
</div>
const byMixdepth = utxos => {
const ret = utxos.reduce((res, utxo) => {
const { mixdepth } = utxo
res[mixdepth] = res[mixdepth] || []
res[mixdepth].push(utxo)
return res
}, {})
console.log(ret)
return ret
}
const DisplayUTXOs = ({ utxos }) => (
<rb.Accordion>
{Object.entries(byMixdepth(utxos)).map(([mixdepth, utxos]) => (
<rb.Accordion.Item key={mixdepth} eventKey={mixdepth}>
<rb.Accordion.Header className="head">
Mixdepth {mixdepth}
</rb.Accordion.Header>
<rb.Accordion.Body>
<ul class="list-group list-group-flush">
{utxos.map(utxo => (
<li class="list-group-item">
<span>Address: {utxo.address}</span>
<br></br>
<span>Sats: {utxo.value}</span>
<br></br>
<span>{utxo.confirmations} Confirmations</span>
<pre>{JSON.stringify(utxo, null, 2)}</pre>
</li>
))}
</ul>
</rb.Accordion.Body>
</rb.Accordion.Item>
))}
</rb.Accordion>
)
export default DisplayUTXOs

View file

@ -133,21 +133,20 @@ export default function Wallet({ name, currentWallet, activeWallet, setAlert })
Please remove the lock file on the server.
</rb.Alert>
)
: (noneActive
? <rb.InputGroup>
<rb.FormControl type="password" placeholder="Password" name="password" disabled={isUnlocking} required />
<rb.FormControl type="hidden" name="action" value="unlock" />
<rb.Button variant="primary" type="submit" disabled={isUnlocking}>
{isUnlocking
? <>
<rb.Spinner as="span" animation="border" size="sm" role="status" aria-hidden="true" className="me-2" />
Unlocking
</>
: 'Unlock'}
</rb.Button>
<rb.Form.Control.Feedback type="invalid">Please set the wallet's password.</rb.Form.Control.Feedback>
</rb.InputGroup>
: null)
: (noneActive &&
<rb.InputGroup>
<rb.FormControl type="password" placeholder="Password" name="password" disabled={isUnlocking} required />
<rb.FormControl type="hidden" name="action" value="unlock" />
<rb.Button variant="primary" type="submit" disabled={isUnlocking}>
{isUnlocking
? <>
<rb.Spinner as="span" animation="border" size="sm" role="status" aria-hidden="true" className="me-2" />
Unlocking
</>
: 'Unlock'}
</rb.Button>
<rb.Form.Control.Feedback type="invalid">Please set the wallet's password.</rb.Form.Control.Feedback>
</rb.InputGroup>)
}
</rb.Form>
</rb.Card.Body>

View file

@ -14,9 +14,7 @@ export default function Wallets({ currentWallet, activeWallet, walletList, onDis
return (
<>
<h1>Wallets</h1>
{alert
? <Alert {...alert} />
: null}
{alert && <Alert {...alert} />}
{walletList.map(wallet =>
<Wallet key={wallet} name={wallet} currentWallet={currentWallet} activeWallet={activeWallet} setAlert={setAlert} onDisplay={onDisplay} />)}
</>