diff --git a/nym-wallet/src/components/Bonding/BondedMixnode.tsx b/nym-wallet/src/components/Bonding/BondedMixnode.tsx index 2e9a233d85..ff7a67303d 100644 --- a/nym-wallet/src/components/Bonding/BondedMixnode.tsx +++ b/nym-wallet/src/components/Bonding/BondedMixnode.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { useNavigate } from 'react-router-dom'; import { Box, Button, Stack, Typography } from '@mui/material'; import { Link } from '@nymproject/react/link/Link'; import { TBondedMixnode, urls } from 'src/context'; @@ -55,8 +56,11 @@ export const BondedMixnode = ({ network?: Network; onActionSelect: (action: TBondedMixnodeActions) => void; }) => { + const navigate = useNavigate(); + const { name, stake, bond, stakeSaturation, profitMargin, operatorRewards, delegators, status, identityKey } = mixnode; + const cells: Cell[] = [ { cell: `${stake.amount} ${stake.denom}`, @@ -117,7 +121,7 @@ export const BondedMixnode = ({ + + + { + await setOpenConfirmationModal(false); + }} + buttonFullWidth + sx={{ + width: '450px', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + }} + headerStyles={{ + width: '100%', + mb: 1, + textAlign: 'center', + color: theme.palette.nym.nymWallet.text.blue, + fontSize: 16, + textTransform: 'capitalize', + }} + subHeaderStyles={{ + width: '100%', + mb: 1, + textAlign: 'center', + color: 'main', + fontSize: 14, + textTransform: 'capitalize', + }} + /> + + ); +}; diff --git a/nym-wallet/src/pages/bonding/node-settings/general-settings/ParametersSettings.tsx b/nym-wallet/src/pages/bonding/node-settings/general-settings/ParametersSettings.tsx new file mode 100644 index 0000000000..ccc2d3fa88 --- /dev/null +++ b/nym-wallet/src/pages/bonding/node-settings/general-settings/ParametersSettings.tsx @@ -0,0 +1,174 @@ +import { useState, useEffect } from 'react'; +import { Button, Divider, Typography, TextField, InputAdornment, Grid, Alert } from '@mui/material'; +import { useTheme } from '@mui/material/styles'; +import { TBondedMixnode, TBondedGateway } from '../../../../context/bonding'; +import { SimpleModal } from '../../../../components/Modals/SimpleModal'; + +export const ParametersSettings = ({ bondedNode }: { bondedNode: TBondedMixnode | TBondedGateway }) => { + const { profitMarginPercent, bond } = bondedNode; + + const [buttonActive, setButtonActive] = useState(false); + const [openConfirmationModal, setOpenConfirmationModal] = useState(false); + const [profitMargin, setProfitMargin] = useState(profitMarginPercent); + const [operatorCost, setOperatorCost] = useState(parseInt(bond.amount)); + + const theme = useTheme(); + + useEffect(() => { + if (profitMargin === profitMarginPercent && operatorCost === parseInt(bond.amount)) { + setButtonActive(false); + } else { + setButtonActive(true); + } + }, [profitMargin, operatorCost]); + + const handleChange = (e: React.ChangeEvent) => { + const { value, id } = e.target; + const numNewValue = parseInt(value) || 0; + switch (id) { + case 'profitMargin': + setProfitMargin(numNewValue); + break; + case 'operatorCost': + setOperatorCost(numNewValue); + break; + } + }; + + return ( + + {buttonActive && ( + theme.palette.nym.nymWallet.text.blue, + '& .MuiAlert-icon': { color: (theme) => theme.palette.nym.nymWallet.text.blue, mr: 1 }, + }} + > + Profit margin can be changed once a month, your changes will be applied in the next interval + + )} + + + + + Profit Margin + + (t.palette.mode === 'light' ? t.palette.nym.text.muted : 'text.primary'), + }} + > + Profit margin can be changed once a month + + + + + handleChange(e)} + fullWidth + InputProps={{ + endAdornment: ( + + % + + ), + }} + /> + + + + + + + + Operator cost + + (t.palette.mode === 'light' ? t.palette.nym.text.muted : 'text.primary'), + }} + > + Lock Wallet after a certain time + + + + + handleChange(e)} + fullWidth + InputProps={{ + endAdornment: ( + + {bond.denom.toUpperCase()} + + ), + }} + /> + + + + + + + + + { + await setOpenConfirmationModal(false); + }} + buttonFullWidth + sx={{ + width: '320px', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + }} + headerStyles={{ + width: '100%', + mb: 1, + textAlign: 'center', + color: theme.palette.nym.nymWallet.text.blue, + fontSize: 16, + textTransform: 'capitalize', + }} + subHeaderStyles={{ + m: 0, + }} + /> + + ); +}; diff --git a/nym-wallet/src/pages/bonding/node-settings/general-settings/index.tsx b/nym-wallet/src/pages/bonding/node-settings/general-settings/index.tsx new file mode 100644 index 0000000000..caf8c121f7 --- /dev/null +++ b/nym-wallet/src/pages/bonding/node-settings/general-settings/index.tsx @@ -0,0 +1,41 @@ +import React, { useContext, useEffect, useState } from 'react'; +import { Box, Button, Divider, Grid } from '@mui/material'; +import { TBondedMixnode, TBondedGateway } from '../../../../context/bonding'; +import { InfoSettings } from './InfoSettings'; +import { ParametersSettings } from './ParametersSettings'; + +const nodeGeneralNav = ['Info', 'Parameters']; + +export const NodeGeneralSettings = ({ bondedNode }: { bondedNode: TBondedMixnode | TBondedGateway }) => { + const [settingsCard, setSettingsCard] = useState(nodeGeneralNav[0]); + //TODO: Check what happens with a gateway + return ( + + + + {nodeGeneralNav.map((item) => ( + + ))} + + + {settingsCard === nodeGeneralNav[0] && } + {settingsCard === nodeGeneralNav[1] && } + + + ); +}; diff --git a/nym-wallet/src/pages/bonding/node-settings/index.tsx b/nym-wallet/src/pages/bonding/node-settings/index.tsx new file mode 100644 index 0000000000..4701e38e3d --- /dev/null +++ b/nym-wallet/src/pages/bonding/node-settings/index.tsx @@ -0,0 +1,135 @@ +import React, { useContext, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { FeeDetails } from '@nymproject/types'; +import { Box, Typography, Stack, Button, Divider, IconButton } from '@mui/material'; +import { Close } from '@mui/icons-material'; +import { useTheme } from '@mui/material/styles'; +import { ConfirmationDetailProps, ConfirmationDetailsModal } from 'src/components/Bonding/modals/ConfirmationModal'; +import { Node as NodeIcon } from 'src/svg-icons/node'; +import { NymCard } from '../../../components'; +import { PageLayout } from '../../../layouts'; +import { Tabs } from 'src/components/Tabs'; +import { useBondingContext, BondingContextProvider } from '../../../context'; +import { AppContext, urls } from 'src/context/main'; +import { NodeGeneralSettings } from './general-settings'; +import { UnbondModal } from '../../../components/Bonding/modals/UnbondModal'; +import { nodeSettingsNav } from './node-settings.constant'; +import { TestNode } from 'src/pages/test-my-node'; + +export const NodeSettings = () => { + const [confirmationDetails, setConfirmationDetails] = useState(); + const [value, setValue] = React.useState(0); + + const theme = useTheme(); + + const handleChange = (event: React.SyntheticEvent, newValue: number) => { + setValue(newValue); + }; + + const { network } = useContext(AppContext); + + const { bondedNode, unbond } = useBondingContext(); + + const navigate = useNavigate(); + + const handleUnbond = async (fee?: FeeDetails) => { + const tx = await unbond(fee); + setConfirmationDetails({ + status: 'success', + title: 'Unbond successful', + txUrl: `${urls(network).blockExplorer}/transaction/${tx?.transaction_hash}`, + }); + }; + + const handleError = (error: string) => { + setConfirmationDetails({ + status: 'error', + title: 'An error occurred', + subtitle: error, + }); + }; + + return ( + + + + + + + Node Settings + + + + + + + + } + Action={ + navigate('/bonding')}> + + + } + > + + {value === 0 && bondedNode && } + {value === 1 && bondedNode && ( + + + + )} + {value === 2 && bondedNode && ( + setValue(0)} onConfirm={handleUnbond} onError={handleError} /> + )} + {confirmationDetails && confirmationDetails.status === 'success' && ( + { + setConfirmationDetails(undefined); + navigate('/bonding'); + }} + /> + )} + + + ); +}; + +export const NodeSettingsPage = () => ( + + + +); diff --git a/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx b/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx new file mode 100644 index 0000000000..d875b7fb54 --- /dev/null +++ b/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx @@ -0,0 +1 @@ +export const nodeSettingsNav = ['General', 'Test Node', 'Unbond']; diff --git a/nym-wallet/src/pages/test-my-node/index.tsx b/nym-wallet/src/pages/test-my-node/index.tsx index 521d0dd7a3..df46701bc1 100644 --- a/nym-wallet/src/pages/test-my-node/index.tsx +++ b/nym-wallet/src/pages/test-my-node/index.tsx @@ -27,7 +27,7 @@ export const TestNode = () => { }; return ( - + {view === 'overview' && } {view === 'start-test' && } {view === 'results' && } diff --git a/nym-wallet/src/routes/app.tsx b/nym-wallet/src/routes/app.tsx index 4be436364b..397f5e8b32 100644 --- a/nym-wallet/src/routes/app.tsx +++ b/nym-wallet/src/routes/app.tsx @@ -1,10 +1,18 @@ -import React from 'react'; import { Route, Routes } from 'react-router-dom'; +import { Send } from 'src/components/Send'; import { ApplicationLayout } from 'src/layouts'; import { Terminal } from 'src/pages/terminal'; -import { Send } from 'src/components/Send'; import { Receive } from '../components/Receive'; -import { Balance, InternalDocs, Unbond, DelegationPage, Admin, BondingPage, TestNode } from '../pages'; +import { + Admin, + Balance, + BondingPage, + DelegationPage, + InternalDocs, + NodeSettingsPage, + TestNode, + Unbond, +} from '../pages'; export const AppRoutes = () => ( @@ -14,6 +22,7 @@ export const AppRoutes = () => ( } /> } /> + } /> } /> } /> } /> diff --git a/nym-wallet/src/theme/mui-theme.d.ts b/nym-wallet/src/theme/mui-theme.d.ts index 4015963ec3..5bf3fb2712 100644 --- a/nym-wallet/src/theme/mui-theme.d.ts +++ b/nym-wallet/src/theme/mui-theme.d.ts @@ -31,6 +31,7 @@ declare module '@mui/material/styles' { highlight: string; success: string; info: string; + red: string; fee: string; background: { light: string; dark: string }; text: { @@ -57,6 +58,7 @@ declare module '@mui/material/styles' { warn: string; contrast: string; grey: string; + blue: string; }; topNav: { background: string; @@ -85,7 +87,7 @@ declare module '@mui/material/styles' { /** * Add anything not palette related to the theme here */ - interface NymTheme {} + interface NymTheme { } /** * This augments the definitions of the MUI Theme with the Nym theme, as well as @@ -93,8 +95,8 @@ declare module '@mui/material/styles' { * * IMPORTANT: only add extensions to the interfaces above, do not modify the lines below */ - interface Theme extends NymTheme {} - interface ThemeOptions extends Partial {} - interface Palette extends NymPaletteAndNymWalletPalette {} - interface PaletteOptions extends NymPaletteAndNymWalletPaletteOptions {} + interface Theme extends NymTheme { } + interface ThemeOptions extends Partial { } + interface Palette extends NymPaletteAndNymWalletPalette { } + interface PaletteOptions extends NymPaletteAndNymWalletPaletteOptions { } } diff --git a/nym-wallet/src/theme/theme.tsx b/nym-wallet/src/theme/theme.tsx index b686c8a833..b2d943d4df 100644 --- a/nym-wallet/src/theme/theme.tsx +++ b/nym-wallet/src/theme/theme.tsx @@ -23,6 +23,7 @@ const nymPalette: NymPalette = { highlight: '#FB6E4E', success: '#21D073', info: '#60D7EF', + red: '#DA465B', fee: '#967FF0', background: { light: '#F4F6F8', dark: '#1D2125' }, text: { @@ -49,6 +50,7 @@ const darkMode: NymPaletteVariant = { warn: '#FFE600', contrast: '#1D2125', grey: '#5B6174', + blue: '#60D7EF', }, topNav: { background: '#111826', @@ -76,6 +78,7 @@ const lightMode: NymPaletteVariant = { warn: '#FFE600', contrast: '#FFFFFF', grey: '#3A4053', + blue: '#514EFB', }, topNav: { background: '#111826', @@ -279,6 +282,16 @@ export const getDesignTokens = (mode: PaletteMode): ThemeOptions => { }, }, }, + MuiToolbar: { + styleOverrides: { + root: { + minWidth: 0, + '@media (min-width: 0px)': { + minHeight: 'fit-content', + }, + }, + }, + }, }, palette, };