feat: add account tabs (#378)
* feat: add account tabs * chore: bump * refactor: change network tab for old accounting * feat: new fonts and text transformation, chequebook tab * feat: polishing
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { createStyles, makeStyles, Tab, Tabs, Theme } from '@material-ui/core'
|
||||
import { ReactElement } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { ACCOUNT_TABS } from '../../routes'
|
||||
|
||||
const tabMap = {
|
||||
WALLET: 0,
|
||||
CHEQUEBOOK: 1,
|
||||
STAMPS: 2,
|
||||
FEEDS: 3,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
active: 'WALLET' | 'CHEQUEBOOK' | 'STAMPS' | 'FEEDS'
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
flexGrow: 1,
|
||||
marginBottom: theme.spacing(4),
|
||||
textTransform: 'none',
|
||||
},
|
||||
leftTab: {
|
||||
marginRight: theme.spacing(0.125),
|
||||
},
|
||||
centerTab: {
|
||||
marginLeft: theme.spacing(0.125),
|
||||
marginRight: theme.spacing(0.125),
|
||||
},
|
||||
rightTab: {
|
||||
marginLeft: theme.spacing(0.125),
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
export function AccountNavigation({ active }: Props): ReactElement {
|
||||
const classes = useStyles()
|
||||
const navigate = useNavigate()
|
||||
|
||||
function onChange(event: React.ChangeEvent<Record<string, never>>, newValue: number) {
|
||||
navigate(ACCOUNT_TABS[newValue])
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Tabs value={tabMap[active]} onChange={onChange} variant="fullWidth">
|
||||
<Tab className={classes.leftTab} key="WALLET" label="Wallet" />
|
||||
<Tab className={classes.centerTab} key="CHEQUEBOOK" label="Chequebook" />
|
||||
<Tab className={classes.centerTab} key="STAMPS" label="Stamps" />
|
||||
<Tab className={classes.rightTab} key="FEEDS" label="Feeds" />
|
||||
</Tabs>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Box, Typography } from '@material-ui/core'
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
export function Header(): ReactElement {
|
||||
return (
|
||||
<Box mb={4}>
|
||||
<Typography variant="h1">Account</Typography>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { ReactElement, useContext } from 'react'
|
||||
import ExpandableList from '../../../components/ExpandableList'
|
||||
import ExpandableListItem from '../../../components/ExpandableListItem'
|
||||
import ExpandableListItemActions from '../../../components/ExpandableListItemActions'
|
||||
import ExpandableListItemKey from '../../../components/ExpandableListItemKey'
|
||||
import TroubleshootConnectionCard from '../../../components/TroubleshootConnectionCard'
|
||||
import DepositModal from '../../../containers/DepositModal'
|
||||
import WithdrawModal from '../../../containers/WithdrawModal'
|
||||
import { useAccounting } from '../../../hooks/accounting'
|
||||
import { CheckState, Context as BeeContext } from '../../../providers/Bee'
|
||||
import { Context as SettingsContext } from '../../../providers/Settings'
|
||||
import PeerBalances from '../../accounting/PeerBalances'
|
||||
import { AccountNavigation } from '../AccountNavigation'
|
||||
import { Header } from '../Header'
|
||||
|
||||
export function AccountChequebook(): ReactElement {
|
||||
const { status, nodeAddresses, chequebookAddress, chequebookBalance, settlements, peerBalances } =
|
||||
useContext(BeeContext)
|
||||
const { beeDebugApi } = useContext(SettingsContext)
|
||||
|
||||
const { accounting, totalUncashed, isLoadingUncashed } = useAccounting(beeDebugApi, settlements, peerBalances)
|
||||
|
||||
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<AccountNavigation active="CHEQUEBOOK" />
|
||||
<div>
|
||||
<ExpandableList label="Chequebook" defaultOpen>
|
||||
<ExpandableListItem label="Total Balance" value={`${chequebookBalance?.totalBalance.toFixedDecimal()} BZZ`} />
|
||||
<ExpandableListItem
|
||||
label="Available Uncommitted Balance"
|
||||
value={`${chequebookBalance?.availableBalance.toFixedDecimal()} BZZ`}
|
||||
/>
|
||||
<ExpandableListItem
|
||||
label="Total Cheques Amount Sent"
|
||||
value={`${settlements?.totalSent.toFixedDecimal()} BZZ`}
|
||||
/>
|
||||
<ExpandableListItem
|
||||
label="Total Cheques Amount Received"
|
||||
value={`${settlements?.totalReceived.toFixedDecimal()} BZZ`}
|
||||
/>
|
||||
<ExpandableListItemActions>
|
||||
<WithdrawModal />
|
||||
<DepositModal />
|
||||
</ExpandableListItemActions>
|
||||
</ExpandableList>
|
||||
<ExpandableList label="Blockchain" defaultOpen>
|
||||
<ExpandableListItemKey label="Ethereum address" value={nodeAddresses?.ethereum || ''} />
|
||||
<ExpandableListItemKey
|
||||
label="Chequebook contract address"
|
||||
value={chequebookAddress?.chequebookAddress || ''}
|
||||
/>
|
||||
</ExpandableList>
|
||||
<PeerBalances accounting={accounting} isLoadingUncashed={isLoadingUncashed} totalUncashed={totalUncashed} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import { Box } from '@material-ui/core'
|
||||
import { ReactElement, useContext, useState } from 'react'
|
||||
import { Download, Info, PlusSquare, Trash } from 'react-feather'
|
||||
import { useNavigate } from 'react-router'
|
||||
import ExpandableList from '../../../components/ExpandableList'
|
||||
import ExpandableListItem from '../../../components/ExpandableListItem'
|
||||
import ExpandableListItemActions from '../../../components/ExpandableListItemActions'
|
||||
import ExpandableListItemKey from '../../../components/ExpandableListItemKey'
|
||||
import { SwarmButton } from '../../../components/SwarmButton'
|
||||
import { Context as IdentityContext, Identity } from '../../../providers/Feeds'
|
||||
import { ROUTES } from '../../../routes'
|
||||
import { formatEnum } from '../../../utils'
|
||||
import { persistIdentitiesWithoutUpdate } from '../../../utils/identity'
|
||||
import { DeleteFeedDialog } from '../../feeds/DeleteFeedDialog'
|
||||
import { ExportFeedDialog } from '../../feeds/ExportFeedDialog'
|
||||
import { ImportFeedDialog } from '../../feeds/ImportFeedDialog'
|
||||
import { AccountNavigation } from '../AccountNavigation'
|
||||
import { Header } from '../Header'
|
||||
|
||||
export function AccountFeeds(): ReactElement {
|
||||
const { identities, setIdentities } = useContext(IdentityContext)
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [selectedIdentity, setSelectedIdentity] = useState<Identity | null>(null)
|
||||
const [showImport, setShowImport] = useState(false)
|
||||
const [showExport, setShowExport] = useState(false)
|
||||
const [showDelete, setShowDelete] = useState(false)
|
||||
|
||||
function createNewFeed() {
|
||||
return navigate(ROUTES.ACCOUNT_FEEDS_NEW)
|
||||
}
|
||||
|
||||
function viewFeed(uuid: string) {
|
||||
navigate(ROUTES.ACCOUNT_FEEDS_VIEW.replace(':uuid', uuid))
|
||||
}
|
||||
|
||||
function onDialogClose() {
|
||||
setShowDelete(false)
|
||||
setShowExport(false)
|
||||
setShowImport(false)
|
||||
setSelectedIdentity(null)
|
||||
}
|
||||
|
||||
function onDelete(identity: Identity) {
|
||||
onDialogClose()
|
||||
const updatedFeeds = identities.filter(x => x.uuid !== identity.uuid)
|
||||
setIdentities(updatedFeeds)
|
||||
persistIdentitiesWithoutUpdate(updatedFeeds)
|
||||
}
|
||||
|
||||
function onShowExport(identity: Identity) {
|
||||
setSelectedIdentity(identity)
|
||||
setShowExport(true)
|
||||
}
|
||||
|
||||
function onShowDelete(identity: Identity) {
|
||||
setSelectedIdentity(identity)
|
||||
setShowDelete(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<AccountNavigation active="FEEDS" />
|
||||
{showImport && <ImportFeedDialog onClose={() => setShowImport(false)} />}
|
||||
{showExport && selectedIdentity && <ExportFeedDialog identity={selectedIdentity} onClose={onDialogClose} />}
|
||||
{showDelete && selectedIdentity && (
|
||||
<DeleteFeedDialog
|
||||
identity={selectedIdentity}
|
||||
onClose={onDialogClose}
|
||||
onConfirm={(identity: Identity) => onDelete(identity)}
|
||||
/>
|
||||
)}
|
||||
<Box mb={4}>
|
||||
<ExpandableListItemActions>
|
||||
<SwarmButton iconType={PlusSquare} onClick={createNewFeed}>
|
||||
Create New Feed
|
||||
</SwarmButton>
|
||||
<SwarmButton iconType={PlusSquare} onClick={() => setShowImport(true)}>
|
||||
Import Feed
|
||||
</SwarmButton>
|
||||
</ExpandableListItemActions>
|
||||
</Box>
|
||||
{identities.map((x, i) => (
|
||||
<ExpandableList key={i} label={`${x.name} Website`} defaultOpen>
|
||||
<Box mb={0.5}>
|
||||
<ExpandableList label={x.name} level={1}>
|
||||
<ExpandableListItemKey label="Identity address" value={x.address} />
|
||||
<ExpandableListItem label="Identity type" value={formatEnum(x.type)} />
|
||||
</ExpandableList>
|
||||
</Box>
|
||||
<ExpandableListItemKey label="Topic" value={'00'.repeat(32)} />
|
||||
{x.feedHash && <ExpandableListItemKey label="Feed hash" value={x.feedHash} />}
|
||||
<Box mt={0.75}>
|
||||
<ExpandableListItemActions>
|
||||
<SwarmButton onClick={() => viewFeed(x.uuid)} iconType={Info}>
|
||||
View Feed Page
|
||||
</SwarmButton>
|
||||
<SwarmButton onClick={() => onShowExport(x)} iconType={Download}>
|
||||
Export...
|
||||
</SwarmButton>
|
||||
<SwarmButton onClick={() => onShowDelete(x)} iconType={Trash}>
|
||||
Delete...
|
||||
</SwarmButton>
|
||||
</ExpandableListItemActions>
|
||||
</Box>
|
||||
</ExpandableList>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { CircularProgress, Container, createStyles, makeStyles } from '@material-ui/core'
|
||||
import { ReactElement, useContext, useEffect } from 'react'
|
||||
import { PlusSquare } from 'react-feather'
|
||||
import { useNavigate } from 'react-router'
|
||||
import { SwarmButton } from '../../../components/SwarmButton'
|
||||
import TroubleshootConnectionCard from '../../../components/TroubleshootConnectionCard'
|
||||
import { CheckState, Context as BeeContext } from '../../../providers/Bee'
|
||||
import { Context as StampsContext } from '../../../providers/Stamps'
|
||||
import { ROUTES } from '../../../routes'
|
||||
import StampsTable from '../../stamps/StampsTable'
|
||||
import { AccountNavigation } from '../AccountNavigation'
|
||||
import { Header } from '../Header'
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
root: {
|
||||
width: '100%',
|
||||
display: 'grid',
|
||||
},
|
||||
actions: {
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flex: '0 1 auto',
|
||||
flexWrap: 'wrap',
|
||||
alignItems: 'center',
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
export function AccountStamps(): ReactElement {
|
||||
const classes = useStyles()
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
const { stamps, isLoading, error, start, stop } = useContext(StampsContext)
|
||||
const { status } = useContext(BeeContext)
|
||||
|
||||
useEffect(() => {
|
||||
if (!status.all) return
|
||||
start()
|
||||
|
||||
return () => stop()
|
||||
}, [status]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
|
||||
|
||||
function navigateToNewStamp() {
|
||||
navigate(ROUTES.ACCOUNT_STAMPS_NEW)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<AccountNavigation active="STAMPS" />
|
||||
<div className={classes.root}>
|
||||
{error && (
|
||||
<Container style={{ textAlign: 'center', padding: '50px' }}>
|
||||
Error loading postage stamps details: {error.message}
|
||||
</Container>
|
||||
)}
|
||||
{!error && (
|
||||
<>
|
||||
<div className={classes.actions}>
|
||||
<SwarmButton onClick={navigateToNewStamp} iconType={PlusSquare}>
|
||||
Buy New Postage Stamp
|
||||
</SwarmButton>
|
||||
<div style={{ height: '5px' }}>{isLoading && <CircularProgress />}</div>
|
||||
</div>
|
||||
<StampsTable postageStamps={stamps} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Box, Grid, Typography } from '@material-ui/core'
|
||||
import { ReactElement, useContext } from 'react'
|
||||
import { Download, Gift, Link } from 'react-feather'
|
||||
import { useNavigate } from 'react-router'
|
||||
import ExpandableListItem from '../../../components/ExpandableListItem'
|
||||
import ExpandableListItemActions from '../../../components/ExpandableListItemActions'
|
||||
import ExpandableListItemKey from '../../../components/ExpandableListItemKey'
|
||||
import { Loading } from '../../../components/Loading'
|
||||
import { SwarmButton } from '../../../components/SwarmButton'
|
||||
import { Context } from '../../../providers/Bee'
|
||||
import { ROUTES } from '../../../routes'
|
||||
import { AccountNavigation } from '../AccountNavigation'
|
||||
import { Header } from '../Header'
|
||||
|
||||
export function AccountWallet(): ReactElement {
|
||||
const { balance } = useContext(Context)
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
if (!balance) {
|
||||
return <Loading />
|
||||
}
|
||||
|
||||
function onCheckTransactions() {
|
||||
window.open(`https://blockscout.com/xdai/mainnet/address/${balance?.address}/transactions`, '_blank')
|
||||
}
|
||||
|
||||
function onInvite() {
|
||||
navigate(ROUTES.ACCOUNT_INVITATIONS)
|
||||
}
|
||||
|
||||
function onDeposit() {
|
||||
navigate(ROUTES.WALLET)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<AccountNavigation active="WALLET" />
|
||||
<Box mb={4}>
|
||||
<Grid container direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Typography variant="h2">Wallet balance</Typography>
|
||||
<SwarmButton onClick={onDeposit} iconType={Download}>
|
||||
Deposit
|
||||
</SwarmButton>
|
||||
</Grid>
|
||||
</Box>
|
||||
<Box mb={0.25}>
|
||||
<ExpandableListItemKey label="Node wallet address" value={balance.address} expanded />
|
||||
</Box>
|
||||
<Box mb={0.25}>
|
||||
<ExpandableListItem label="XDAI balance" value={`${balance.dai.toSignificantDigits(4)} XDAI`} />
|
||||
</Box>
|
||||
<Box mb={2}>
|
||||
<ExpandableListItem label="BZZ balance" value={`${balance.bzz.toSignificantDigits(4)} BZZ`} />
|
||||
</Box>
|
||||
<ExpandableListItemActions>
|
||||
<SwarmButton onClick={onCheckTransactions} iconType={Link}>
|
||||
Check transactions on Blockscout
|
||||
</SwarmButton>
|
||||
<SwarmButton onClick={onInvite} iconType={Gift}>
|
||||
Invite to Swarm...
|
||||
</SwarmButton>
|
||||
</ExpandableListItemActions>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user