feat: display basic yield generator report (#73)

* feat: display basic yield generator report

* feat: add toggle for yield generator report

* review: use button instead of toggle to show/hide report

* review: better message on yield generator report error
This commit is contained in:
Thebora Kompanioni 2022-02-11 10:09:30 +01:00 committed by GitHub
parent 174726b74f
commit b37de7083e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 177 additions and 69 deletions

View file

@ -1,20 +1,67 @@
import React from 'react'
import { useEffect, useState } from 'react'
import * as rb from 'react-bootstrap'
import { useSettings } from '../context/SettingsContext'
import Sprite from './Sprite'
import * as Api from '../libs/JmWalletApi'
const OFFERTYPE_REL = 'sw0reloffer'
const OFFERTYPE_ABS = 'sw0absoffer'
const YieldgenReport = ({ lines }) => {
const settings = useSettings()
const empty = !lines || lines.length < 2
const headers = empty ? [] : lines[0].split(',')
const linesWithoutHeader = empty
? []
: lines
.slice(1, lines.length)
.map((line) => line.split(','))
.reverse()
return (
<div className="mt-2 mb-3">
{empty && <rb.Alert variant="info">The report is empty.</rb.Alert>}
{!empty && (
<>
<rb.Table striped bordered hover variant={settings.theme} responsive>
<thead>
<tr>
{headers.map((name, index) => (
<th key={`header_${index}`}>{name}</th>
))}
</tr>
</thead>
<tbody>
{linesWithoutHeader.map((line, lineIndex) => (
<tr key={lineIndex}>
{line.map((val, valIndex) => (
<td key={valIndex}>{val}</td>
))}
</tr>
))}
</tbody>
</rb.Table>
</>
)}
</div>
)
}
export default function Earn({ currentWallet, makerRunning }) {
const settings = useSettings()
const [validated, setValidated] = useState(false)
const [alert, setAlert] = useState(null)
const [isSending, setIsSending] = useState(false)
const [isWaiting, setIsWaiting] = useState(false)
const [isReportLoading, setIsReportLoading] = useState(false)
const [isShowReport, setIsShowReport] = useState(false)
const [offertype, setOffertype] = useState(window.localStorage.getItem('jm-offertype') || OFFERTYPE_REL)
const [feeRel, setFeeRel] = useState(parseFloat(window.localStorage.getItem('jm-feeRel')) || 0.0003)
const [feeAbs, setFeeAbs] = useState(parseInt(window.localStorage.getItem('jm-feeAbs'), 10) || 250)
const [minsize, setMinsize] = useState(parseInt(window.localStorage.getItem('jm-minsize'), 10) || 100000)
const [yieldgenReportLines, setYieldgenReportLines] = useState([])
const setAndPersistOffertype = (value) => {
setOffertype(value)
@ -74,6 +121,30 @@ export default function Earn({ currentWallet, makerRunning }) {
setAlert(null)
}, [makerRunning])
useEffect(() => {
if (!isShowReport) return
const abortCtrl = new AbortController()
setIsReportLoading(true)
Api.getYieldgenReport({ signal: abortCtrl.signal })
.then((res) => {
if (res.ok) return res.json()
// 404 is returned till the maker is started at least once
if (res.status === 404) return {}
return Promise.reject(new Error(res.message || 'Failed to load yield generator report.'))
})
.then((data) => setYieldgenReportLines(data.yigen_data))
.catch((err) => {
console.log(`Error while loading yield generator`, err)
})
// show the loader a little longer to avoid flickering
.then((_) => new Promise((r) => setTimeout(r, 200)))
.finally(() => setIsReportLoading(false))
return () => abortCtrl.abort()
}, [makerRunning, isShowReport])
const stopMakerService = async () => {
const { name: walletName, token } = currentWallet
@ -118,79 +189,109 @@ export default function Earn({ currentWallet, makerRunning }) {
const isRelOffer = offertype === OFFERTYPE_REL
return (
<rb.Form onSubmit={onSubmit} validated={validated} noValidate>
<>
{alert && <rb.Alert variant={alert.variant}>{alert.message}</rb.Alert>}
<p>Service {makerRunning ? 'running' : 'not running'}.</p>
{!makerRunning && !isWaiting && (
<>
<rb.Form.Group className="mb-3" controlId="offertype">
<rb.Form.Check
type="switch"
label="Relative offer"
checked={isRelOffer}
onChange={(e) => setAndPersistOffertype(e.target.checked ? OFFERTYPE_REL : OFFERTYPE_ABS)}
/>
</rb.Form.Group>
{isRelOffer ? (
<rb.Form.Group className="mb-3" controlId="feeRel">
<rb.Form.Label>Relative Fee (percent)</rb.Form.Label>
<rb.Form.Control
type="number"
name="feeRel"
required
step={0.0001}
value={feeRel}
min={0}
max={0.1}
style={{ width: '16ch' }}
onChange={(e) => setAndPersistFeeRel(e.target.value)}
/>
<rb.Form.Control.Feedback type="invalid">Please provide a relative fee.</rb.Form.Control.Feedback>
</rb.Form.Group>
) : (
<rb.Form.Group className="mb-3" controlId="feeAbs">
<rb.Form.Label>Absolute Fee in SATS</rb.Form.Label>
<rb.Form.Control
type="number"
name="feeAbs"
required
step={1}
value={feeAbs}
min={0}
style={{ width: '16ch' }}
onChange={(e) => setAndPersistFeeAbs(e.target.value)}
/>
<rb.Form.Control.Feedback type="invalid">Please provide an absolute fee.</rb.Form.Control.Feedback>
</rb.Form.Group>
)}
<rb.Form.Group className="mb-3" controlId="minsize">
<rb.Form.Label>Minimum amount in SATS</rb.Form.Label>
<rb.Form.Control
type="number"
name="minsize"
required
step={1000}
value={minsize}
min={0}
style={{ width: '16ch' }}
onChange={(e) => setAndPersistMinsize(e.target.value)}
/>
<rb.Form.Control.Feedback type="invalid">Please provide a minimum amount.</rb.Form.Control.Feedback>
</rb.Form.Group>
</>
)}
<rb.Button variant="dark" type="submit" disabled={isSending}>
{isSending ? (
<rb.Form onSubmit={onSubmit} validated={validated} noValidate>
{!makerRunning && !isWaiting && (
<>
<rb.Spinner as="span" animation="border" size="sm" role="status" aria-hidden="true" className="me-2" />
{makerRunning === true ? 'Stopping' : 'Starting'}
<rb.Form.Group className="mb-3" controlId="offertype">
<rb.Form.Check
type="switch"
label="Relative offer"
checked={isRelOffer}
onChange={(e) => setAndPersistOffertype(e.target.checked ? OFFERTYPE_REL : OFFERTYPE_ABS)}
/>
</rb.Form.Group>
{isRelOffer ? (
<rb.Form.Group className="mb-3" controlId="feeRel">
<rb.Form.Label>Relative Fee (percent)</rb.Form.Label>
<rb.Form.Control
type="number"
name="feeRel"
required
step={0.0001}
value={feeRel}
min={0}
max={0.1}
style={{ width: '16ch' }}
onChange={(e) => setAndPersistFeeRel(e.target.value)}
/>
<rb.Form.Control.Feedback type="invalid">Please provide a relative fee.</rb.Form.Control.Feedback>
</rb.Form.Group>
) : (
<rb.Form.Group className="mb-3" controlId="feeAbs">
<rb.Form.Label>Absolute Fee in SATS</rb.Form.Label>
<rb.Form.Control
type="number"
name="feeAbs"
required
step={1}
value={feeAbs}
min={0}
style={{ width: '16ch' }}
onChange={(e) => setAndPersistFeeAbs(e.target.value)}
/>
<rb.Form.Control.Feedback type="invalid">Please provide an absolute fee.</rb.Form.Control.Feedback>
</rb.Form.Group>
)}
<rb.Form.Group className="mb-3" controlId="minsize">
<rb.Form.Label>Minimum amount in SATS</rb.Form.Label>
<rb.Form.Control
type="number"
name="minsize"
required
step={1000}
value={minsize}
min={0}
style={{ width: '16ch' }}
onChange={(e) => setAndPersistMinsize(e.target.value)}
/>
<rb.Form.Control.Feedback type="invalid">Please provide a minimum amount.</rb.Form.Control.Feedback>
</rb.Form.Group>
</>
) : makerRunning === true ? (
'Stop'
) : (
'Start'
)}
</rb.Button>
</rb.Form>
<rb.Button variant="dark" type="submit" disabled={isSending || isWaiting}>
{isSending ? (
<>
<rb.Spinner as="span" animation="border" size="sm" role="status" aria-hidden="true" className="me-2" />
{makerRunning === true ? 'Stopping' : 'Starting'}
</>
) : makerRunning === true ? (
'Stop'
) : (
'Start'
)}
</rb.Button>
</rb.Form>
{settings.useAdvancedWalletMode && (
<div className="mt-5 mb-3 pe-3">
<h6>Report</h6>
<rb.Button
variant="outline-dark"
className="border-0 mb-2 d-inline-flex align-items-center"
onClick={(e) => {
e.preventDefault()
setIsShowReport(!isShowReport)
}}
>
<Sprite symbol={isShowReport ? 'hide' : 'show'} width="24" height="24" className="me-2" />
{isShowReport ? 'Hide' : 'Show'} report
{isReportLoading && (
<rb.Spinner
as="span"
animation="border"
size="sm"
role="status"
aria-hidden="true"
className="ms-2 me-1"
/>
)}
</rb.Button>
{isShowReport && <YieldgenReport lines={yieldgenReportLines} />}
</div>
)}
</>
)
}

View file

@ -124,6 +124,12 @@ const postCoinjoin = async ({ walletName, token }, { account, destination, amoun
})
}
const getYieldgenReport = async ({ signal }) => {
return await fetch(`/api/v1/wallet/yieldgen/report`, {
signal,
})
}
export {
postMakerStart,
getMakerStop,
@ -137,4 +143,5 @@ export {
getWalletLock,
postWalletUnlock,
getWalletUtxos,
getYieldgenReport,
}