diff --git a/src/components/Redistribution.tsx b/src/components/Redistribution.tsx new file mode 100644 index 00000000..1e0c0c86 --- /dev/null +++ b/src/components/Redistribution.tsx @@ -0,0 +1,71 @@ +import { RedistributionState, BZZ, DAI } from '@ethersphere/bee-js' +import { useContext, useEffect, useState } from 'react' +import { Context } from '../providers/Settings' +import ExpandableListItem from './ExpandableListItem' + +export function Redistribution() { + const { beeApi } = useContext(Context) + const [redistributionState, setRedistributionState] = useState(null) + + useEffect(() => { + const interval = setInterval(() => { + if (!beeApi) { + return + } + + beeApi.getRedistributionState().then(setRedistributionState).catch(console.error) // eslint-disable-line + }, 3_000) + + return () => clearInterval(interval) + }) + + const formatDurationSeconds = (s?: number) => { + if (s === null || s === undefined) { + return '-' + } else { + return `${s} s` + } + } + + const formatBzzAmount = (amount?: BZZ) => { + if (amount === null || amount === undefined) { + return '-' + } else { + return `${amount.toSignificantDigits(4)} xBZZ` + } + } + + const formatDaiAmount = (amount?: DAI) => { + if (amount === null || amount === undefined) { + return '-' + } else { + return `${amount.toSignificantDigits(4)} xDAI` + } + } + + return ( + <> + + + + + + + + + + + + + + ) +} diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 027e165e..a2ff20c9 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -8,6 +8,7 @@ import FileManagerIcon from 'remixicon-react/FolderOpenLineIcon' import DocsIcon from 'remixicon-react/BookOpenLineIcon' import ExternalLinkIcon from 'remixicon-react/ExternalLinkLineIcon' import GithubIcon from 'remixicon-react/GithubFillIcon' +import ExchangeDollarLineIcon from 'remixicon-react/ExchangeDollarLineIcon' import HomeIcon from 'remixicon-react/Home3LineIcon' import SettingsIcon from 'remixicon-react/Settings2LineIcon' import AccountIcon from 'remixicon-react/Wallet3LineIcon' @@ -95,6 +96,11 @@ export default function SideBar(): ReactElement { icon: AccountIcon, pathMatcherSubstring: '/account/', }, + { + label: 'Redistribution', + path: ROUTES.REDISTRIBUTION, + icon: ExchangeDollarLineIcon, + }, { label: 'Settings', path: ROUTES.SETTINGS, diff --git a/src/pages/info/index.tsx b/src/pages/info/index.tsx index a0634615..aac2e528 100644 --- a/src/pages/info/index.tsx +++ b/src/pages/info/index.tsx @@ -13,7 +13,7 @@ import NodeInfoCard from './NodeInfoCard' import { WalletInfoCard } from './WalletInfoCard' export default function Status(): ReactElement { - const { beeVersion, status, topology, nodeInfo, walletBalance } = useContext(BeeContext) + const { beeVersion, status, topology, nodeInfo, nodeStatus, walletBalance } = useContext(BeeContext) const { isDesktop, desktopUrl } = useContext(SettingsContext) const { beeDesktopVersion } = useBeeDesktop(isDesktop, desktopUrl) const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isDesktop, desktopUrl, false) @@ -38,7 +38,10 @@ export default function Status(): ReactElement {
+ + +
diff --git a/src/pages/redistribution/index.tsx b/src/pages/redistribution/index.tsx new file mode 100644 index 00000000..dc8bb844 --- /dev/null +++ b/src/pages/redistribution/index.tsx @@ -0,0 +1,25 @@ +import CircularProgress from '@material-ui/core/CircularProgress' +import { ReactElement, useContext } from 'react' +import ExpandableList from '../../components/ExpandableList' +import { Redistribution } from '../../components/Redistribution' +import { Context as SettingsContext } from '../../providers/Settings' + +export default function RedistributionPage(): ReactElement { + const { isLoading } = useContext(SettingsContext) + + if (isLoading) { + return ( +
+ +
+ ) + } + + return ( + <> + + + + + ) +} diff --git a/src/providers/Bee.tsx b/src/providers/Bee.tsx index 41d5595e..7f99b88f 100644 --- a/src/providers/Bee.tsx +++ b/src/providers/Bee.tsx @@ -5,11 +5,13 @@ import { ChainState, ChequebookAddressResponse, ChequebookBalanceResponse, + DebugStatus, LastChequesResponse, NodeAddresses, NodeInfo, Peer, PeerBalance, + RedistributionState, Topology, WalletBalance, } from '@ethersphere/bee-js' @@ -49,6 +51,7 @@ interface ContextInterface { apiHealth: boolean nodeAddresses: NodeAddresses | null nodeInfo: NodeInfo | null + nodeStatus: DebugStatus | null topology: Topology | null chequebookAddress: ChequebookAddressResponse | null peers: Peer[] | null @@ -59,6 +62,7 @@ interface ContextInterface { settlements: AllSettlements | null chainState: ChainState | null walletBalance: WalletBalance | null + redistributionState: RedistributionState | null latestBeeRelease: LatestBeeRelease | null isLoading: boolean lastUpdate: number | null @@ -79,6 +83,7 @@ const initialValues: ContextInterface = { apiHealth: false, nodeAddresses: null, nodeInfo: null, + nodeStatus: null, topology: null, chequebookAddress: null, stake: null, @@ -89,6 +94,7 @@ const initialValues: ContextInterface = { settlements: null, chainState: null, walletBalance: null, + redistributionState: null, latestBeeRelease: null, isLoading: true, lastUpdate: null, @@ -172,6 +178,7 @@ export function Provider({ children }: Props): ReactElement { const [apiHealth, setApiHealth] = useState(false) const [nodeAddresses, setNodeAddresses] = useState(null) const [nodeInfo, setNodeInfo] = useState(null) + const [nodeStatus, setNodeStatus] = useState(null) const [topology, setNodeTopology] = useState(null) const [chequebookAddress, setChequebookAddress] = useState(null) const [peers, setPeers] = useState(null) @@ -182,6 +189,7 @@ export function Provider({ children }: Props): ReactElement { const [settlements, setSettlements] = useState(null) const [chainState, setChainState] = useState(null) const [walletBalance, setWalletBalance] = useState(null) + const [redistributionState, setRedistributionState] = useState(null) const [startedAt] = useState(Date.now()) const { latestBeeRelease } = useLatestBeeRelease() @@ -257,6 +265,12 @@ export function Provider({ children }: Props): ReactElement { .then(setNodeInfo) .catch(() => setNodeInfo(null)), + // NodeDebugInfo + beeApi + .getStatus({ timeout: TIMEOUT }) + .then(setNodeStatus) + .catch(() => setNodeInfo(null)), + // Network Topology beeApi .getTopology({ timeout: TIMEOUT }) @@ -304,6 +318,12 @@ export function Provider({ children }: Props): ReactElement { .then(stake => setStake(stake)) .catch(() => setStake(null)), + // Redistribution stats + beeApi + .getRedistributionState({ timeout: TIMEOUT }) + .then(setRedistributionState) + .catch(() => setRedistributionState(null)), + // Peer balances beeApi .getAllBalances({ timeout: TIMEOUT }) @@ -362,6 +382,7 @@ export function Provider({ children }: Props): ReactElement { apiHealth, nodeAddresses, nodeInfo, + nodeStatus, topology, chequebookAddress, peers, @@ -372,6 +393,7 @@ export function Provider({ children }: Props): ReactElement { settlements, chainState, walletBalance, + redistributionState, latestBeeRelease, isLoading, lastUpdate, diff --git a/src/routes.tsx b/src/routes.tsx index 455d316c..30875ce4 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -25,6 +25,7 @@ import { BankCardTopUpIndex } from './pages/top-up/BankCardTopUpIndex' import { CryptoTopUpIndex } from './pages/top-up/CryptoTopUpIndex' import { GiftCardFund } from './pages/top-up/GiftCardFund' import { GiftCardTopUpIndex } from './pages/top-up/GiftCardTopUpIndex' +import RedistributionPage from './pages/redistribution' import { Swap } from './pages/top-up/Swap' import { Context as SettingsContext } from './providers/Settings' import { FileManagerPage } from './pages/filemanager' @@ -37,6 +38,7 @@ export enum ROUTES { UPLOAD_IN_PROGRESS = '/files/upload/workflow', DOWNLOAD = '/files/download', HASH = '/files/hash/:hash', + REDISTRIBUTION = '/redistribution', SETTINGS = '/settings', STATUS = '/status', TOP_UP = '/account/wallet/top-up', @@ -82,6 +84,7 @@ const BaseRouter = (): ReactElement => { } /> } /> } /> + } /> } /> } /> } />