diff --git a/src/App.css b/src/App.css index 585a1c1..f5a74ea 100644 --- a/src/App.css +++ b/src/App.css @@ -1,63 +1,28 @@ @font-face { - font-family: 'Work Sans'; + font-family: 'iAWriterQuattroV'; font-style: normal; font-weight: 300; font-display: swap; - src: url(assets/fonts/WorkSans/WorkSans-Light.ttf) format('truetype'); + src: url(assets/fonts/iAWriterQuattroV.ttf) format('truetype'); } + @font-face { - font-family: 'Work Sans'; + font-family: 'iAWriterMonoV'; font-style: normal; - font-weight: 400; - font-display: swap; - src: url(assets/fonts/WorkSans/WorkSans-Regular.ttf) format('truetype'); -} -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: url(assets/fonts/WorkSans/WorkSans-Medium.ttf) format('truetype'); -} -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 600; - font-display: swap; - src: url(assets/fonts/WorkSans/WorkSans-SemiBold.ttf) format('truetype'); -} -@font-face { - font-family: 'IBMPlexMono500'; - src: url(assets/fonts/IBMPlexMono500.ttf) format('truetype'); - font-weight: 500; -} -@font-face { - font-family: 'IBMPlexMono600'; - src: url(assets/fonts/IBMPlexMono600.ttf) format('truetype'); - font-weight: 600; -} -@font-face { - font-family: 'IBMPlexMonoregular'; - src: url(assets/fonts/IBMPlexMonoregular.ttf) format('truetype'); font-weight: 300; -} -@font-face { - font-family: 'WorkSans-Italic-VariableFont_wght'; - src: url(assets/fonts/WorkSans-Italic-VariableFont_wght.ttf) format('truetype'); - font-weight: 700; -} -@font-face { - font-family: 'WorkSans-VariableFont_wght'; - src: url(assets/fonts/WorkSans-VariableFont_wght.ttf) format('truetype'); - font-weight: 400; + font-display: swap; + src: url(assets/fonts/iAWriterMonoV.ttf) format('truetype'); } .App { - font-family: 'Work Sans', 'Helvetica Neue', HelveticaNeue, Helvetica, Arial, sans-serif; + font-family: 'iAWriterQuattroV', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', + 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } a, button { - font-family: 'IBMPlexMono500' !important; + font-family: 'iAWriterMonoV' !important; color: #dd7700; } diff --git a/src/assets/fonts/IBMPlexMono500.ttf b/src/assets/fonts/IBMPlexMono500.ttf deleted file mode 100644 index cd02e15..0000000 Binary files a/src/assets/fonts/IBMPlexMono500.ttf and /dev/null differ diff --git a/src/assets/fonts/IBMPlexMono500.woff b/src/assets/fonts/IBMPlexMono500.woff deleted file mode 100644 index 3fb3849..0000000 Binary files a/src/assets/fonts/IBMPlexMono500.woff and /dev/null differ diff --git a/src/assets/fonts/IBMPlexMono600.ttf b/src/assets/fonts/IBMPlexMono600.ttf deleted file mode 100644 index e485804..0000000 Binary files a/src/assets/fonts/IBMPlexMono600.ttf and /dev/null differ diff --git a/src/assets/fonts/IBMPlexMono600.woff b/src/assets/fonts/IBMPlexMono600.woff deleted file mode 100644 index f30e58f..0000000 Binary files a/src/assets/fonts/IBMPlexMono600.woff and /dev/null differ diff --git a/src/assets/fonts/IBMPlexMonoRegular.woff b/src/assets/fonts/IBMPlexMonoRegular.woff deleted file mode 100644 index 000a393..0000000 Binary files a/src/assets/fonts/IBMPlexMonoRegular.woff and /dev/null differ diff --git a/src/assets/fonts/IBMPlexMonoregular.ttf b/src/assets/fonts/IBMPlexMonoregular.ttf deleted file mode 100644 index f99c8e9..0000000 Binary files a/src/assets/fonts/IBMPlexMonoregular.ttf and /dev/null differ diff --git a/src/assets/fonts/SourceCodePro-Medium.ttf b/src/assets/fonts/SourceCodePro-Medium.ttf deleted file mode 100644 index 6450399..0000000 Binary files a/src/assets/fonts/SourceCodePro-Medium.ttf and /dev/null differ diff --git a/src/assets/fonts/SourceCodePro-Regular.ttf b/src/assets/fonts/SourceCodePro-Regular.ttf deleted file mode 100644 index 3563e73..0000000 Binary files a/src/assets/fonts/SourceCodePro-Regular.ttf and /dev/null differ diff --git a/src/assets/fonts/SourceCodePro-SemiBold.ttf b/src/assets/fonts/SourceCodePro-SemiBold.ttf deleted file mode 100644 index 526be56..0000000 Binary files a/src/assets/fonts/SourceCodePro-SemiBold.ttf and /dev/null differ diff --git a/src/assets/fonts/SpaceMono-Bold.ttf b/src/assets/fonts/SpaceMono-Bold.ttf deleted file mode 100644 index 18b8aea..0000000 Binary files a/src/assets/fonts/SpaceMono-Bold.ttf and /dev/null differ diff --git a/src/assets/fonts/SpaceMono-Regular.ttf b/src/assets/fonts/SpaceMono-Regular.ttf deleted file mode 100644 index 3374aca..0000000 Binary files a/src/assets/fonts/SpaceMono-Regular.ttf and /dev/null differ diff --git a/src/assets/fonts/WorkSans-Italic-VariableFont_wght.ttf b/src/assets/fonts/WorkSans-Italic-VariableFont_wght.ttf deleted file mode 100644 index dd9d85c..0000000 Binary files a/src/assets/fonts/WorkSans-Italic-VariableFont_wght.ttf and /dev/null differ diff --git a/src/assets/fonts/WorkSans-VariableFont_wght.ttf b/src/assets/fonts/WorkSans-VariableFont_wght.ttf deleted file mode 100644 index 34f0583..0000000 Binary files a/src/assets/fonts/WorkSans-VariableFont_wght.ttf and /dev/null differ diff --git a/src/assets/fonts/WorkSans/WorkSans-Light.ttf b/src/assets/fonts/WorkSans/WorkSans-Light.ttf deleted file mode 100644 index ac80535..0000000 Binary files a/src/assets/fonts/WorkSans/WorkSans-Light.ttf and /dev/null differ diff --git a/src/assets/fonts/WorkSans/WorkSans-Medium.ttf b/src/assets/fonts/WorkSans/WorkSans-Medium.ttf deleted file mode 100644 index 11e3dda..0000000 Binary files a/src/assets/fonts/WorkSans/WorkSans-Medium.ttf and /dev/null differ diff --git a/src/assets/fonts/WorkSans/WorkSans-Regular.ttf b/src/assets/fonts/WorkSans/WorkSans-Regular.ttf deleted file mode 100644 index 92cd6d4..0000000 Binary files a/src/assets/fonts/WorkSans/WorkSans-Regular.ttf and /dev/null differ diff --git a/src/assets/fonts/WorkSans/WorkSans-SemiBold.ttf b/src/assets/fonts/WorkSans/WorkSans-SemiBold.ttf deleted file mode 100644 index fa0af5b..0000000 Binary files a/src/assets/fonts/WorkSans/WorkSans-SemiBold.ttf and /dev/null differ diff --git a/src/assets/fonts/WorkSans500.woff b/src/assets/fonts/WorkSans500.woff deleted file mode 100644 index afd29fb..0000000 Binary files a/src/assets/fonts/WorkSans500.woff and /dev/null differ diff --git a/src/assets/fonts/WorkSansRegular.woff b/src/assets/fonts/WorkSansRegular.woff deleted file mode 100644 index 5de8ad6..0000000 Binary files a/src/assets/fonts/WorkSansRegular.woff and /dev/null differ diff --git a/src/assets/fonts/iAWriterMonoV.ttf b/src/assets/fonts/iAWriterMonoV.ttf new file mode 100644 index 0000000..8bdb5e2 Binary files /dev/null and b/src/assets/fonts/iAWriterMonoV.ttf differ diff --git a/src/assets/fonts/iAWriterQuattroV.ttf b/src/assets/fonts/iAWriterQuattroV.ttf new file mode 100644 index 0000000..6d50c14 Binary files /dev/null and b/src/assets/fonts/iAWriterQuattroV.ttf differ diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 0348828..2626e67 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -1,11 +1,13 @@ +import { BeeModes } from '@ethersphere/bee-js' import { Divider, Drawer, Grid, Link as MUILink, List } from '@material-ui/core' import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' import { OpenInNewSharp } from '@material-ui/icons' -import type { ReactElement } from 'react' -import { Bookmark, BookOpen, Briefcase, DollarSign, FileText, Gift, Home, Layers, Settings } from 'react-feather' +import { ReactElement, useContext } from 'react' +import { BookOpen, Briefcase, DollarSign, FileText, Home, Settings } from 'react-feather' import { Link } from 'react-router-dom' import Logo from '../assets/logo.svg' import { config } from '../config' +import { Context } from '../providers/Bee' import { ROUTES } from '../routes' import SideBarItem from './SideBarItem' import SideBarStatus from './SideBarStatus' @@ -22,35 +24,22 @@ const navBarItems = [ icon: FileText, }, { - label: 'Feeds', - path: ROUTES.FEEDS, - icon: Bookmark, + label: 'Account', + path: ROUTES.ACCOUNT_WALLET, + icon: Briefcase, + pathMatcherSubstring: '/account/', }, { - label: 'Stamps', - path: ROUTES.STAMPS, - icon: Layers, - }, - { - label: 'Accounting', - path: ROUTES.ACCOUNTING, + label: 'Top Up', + path: ROUTES.WALLET, icon: DollarSign, + requiresMode: BeeModes.ULTRA_LIGHT, }, { label: 'Settings', path: ROUTES.SETTINGS, icon: Settings, }, - { - label: 'Account', - path: ROUTES.WALLET, - icon: Briefcase, - }, - { - label: 'Gift Wallets', - path: ROUTES.GIFT_CODES, - icon: Gift, - }, ] const drawerWidth = 300 @@ -103,6 +92,7 @@ const useStyles = makeStyles((theme: Theme) => export default function SideBar(): ReactElement { const classes = useStyles() + const { nodeInfo } = useContext(Context) return ( @@ -114,16 +104,19 @@ export default function SideBar(): ReactElement { - {navBarItems.map(p => ( - - } - path={p.path} - label={p.label} - /> - - ))} + {navBarItems + .filter(p => !p.requiresMode || nodeInfo?.beeMode === p.requiresMode) + .map(p => ( + + } + path={p.path} + pathMatcherSubstring={p.pathMatcherSubstring} + label={p.label} + /> + + ))} diff --git a/src/components/SideBarItem.tsx b/src/components/SideBarItem.tsx index 0c57082..f4d6f88 100644 --- a/src/components/SideBarItem.tsx +++ b/src/components/SideBarItem.tsx @@ -1,8 +1,7 @@ +import { ListItem, ListItemIcon, ListItemText } from '@material-ui/core' +import { createStyles, makeStyles, Theme, withStyles } from '@material-ui/core/styles' import type { ReactElement, ReactNode } from 'react' -import { useLocation, matchPath } from 'react-router-dom' - -import { createStyles, Theme, makeStyles, withStyles } from '@material-ui/core/styles' -import { ListItemText, ListItemIcon, ListItem } from '@material-ui/core' +import { matchPath, useLocation } from 'react-router-dom' const StyledListItem = withStyles((theme: Theme) => ({ root: { @@ -45,12 +44,15 @@ interface Props { iconEnd?: ReactNode path?: string label: ReactNode + pathMatcherSubstring?: string } -export default function SideBarItem({ iconStart, iconEnd, path, label }: Props): ReactElement { +export default function SideBarItem({ iconStart, iconEnd, path, label, pathMatcherSubstring }: Props): ReactElement { const classes = useStyles() const location = useLocation() - const isSelected = Boolean(path && matchPath(location.pathname, path)) + const isSelected = pathMatcherSubstring + ? location.pathname.startsWith(pathMatcherSubstring) + : Boolean(path && matchPath(location.pathname, path)) return ( diff --git a/src/components/SwarmButton.tsx b/src/components/SwarmButton.tsx index 065fb18..84bb5e0 100644 --- a/src/components/SwarmButton.tsx +++ b/src/components/SwarmButton.tsx @@ -16,7 +16,7 @@ interface Props { const useStyles = makeStyles(() => createStyles({ button: { - height: '52px', + height: '42px', position: 'relative', whiteSpace: 'nowrap', color: '#242424', diff --git a/src/index.css b/src/index.css index abbe693..a91ac00 100644 --- a/src/index.css +++ b/src/index.css @@ -2,9 +2,8 @@ body { height: 100vh; min-height: 100vh; margin: 0; - font-family: 'Work Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: 'iAWriterQuattroV', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', + 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } @@ -16,6 +15,5 @@ body { } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } diff --git a/src/pages/account/AccountNavigation.tsx b/src/pages/account/AccountNavigation.tsx new file mode 100644 index 0000000..07172ee --- /dev/null +++ b/src/pages/account/AccountNavigation.tsx @@ -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>, newValue: number) { + navigate(ACCOUNT_TABS[newValue]) + } + + return ( +
+ + + + + + +
+ ) +} diff --git a/src/pages/account/Header.tsx b/src/pages/account/Header.tsx new file mode 100644 index 0000000..afa7263 --- /dev/null +++ b/src/pages/account/Header.tsx @@ -0,0 +1,10 @@ +import { Box, Typography } from '@material-ui/core' +import { ReactElement } from 'react' + +export function Header(): ReactElement { + return ( + + Account + + ) +} diff --git a/src/pages/account/chequebook/AccountChequebook.tsx b/src/pages/account/chequebook/AccountChequebook.tsx new file mode 100644 index 0000000..28f4ae0 --- /dev/null +++ b/src/pages/account/chequebook/AccountChequebook.tsx @@ -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 + + return ( + <> +
+ +
+ + + + + + + + + + + + + + + +
+ + ) +} diff --git a/src/pages/account/feeds/AccountFeeds.tsx b/src/pages/account/feeds/AccountFeeds.tsx new file mode 100644 index 0000000..93706cb --- /dev/null +++ b/src/pages/account/feeds/AccountFeeds.tsx @@ -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(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 ( + <> +
+ + {showImport && setShowImport(false)} />} + {showExport && selectedIdentity && } + {showDelete && selectedIdentity && ( + onDelete(identity)} + /> + )} + + + + Create New Feed + + setShowImport(true)}> + Import Feed + + + + {identities.map((x, i) => ( + + + + + + + + + {x.feedHash && } + + + viewFeed(x.uuid)} iconType={Info}> + View Feed Page + + onShowExport(x)} iconType={Download}> + Export... + + onShowDelete(x)} iconType={Trash}> + Delete... + + + + + ))} + + ) +} diff --git a/src/pages/account/stamps/AccountStamps.tsx b/src/pages/account/stamps/AccountStamps.tsx new file mode 100644 index 0000000..7596110 --- /dev/null +++ b/src/pages/account/stamps/AccountStamps.tsx @@ -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 + + function navigateToNewStamp() { + navigate(ROUTES.ACCOUNT_STAMPS_NEW) + } + + return ( + <> +
+ +
+ {error && ( + + Error loading postage stamps details: {error.message} + + )} + {!error && ( + <> +
+ + Buy New Postage Stamp + +
{isLoading && }
+
+ + + )} +
+ + ) +} diff --git a/src/pages/account/wallet/AccountWallet.tsx b/src/pages/account/wallet/AccountWallet.tsx new file mode 100644 index 0000000..8f4cbda --- /dev/null +++ b/src/pages/account/wallet/AccountWallet.tsx @@ -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 + } + + 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 ( + <> +
+ + + + Wallet balance + + Deposit + + + + + + + + + + + + + + + Check transactions on Blockscout + + + Invite to Swarm... + + + + ) +} diff --git a/src/pages/accounting/index.tsx b/src/pages/accounting/index.tsx deleted file mode 100644 index e588f60..0000000 --- a/src/pages/accounting/index.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { ReactElement, useContext } from 'react' - -import PeerBalances from './PeerBalances' -import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard' -import { CheckState, Context as BeeContext } from '../../providers/Bee' -import { Context as SettingsContext } from '../../providers/Settings' -import { useAccounting } from '../../hooks/accounting' -import ExpandableList from '../../components/ExpandableList' -import ExpandableListItem from '../../components/ExpandableListItem' -import ExpandableListItemActions from '../../components/ExpandableListItemActions' -import ExpandableListItemKey from '../../components/ExpandableListItemKey' -import WithdrawModal from '../../containers/WithdrawModal' -import DepositModal from '../../containers/DepositModal' - -export default function Accounting(): 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 - - return ( -
- - - - - - - - - - - - - - - -
- ) -} diff --git a/src/pages/feeds/CreateNewFeed.tsx b/src/pages/feeds/CreateNewFeed.tsx index 5439aad..2255dd5 100644 --- a/src/pages/feeds/CreateNewFeed.tsx +++ b/src/pages/feeds/CreateNewFeed.tsx @@ -65,7 +65,7 @@ export default function CreateNewFeed(): ReactElement { const identity = await convertWalletToIdentity(wallet, values.type, values.identityName, values.password) persistIdentity(identities, identity) setIdentities(identities) - navigate(ROUTES.FEEDS) + navigate(ROUTES.ACCOUNT_FEEDS) setLoading(false) } diff --git a/src/pages/feeds/FeedSubpage.tsx b/src/pages/feeds/FeedSubpage.tsx index 724d57b..236d197 100644 --- a/src/pages/feeds/FeedSubpage.tsx +++ b/src/pages/feeds/FeedSubpage.tsx @@ -2,7 +2,7 @@ import * as swarmCid from '@ethersphere/swarm-cid' import { Box } from '@material-ui/core' import { ReactElement, useContext, useEffect, useState } from 'react' import { X } from 'react-feather' -import { useParams, useNavigate } from 'react-router-dom' +import { useNavigate, useParams } from 'react-router-dom' import { DocumentationText } from '../../components/DocumentationText' import ExpandableListItemActions from '../../components/ExpandableListItemActions' import ExpandableListItemKey from '../../components/ExpandableListItemKey' @@ -40,13 +40,13 @@ export function FeedSubpage(): ReactElement { }, [beeApi, uuid, identity]) if (!identity || !status.all) { - navigate(ROUTES.FEEDS, { replace: true }) + navigate(ROUTES.ACCOUNT_FEEDS, { replace: true }) return <> } function onClose() { - navigate(ROUTES.FEEDS) + navigate(ROUTES.ACCOUNT_FEEDS) } return ( diff --git a/src/pages/feeds/UpdateFeed.tsx b/src/pages/feeds/UpdateFeed.tsx index fa5ecd1..60546a8 100644 --- a/src/pages/feeds/UpdateFeed.tsx +++ b/src/pages/feeds/UpdateFeed.tsx @@ -2,7 +2,7 @@ import { Box, Grid, Typography } from '@material-ui/core' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useEffect, useState } from 'react' import { Bookmark, X } from 'react-feather' -import { useParams, useNavigate } from 'react-router' +import { useNavigate, useParams } from 'react-router' import ExpandableListItemActions from '../../components/ExpandableListItemActions' import { HistoryHeader } from '../../components/HistoryHeader' import { SwarmButton } from '../../components/SwarmButton' @@ -73,10 +73,10 @@ export default function UpdateFeed(): ReactElement { } try { - await updateFeed(beeApi, identity, hash!, selectedStamp, password as string) // eslint-disable-line + await updateFeed(beeApi, beeDebugApi, identity, hash!, selectedStamp, password as string) // eslint-disable-line persistIdentity(identities, identity) setIdentities([...identities]) - navigate(ROUTES.FEEDS_PAGE.replace(':uuid', identity.uuid)) + navigate(ROUTES.ACCOUNT_FEEDS_VIEW.replace(':uuid', identity.uuid)) } catch (error: unknown) { setLoading(false) diff --git a/src/pages/feeds/index.tsx b/src/pages/feeds/index.tsx index 662fc09..a13bbba 100644 --- a/src/pages/feeds/index.tsx +++ b/src/pages/feeds/index.tsx @@ -29,11 +29,11 @@ export default function Feeds(): ReactElement { const [showDelete, setShowDelete] = useState(false) function createNewFeed() { - return navigate(ROUTES.FEEDS_NEW) + return navigate(ROUTES.ACCOUNT_FEEDS_NEW) } function viewFeed(uuid: string) { - navigate(ROUTES.FEEDS_PAGE.replace(':uuid', uuid)) + navigate(ROUTES.ACCOUNT_FEEDS_VIEW.replace(':uuid', uuid)) } function onDialogClose() { diff --git a/src/pages/files/Share.tsx b/src/pages/files/Share.tsx index 81bb571..ccf2407 100644 --- a/src/pages/files/Share.tsx +++ b/src/pages/files/Share.tsx @@ -99,7 +99,7 @@ export function Share(): ReactElement { } function onUpdateFeed() { - navigate(ROUTES.FEEDS_UPDATE.replace(':hash', reference)) + navigate(ROUTES.ACCOUNT_FEEDS_UPDATE.replace(':hash', reference)) } useEffect(() => { diff --git a/src/pages/files/Upload.tsx b/src/pages/files/Upload.tsx index 2c3937f..94f920f 100644 --- a/src/pages/files/Upload.tsx +++ b/src/pages/files/Upload.tsx @@ -13,6 +13,7 @@ import { Context as FileContext } from '../../providers/File' import { Context as SettingsContext } from '../../providers/Settings' import { Context as StampsContext, EnrichedPostageBatch } from '../../providers/Stamps' import { ROUTES } from '../../routes' +import { waitUntilStampUsable } from '../../utils' import { detectIndexHtml, getAssetNameFromFiles, packageFile } from '../../utils/file' import { persistIdentity, updateFeed } from '../../utils/identity' import { HISTORY_KEYS, putHistory } from '../../utils/local-storage' @@ -31,7 +32,7 @@ export function Upload(): ReactElement { const [showPasswordPrompt, setShowPasswordPrompt] = useState(false) const { refresh } = useContext(StampsContext) - const { beeApi } = useContext(SettingsContext) + const { beeApi, beeDebugApi } = useContext(SettingsContext) const { files, setFiles, uploadOrigin, metadata, previewUri, previewBlob } = useContext(FileContext) const { identities, setIdentities } = useContext(IdentityContext) const { status } = useContext(BeeContext) @@ -66,7 +67,7 @@ export function Upload(): ReactElement { } } - const uploadFiles = (password?: string) => { + const uploadFiles = async (password?: string) => { if (!beeApi || !files.length || !stamp || !metadata) { return } @@ -122,6 +123,10 @@ export function Upload(): ReactElement { setUploading(true) + if (beeDebugApi) { + await waitUntilStampUsable(stamp.batchID, beeDebugApi) + } + beeApi .uploadFiles(stamp.batchID, fls, { indexDocument }) .then(hash => { @@ -130,11 +135,13 @@ export function Upload(): ReactElement { if (uploadOrigin.origin === 'UPLOAD') { navigate(ROUTES.HASH.replace(':hash', hash.reference), { replace: true }) } else { - updateFeed(beeApi, identity as Identity, hash.reference, stamp.batchID, password as string).then(() => { - persistIdentity(identities, identity as Identity) - setIdentities([...identities]) - navigate(ROUTES.FEEDS_PAGE.replace(':uuid', uploadOrigin.uuid as string), { replace: true }) - }) + updateFeed(beeApi, beeDebugApi, identity as Identity, hash.reference, stamp.batchID, password as string).then( + () => { + persistIdentity(identities, identity as Identity) + setIdentities([...identities]) + navigate(ROUTES.ACCOUNT_FEEDS_VIEW.replace(':uuid', uploadOrigin.uuid as string), { replace: true }) + }, + ) } }) .catch(e => { diff --git a/src/pages/stamps/CreatePostageStampPage.tsx b/src/pages/stamps/CreatePostageStampPage.tsx index 762665d..2888824 100644 --- a/src/pages/stamps/CreatePostageStampPage.tsx +++ b/src/pages/stamps/CreatePostageStampPage.tsx @@ -8,7 +8,7 @@ export function CreatePostageStampPage(): ReactElement { const navigate = useNavigate() function onFinished() { - navigate(ROUTES.STAMPS) + navigate(ROUTES.ACCOUNT_STAMPS) } return ( diff --git a/src/pages/stamps/PostageStampCreation.tsx b/src/pages/stamps/PostageStampCreation.tsx index 89d2e9e..c25595b 100644 --- a/src/pages/stamps/PostageStampCreation.tsx +++ b/src/pages/stamps/PostageStampCreation.tsx @@ -9,13 +9,7 @@ import { SwarmTextInput } from '../../components/SwarmTextInput' import { Context as BeeContext } from '../../providers/Bee' import { Context as SettingsContext } from '../../providers/Settings' import { Context as StampsContext } from '../../providers/Stamps' -import { - calculateStampPrice, - convertAmountToSeconds, - convertDepthToBytes, - secondsToTimeString, - waitUntilStampUsable, -} from '../../utils' +import { calculateStampPrice, convertAmountToSeconds, convertDepthToBytes, secondsToTimeString } from '../../utils' import { getHumanReadableFileSize } from '../../utils/file' interface FormValues { @@ -88,8 +82,7 @@ export function PostageStampCreation({ onFinished }: Props): ReactElement { const amount = BigInt(values.amount) const depth = Number.parseInt(values.depth) const options = values.label ? { label: values.label } : undefined - const batch = await beeDebugApi.createPostageBatch(amount.toString(), depth, options) - await waitUntilStampUsable(batch, beeDebugApi) + await beeDebugApi.createPostageBatch(amount.toString(), depth, options) actions.resetForm() await refresh() onFinished() @@ -107,7 +100,7 @@ export function PostageStampCreation({ onFinished }: Props): ReactElement { const depth = new BigNumber(values.depth) if (!depth.isInteger()) errors.depth = 'Depth must be an integer' - else if (depth.isLessThan(16)) errors.depth = 'Minimal depth is 16' + else if (depth.isLessThan(17)) errors.depth = 'Minimal depth is 17' else if (depth.isGreaterThan(255)) errors.depth = 'Depth has to be at most 255' } diff --git a/src/pages/stamps/index.tsx b/src/pages/stamps/index.tsx index a5f449a..ef3f91a 100644 --- a/src/pages/stamps/index.tsx +++ b/src/pages/stamps/index.tsx @@ -44,7 +44,7 @@ export default function Stamp(): ReactElement { if (status.all === CheckState.ERROR) return function navigateToNewStamp() { - navigate(ROUTES.STAMPS_NEW) + navigate(ROUTES.ACCOUNT_STAMPS_NEW) } return ( diff --git a/src/providers/Stamps.tsx b/src/providers/Stamps.tsx index f0d3bd2..0117f22 100644 --- a/src/providers/Stamps.tsx +++ b/src/providers/Stamps.tsx @@ -34,7 +34,7 @@ interface Props { children: ReactChild } -function enrichStamp(postageBatch: PostageBatch): EnrichedPostageBatch { +export function enrichStamp(postageBatch: PostageBatch): EnrichedPostageBatch { const { depth, bucketDepth, utilization } = postageBatch const usage = utilization / Math.pow(2, depth - bucketDepth) diff --git a/src/routes.tsx b/src/routes.tsx index 165fed3..1f1e7e8 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -1,7 +1,9 @@ import type { ReactElement } from 'react' import { Route, Routes } from 'react-router-dom' -import Accounting from './pages/accounting' -import Feeds from './pages/feeds' +import { AccountChequebook } from './pages/account/chequebook/AccountChequebook' +import { AccountFeeds } from './pages/account/feeds/AccountFeeds' +import { AccountStamps } from './pages/account/stamps/AccountStamps' +import { AccountWallet } from './pages/account/wallet/AccountWallet' import CreateNewFeed from './pages/feeds/CreateNewFeed' import { FeedSubpage } from './pages/feeds/FeedSubpage' import UpdateFeed from './pages/feeds/UpdateFeed' @@ -16,7 +18,6 @@ import Restart from './pages/restart/Restart' import Wallet from './pages/rpc' import Confirmation from './pages/rpc/Confirmation' import Settings from './pages/settings' -import Stamps from './pages/stamps' import { CreatePostageStampPage } from './pages/stamps/CreatePostageStampPage' import Status from './pages/status' import { BankCardTopUpIndex } from './pages/top-up/BankCardTopUpIndex' @@ -32,15 +33,8 @@ export enum ROUTES { UPLOAD_IN_PROGRESS = '/files/upload/workflow', DOWNLOAD = '/files/download', HASH = '/files/hash/:hash', - ACCOUNTING = '/accounting', SETTINGS = '/settings', - STAMPS = '/stamps', - STAMPS_NEW = '/stamps/new', STATUS = '/status', - FEEDS = '/feeds', - FEEDS_NEW = '/feeds/new', - FEEDS_UPDATE = '/feeds/update/:hash', - FEEDS_PAGE = '/feeds/:uuid', WALLET = '/wallet', CONFIRMATION = '/wallet/confirmation', TOP_UP_CRYPTO = '/top-up/crypto', @@ -49,30 +43,37 @@ export enum ROUTES { TOP_UP_BANK_CARD_SWAP = '/top-up/bank-card/swap', TOP_UP_GIFT_CODE = '/top-up/gift-code', TOP_UP_GIFT_CODE_FUND = '/top-up/gift-code/fund/:privateKeyString', - GIFT_CODES = '/gift-codes', RESTART = '/restart', RESTART_LIGHT = '/light-mode-restart', + ACCOUNT_WALLET = '/account/wallet', + ACCOUNT_CHEQUEBOOK = '/account/chequebook', + ACCOUNT_STAMPS = '/account/stamps', + ACCOUNT_STAMPS_NEW = '/account/stamps/new', + ACCOUNT_FEEDS = '/account/feeds', + ACCOUNT_FEEDS_NEW = '/account/feeds/new', + ACCOUNT_FEEDS_UPDATE = '/account/feeds/update/:hash', + ACCOUNT_FEEDS_VIEW = '/account/feeds/:uuid', + ACCOUNT_INVITATIONS = '/account/invitations', } +export const ACCOUNT_TABS = [ + ROUTES.ACCOUNT_WALLET, + ROUTES.ACCOUNT_CHEQUEBOOK, + ROUTES.ACCOUNT_STAMPS, + ROUTES.ACCOUNT_FEEDS, +] + const BaseRouter = (): ReactElement => ( } /> } /> } /> } /> - } /> } /> - } /> - } /> } /> - } /> - } /> - } /> - } /> } /> } /> } /> - } /> } /> } /> } /> @@ -81,6 +82,15 @@ const BaseRouter = (): ReactElement => ( } /> } /> } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> ) diff --git a/src/theme.tsx b/src/theme.tsx index 1414050..6c5cc68 100644 --- a/src/theme.tsx +++ b/src/theme.tsx @@ -1,5 +1,5 @@ -import { createTheme, Theme } from '@material-ui/core/styles' import { orange } from '@material-ui/core/colors' +import { createTheme, Theme } from '@material-ui/core/styles' declare module '@material-ui/core/styles/createPalette' { interface TypeBackground { @@ -186,23 +186,29 @@ export const theme = createTheme({ }, }, typography: { - fontFamily: ['Work Sans', 'Montserrat', 'Nunito', 'Roboto', '"Helvetica Neue"', 'Arial', 'sans-serif'].join(','), + fontFamily: ['iAWriterQuattroV', 'Roboto', '"Helvetica Neue"', 'Arial', 'sans-serif'].join(','), h1: { - fontSize: '1.3rem', - fontWeight: 500, + fontSize: '1.1rem', + fontWeight: 600, }, h2: { - fontSize: '1rem', - fontWeight: 500, + fontSize: '0.9rem', + fontWeight: 600, }, h3: { fontSize: '0.8rem', fontWeight: 500, }, + body1: { + fontSize: '0.85rem', + }, body2: { - fontFamily: '"IBM Plex Mono", monospace', + fontFamily: '"iAWriterMonoV", monospace', fontWeight: 500, - fontSize: '1rem', + fontSize: '0.85rem', + }, + button: { + textTransform: 'none', }, }, }) diff --git a/src/utils/identity.ts b/src/utils/identity.ts index 442a9b5..091f706 100644 --- a/src/utils/identity.ts +++ b/src/utils/identity.ts @@ -1,6 +1,6 @@ -import { Bee, Reference } from '@ethersphere/bee-js' +import { BatchId, Bee, BeeDebug, Reference } from '@ethersphere/bee-js' import Wallet from 'ethereumjs-wallet' -import { uuidV4 } from '.' +import { uuidV4, waitUntilStampUsable } from '.' import { Identity, IdentityType } from '../providers/Feeds' export function generateWallet(): Wallet { @@ -88,6 +88,7 @@ export function getWalletFromPrivateKeyString(privateKey: string): Wallet { export async function updateFeed( beeApi: Bee, + beeDebugApi: BeeDebug | null, identity: Identity, hash: string, stamp: string, @@ -100,6 +101,10 @@ export async function updateFeed( } const writer = beeApi.makeFeedWriter('sequence', '00'.repeat(32), wallet.getPrivateKeyString()) + + if (beeDebugApi) { + await waitUntilStampUsable(stamp as BatchId, beeDebugApi) + } await writer.upload(stamp, hash as Reference) }