diff --git a/nym-wallet/src/components/CopyToClipboard.tsx b/nym-wallet/src/components/CopyToClipboard.tsx index 453a2ce382..8df15668a8 100644 --- a/nym-wallet/src/components/CopyToClipboard.tsx +++ b/nym-wallet/src/components/CopyToClipboard.tsx @@ -36,7 +36,7 @@ export const CopyToClipboard = ({ text = '', iconButton }: { text?: string; icon color: 'text.primary', }} > - {!copied ? : } + {!copied ? : } ); diff --git a/nym-wallet/src/context/bonding.tsx b/nym-wallet/src/context/bonding.tsx index d7a584e533..33f56a3859 100644 --- a/nym-wallet/src/context/bonding.tsx +++ b/nym-wallet/src/context/bonding.tsx @@ -1,4 +1,4 @@ -import { MajorCurrencyAmount, TransactionExecuteResult } from '@nymproject/types'; +import { MajorCurrencyAmount, MixnodeStatus, TransactionExecuteResult } from '@nymproject/types'; import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import type { Network } from 'src/types'; import { TBondGatewayArgs, TBondMixNodeArgs } from 'src/types'; @@ -11,6 +11,26 @@ import { unbondMixNode as unbondMixNodeRequest, } from '../requests'; +/* const bounded: BondedMixnode = { + bond: { denom: 'NYM', amount: '1234' }, + key: 'B2Xx4haarLWMajX8w259oHjtRZsC7nHwagbWrJNiA3QC', + delegators: 123, + ip: '1.2.34.5', + nodeRewards: { denom: 'NYM', amount: '123' }, + operatorRewards: { denom: 'NYM', amount: '12' }, + profitMargin: 10, + stake: { denom: 'NYM', amount: '99' }, + stakeSaturation: 99, + status: 'active', +}; */ + +const bounded: BondedMixnode | BondedGateway = { + bond: { denom: 'NYM', amount: '1234' }, + key: 'B2Xx4haarLWMajX8w259oHjtRZsC7nHwagbWrJNiA3QC', + ip: '1.2.34.5', + location: 'France', +}; + // TODO temporary type for bonded mixnode data export interface BondedMixnode { key: string; @@ -22,6 +42,7 @@ export interface BondedMixnode { nodeRewards: MajorCurrencyAmount; operatorRewards: MajorCurrencyAmount; delegators: number; + status: MixnodeStatus; } // TODO temporary type for bonded gateway data @@ -89,17 +110,6 @@ export const BondingContextProvider = ({ }; const refresh = useCallback(async () => { - const bounded: BondedMixnode = { - bond: { denom: 'NYM', amount: '1234' }, - key: 'B2Xx4haarLWMajX8w259oHjtRZsC7nHwagbWrJNiA3QC', - delegators: 123, - ip: '1.2.34.5', - nodeRewards: { denom: 'NYM', amount: '123' }, - operatorRewards: { denom: 'NYM', amount: '12' }, - profitMargin: 10, - stake: { denom: 'NYM', amount: '99' }, - stakeSaturation: 99, - }; // TODO fetch bondedMixnode and bondedGatway via tauri dedicated requests /* try { bounded = await fetchBondingData(); @@ -192,6 +202,7 @@ export const BondingContextProvider = ({ error, bondMixnode, bondedMixnode, + bondedGateway, bondGateway, unbondMixnode, unbondGateway, diff --git a/nym-wallet/src/context/mocks/bonding.tsx b/nym-wallet/src/context/mocks/bonding.tsx index 0fddce84a7..1a87713c37 100644 --- a/nym-wallet/src/context/mocks/bonding.tsx +++ b/nym-wallet/src/context/mocks/bonding.tsx @@ -16,6 +16,7 @@ const bondedMixnodeMock: BondedMixnode = { nodeRewards: { denom: 'NYM', amount: '1234' }, operatorRewards: { denom: 'NYM', amount: '1234' }, delegators: 5423, + status: 'active', }; const bondedGatewayMock: BondedGateway = { diff --git a/nym-wallet/src/pages/bonding/BondedNodeCard.tsx b/nym-wallet/src/pages/bonding/BondedNodeCard.tsx new file mode 100644 index 0000000000..148172c8a9 --- /dev/null +++ b/nym-wallet/src/pages/bonding/BondedNodeCard.tsx @@ -0,0 +1,86 @@ +import * as React from 'react'; +import { Card, CardContent, CardHeader, Stack, Typography } from '@mui/material'; +import { MixnodeStatus } from '@nymproject/types'; +import { CheckCircleOutline, CircleOutlined, PauseCircleOutlined } from '@mui/icons-material'; +import { CopyToClipboard } from '../../components'; +import { splice } from '../../utils'; + +interface Props { + children?: React.ReactNode; + title: string; + identityKey: string; + status?: MixnodeStatus; + action?: React.ReactNode; +} + +const IdentityKey = ({ identityKey }: { identityKey: string }) => ( + + {splice(6, identityKey)} + + +); + +export const getNodeStatus = ({ status }: { status: MixnodeStatus }) => { + switch (status) { + case 'active': + return ( + + Active + + ); + case 'standby': + return ( + + Standby + + ); + case 'inactive': + return ( + + Inactive + + ); + case 'not_found': + return ( + + Not found + + ); + default: + return null; + } +}; + +const BondedNodeCard = (props: Props) => { + const { title: rawTitle, identityKey, status: rawStatus, action, children } = props; + let title: string | React.ReactNode = ( + + {rawTitle} + + ); + if (rawStatus) { + title = ( + + + {rawTitle} + + {getNodeStatus({ status: rawStatus })} + + ); + } + + return ( + + } + action={action} + disableTypography + sx={{ pb: 0 }} + /> + {children} + + ); +}; + +export default BondedNodeCard; diff --git a/nym-wallet/src/pages/bonding/GatewayCard.tsx b/nym-wallet/src/pages/bonding/GatewayCard.tsx index 08794d4f82..12716866a5 100644 --- a/nym-wallet/src/pages/bonding/GatewayCard.tsx +++ b/nym-wallet/src/pages/bonding/GatewayCard.tsx @@ -1,11 +1,61 @@ -import React from 'react'; -import { Grid } from '@mui/material'; +import React, { useMemo } from 'react'; +import { IconButton } from '@mui/material'; +import { MoreVert } from '@mui/icons-material'; +import { useTheme } from '@mui/material/styles'; import { NymCard } from '../../components'; +import { BondedGateway } from '../../context'; +import { Cell, Header, NodeTable } from './NodeTable'; +import BondedNodeCard from './BondedNodeCard'; +import { bondGateway } from '../../requests'; -export const GatewayCard = () => ( - - - bonded gateway data table - - -); +const headers: Header[] = [ + { + header: 'IP', + id: 'ip-header', + sx: { pl: 0 }, + }, + { + header: 'Bond', + id: 'bond-header', + }, + { + id: 'menu-button', + size: 'small', + sx: { pr: 0 }, + }, +]; + +export const GatewayCard = ({ gateway }: { gateway: BondedGateway }) => { + const { ip, bond } = gateway; + const theme = useTheme(); + const cells: Cell[] = useMemo( + () => [ + { + cell: ip, + id: 'ip-cell', + sx: { pl: 0 }, + }, + { + cell: `${bond.amount} ${bond.denom}`, + id: 'bond-cell', + }, + { + cell: ( + + + + ), + id: 'menu-button-cell', + align: 'center', + size: 'small', + sx: { pr: 0 }, + }, + ], + [gateway, theme], + ); + return ( + + + + ); +}; diff --git a/nym-wallet/src/pages/bonding/MixnodeCard.tsx b/nym-wallet/src/pages/bonding/MixnodeCard.tsx index ba38302f6a..a9875f60eb 100644 --- a/nym-wallet/src/pages/bonding/MixnodeCard.tsx +++ b/nym-wallet/src/pages/bonding/MixnodeCard.tsx @@ -1,10 +1,12 @@ import React, { useMemo } from 'react'; -import { IconButton, Typography } from '@mui/material'; +import { Button, IconButton, Typography } from '@mui/material'; import { MoreVert } from '@mui/icons-material'; +import { useTheme } from '@mui/material/styles'; import { Link } from '@nymproject/react/link/Link'; -import { NymCard } from '../../components'; import { BondedMixnode } from '../../context'; +import { Node as NodeIcon } from '../../svg-icons/node'; import { Cell, Header, NodeTable } from './NodeTable'; +import BondedNodeCard from './BondedNodeCard'; const headers: Header[] = [ { @@ -51,6 +53,7 @@ const headers: Header[] = [ export const MixnodeCard = ({ mixnode }: { mixnode: BondedMixnode }) => { const { stake, bond, stakeSaturation, profitMargin, nodeRewards, operatorRewards, delegators } = mixnode; + const theme = useTheme(); const cells: Cell[] = useMemo( () => [ { @@ -65,6 +68,7 @@ export const MixnodeCard = ({ mixnode }: { mixnode: BondedMixnode }) => { { cell: `${stakeSaturation}%`, id: 'stake-saturation-cell', + color: stakeSaturation > 100 ? theme.palette.nym.nymWallet.selectionChance.underModerate : undefined, }, { cell: `${profitMargin}%`, @@ -94,10 +98,29 @@ export const MixnodeCard = ({ mixnode }: { mixnode: BondedMixnode }) => { sx: { pr: 0 }, }, ], - [mixnode], + [mixnode, theme], ); return ( - + } + > + Node settings + + } + > Check more stats of your node on the{' '} @@ -105,6 +128,6 @@ export const MixnodeCard = ({ mixnode }: { mixnode: BondedMixnode }) => { explorer - + ); }; diff --git a/nym-wallet/src/pages/bonding/NodeTable.tsx b/nym-wallet/src/pages/bonding/NodeTable.tsx index 4dcc45fe29..5af3e560fa 100644 --- a/nym-wallet/src/pages/bonding/NodeTable.tsx +++ b/nym-wallet/src/pages/bonding/NodeTable.tsx @@ -25,7 +25,7 @@ export interface TableCell { export type TableHeader = TableCell & { tooltip?: React.ReactNode }; const CellHeader = ({ children, tooltip, sx, size, align, color }: TableHeader) => ( - + {tooltip ? ( @@ -40,7 +40,7 @@ const CellHeader = ({ children, tooltip, sx, size, align, color }: TableHeader) ); const CellValue = ({ children, align, size, color, sx }: TableCell) => ( - + {children} ); diff --git a/nym-wallet/src/pages/bonding/index.tsx b/nym-wallet/src/pages/bonding/index.tsx index 8a6746a471..32cfa7dbb1 100644 --- a/nym-wallet/src/pages/bonding/index.tsx +++ b/nym-wallet/src/pages/bonding/index.tsx @@ -27,6 +27,7 @@ const Bonding = () => { {bondedMixnode && } + {bondedGateway && } ); diff --git a/nym-wallet/src/theme/mui-theme.d.ts b/nym-wallet/src/theme/mui-theme.d.ts index 83e2c36d79..3ebdaec69c 100644 --- a/nym-wallet/src/theme/mui-theme.d.ts +++ b/nym-wallet/src/theme/mui-theme.d.ts @@ -64,6 +64,17 @@ declare module '@mui/material/styles' { nav: { background: string; }; + mixnodes: { + status: { + active: string; + standby: string; + }; + }; + selectionChance: { + overModerate: string; + moderate: string; + underModerate: string; + }; } /** diff --git a/nym-wallet/src/theme/theme.tsx b/nym-wallet/src/theme/theme.tsx index 6749d3d864..6cc8adb2c9 100644 --- a/nym-wallet/src/theme/theme.tsx +++ b/nym-wallet/src/theme/theme.tsx @@ -56,6 +56,17 @@ const darkMode: NymPaletteVariant = { nav: { background: '#292E34', }, + mixnodes: { + status: { + active: '#20D073', + standby: '#5FD7EF', + }, + }, + selectionChance: { + overModerate: '#20D073', + moderate: '#EBA53D', + underModerate: '#DA465B', + }, }; const lightMode: NymPaletteVariant = { @@ -80,6 +91,17 @@ const lightMode: NymPaletteVariant = { nav: { background: '#FFFFFF', }, + mixnodes: { + status: { + active: '#1CBB67', + standby: '#55C1D7', + }, + }, + selectionChance: { + overModerate: '#20D073', + moderate: '#EBA53D', + underModerate: '#DA465B', + }, }; /**