Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e3c9b11258 | |||
| e7179eaa46 | |||
| 84cf1c6a62 | |||
| f5e874f8d9 | |||
| 183f2779f0 | |||
| 92e56c0121 | |||
| 550e0ce856 | |||
| 3b0215ccee | |||
| 38a8621032 | |||
| caa0bc4e1e | |||
| abcb0cbf5e | |||
| cdbcfbe3bf | |||
| b8ee730561 | |||
| 26a067c14d | |||
| 69fe8e5cce | |||
| 4fbf1cd876 | |||
| c693412258 | |||
| 72825a2ad3 | |||
| 89a19815fc | |||
| 394f0d30bf |
@@ -22,5 +22,11 @@ pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
|||||||
vec![ValidatorDetails::new(
|
vec![ValidatorDetails::new(
|
||||||
"https://rpc.nyx.nodes.guru/",
|
"https://rpc.nyx.nodes.guru/",
|
||||||
Some("https://api.nyx.nodes.guru/"),
|
Some("https://api.nyx.nodes.guru/"),
|
||||||
|
), ValidatorDetails::new(
|
||||||
|
"https://test2.nyx.nodes.guru/",
|
||||||
|
Some("https://test1.nyx.nodes.guru/"),
|
||||||
|
), ValidatorDetails::new(
|
||||||
|
"https://test2.nyx.nodes.guru/",
|
||||||
|
Some("https://test1.nyx.nodes.guru/"),
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
invoke: (operation) => {
|
invoke: (operation, ...args) => {
|
||||||
|
switch(operation) {
|
||||||
|
case 'get_validator_nymd_urls': {
|
||||||
|
const { network } = args;
|
||||||
|
return new Promise(resolve => {
|
||||||
|
resolve({
|
||||||
|
urls: ['foo', 'bar'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
console.error(`Tauri cannot be used in Storybook. The operation requested was "${operation}". You can add mock responses to "nym_wallet/.storybook/mocks/tauri.js" if you need. The default response is "void".`);
|
console.error(`Tauri cannot be used in Storybook. The operation requested was "${operation}". You can add mock responses to "nym_wallet/.storybook/mocks/tauri.js" if you need. The default response is "void".`);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
reject(new Error(`Tauri operation ${operation} not available in storybook.`));
|
reject(new Error(`Tauri operation ${operation} not available in storybook.`));
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { Logout } from '@mui/icons-material';
|
|||||||
import { ClientContext } from '../context/main';
|
import { ClientContext } from '../context/main';
|
||||||
import { NetworkSelector } from './NetworkSelector';
|
import { NetworkSelector } from './NetworkSelector';
|
||||||
import { Node as NodeIcon } from '../svg-icons/node';
|
import { Node as NodeIcon } from '../svg-icons/node';
|
||||||
|
import { Delegate as DelegateIcon } from '../svg-icons';
|
||||||
|
|
||||||
|
|
||||||
export const AppBar = () => {
|
export const AppBar = () => {
|
||||||
const { showSettings, logOut, handleShowSettings } = useContext(ClientContext);
|
const { showSettings, showValidatorSettings, logOut, handleShowSettings, handleShowValidatorSettings } = useContext(ClientContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MuiAppBar position="sticky" sx={{ boxShadow: 'none', bgcolor: 'transparent' }}>
|
<MuiAppBar position="sticky" sx={{ boxShadow: 'none', bgcolor: 'transparent' }}>
|
||||||
@@ -16,6 +18,15 @@ export const AppBar = () => {
|
|||||||
<NetworkSelector />
|
<NetworkSelector />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item container justifyContent="flex-end" md={12} lg={5} spacing={2}>
|
<Grid item container justifyContent="flex-end" md={12} lg={5} spacing={2}>
|
||||||
|
<Grid item>
|
||||||
|
<IconButton
|
||||||
|
onClick={handleShowValidatorSettings}
|
||||||
|
sx={{ color: showValidatorSettings ? 'primary.main' : 'nym.background.dark' }}
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<DelegateIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={handleShowSettings}
|
onClick={handleShowSettings}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import React, { useMemo, createContext, useEffect, useState } from 'react';
|
|||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from 'notistack';
|
||||||
import { TLoginType } from 'src/pages/sign-in/types';
|
import { TLoginType } from 'src/pages/sign-in/types';
|
||||||
import { Account, Network, TCurrency, TMixnodeBondDetails } from '../types';
|
import { Account, Network, TCurrency, TMixnodeBondDetails, ValidatorUrls } from '../types';
|
||||||
import { TUseuserBalance, useGetBalance } from '../hooks/useGetBalance';
|
import { TUseuserBalance, useGetBalance } from '../hooks/useGetBalance';
|
||||||
import { config } from '../../config';
|
import { config } from '../../config';
|
||||||
import { getMixnodeBondDetails, selectNetwork, signInWithMnemonic, signInWithPassword, signOut } from '../requests';
|
import { getMixnodeBondDetails, selectNetwork, signInWithMnemonic, signInWithPassword, signOut, getValidatorUrls, selectValidatorNymdUrl } from '../requests';
|
||||||
import { currencyMap } from '../utils';
|
import { currencyMap } from '../utils';
|
||||||
import { Console } from '../utils/console';
|
import { Console } from '../utils/console';
|
||||||
|
|
||||||
@@ -29,6 +29,8 @@ type TClientContext = {
|
|||||||
userBalance: TUseuserBalance;
|
userBalance: TUseuserBalance;
|
||||||
showAdmin: boolean;
|
showAdmin: boolean;
|
||||||
showSettings: boolean;
|
showSettings: boolean;
|
||||||
|
showValidatorSettings: boolean;
|
||||||
|
validatorsUrl?: ValidatorUrls;
|
||||||
network?: Network;
|
network?: Network;
|
||||||
currency?: TCurrency;
|
currency?: TCurrency;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
@@ -37,7 +39,10 @@ type TClientContext = {
|
|||||||
setError: (value?: string) => void;
|
setError: (value?: string) => void;
|
||||||
switchNetwork: (network: Network) => void;
|
switchNetwork: (network: Network) => void;
|
||||||
getBondDetails: () => Promise<void>;
|
getBondDetails: () => Promise<void>;
|
||||||
|
fetchValidatorsUrl: (network: Network) => Promise<void>;
|
||||||
|
selectValidatorNymd: (validatorNymd: string, network: Network) => Promise<void>;
|
||||||
handleShowSettings: () => void;
|
handleShowSettings: () => void;
|
||||||
|
handleShowValidatorSettings: () => void;
|
||||||
handleShowAdmin: () => void;
|
handleShowAdmin: () => void;
|
||||||
logIn: (opts: { type: 'mnemonic' | 'password'; value: string }) => void;
|
logIn: (opts: { type: 'mnemonic' | 'password'; value: string }) => void;
|
||||||
signInWithPassword: (password: string) => void;
|
signInWithPassword: (password: string) => void;
|
||||||
@@ -49,10 +54,12 @@ export const ClientContext = createContext({} as TClientContext);
|
|||||||
export const ClientContextProvider = ({ children }: { children: React.ReactNode }) => {
|
export const ClientContextProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
const [clientDetails, setClientDetails] = useState<Account>();
|
const [clientDetails, setClientDetails] = useState<Account>();
|
||||||
const [mixnodeDetails, setMixnodeDetails] = useState<TMixnodeBondDetails | null>();
|
const [mixnodeDetails, setMixnodeDetails] = useState<TMixnodeBondDetails | null>();
|
||||||
|
const [validatorsUrl, setValidatorsUrl] = useState<ValidatorUrls>();
|
||||||
const [network, setNetwork] = useState<Network | undefined>();
|
const [network, setNetwork] = useState<Network | undefined>();
|
||||||
const [currency, setCurrency] = useState<TCurrency>();
|
const [currency, setCurrency] = useState<TCurrency>();
|
||||||
const [showAdmin, setShowAdmin] = useState(false);
|
const [showAdmin, setShowAdmin] = useState(false);
|
||||||
const [showSettings, setShowSettings] = useState(false);
|
const [showSettings, setShowSettings] = useState(false);
|
||||||
|
const [showValidatorSettings, setShowValidatorSettings] = useState(false);
|
||||||
const [mode] = useState<'light' | 'dark'>('light');
|
const [mode] = useState<'light' | 'dark'>('light');
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string>();
|
const [error, setError] = useState<string>();
|
||||||
@@ -83,17 +90,49 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchValidatorsUrl = async (network: Network) => {
|
||||||
|
try {
|
||||||
|
if (network) {
|
||||||
|
const urls = await getValidatorUrls(network);
|
||||||
|
setValidatorsUrl(urls);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Console.error(e as string);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectValidatorNymd = async (validatorNymd: string, network: Network) => {
|
||||||
|
try {
|
||||||
|
if (network) {
|
||||||
|
const response = await selectValidatorNymdUrl(validatorNymd, network);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Console.error(e as string);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const refreshAccount = async () => {
|
const refreshAccount = async () => {
|
||||||
if (network) {
|
if (network) {
|
||||||
await loadAccount(network);
|
await loadAccount(network);
|
||||||
await getBondDetails();
|
await getBondDetails();
|
||||||
await userBalance.fetchBalance();
|
await userBalance.fetchBalance();
|
||||||
|
await fetchValidatorsUrl(network);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
refreshAccount();
|
refreshAccount();
|
||||||
}, [network]);
|
}, [network]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const refreshValidators = async () => {
|
||||||
|
if (!validatorsUrl && network) {
|
||||||
|
await fetchValidatorsUrl(network);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
refreshValidators();
|
||||||
|
}, [showValidatorSettings]);
|
||||||
|
|
||||||
const logIn = async ({ type, value }: { type: TLoginType; value: string }) => {
|
const logIn = async ({ type, value }: { type: TLoginType; value: string }) => {
|
||||||
if (value.length === 0) {
|
if (value.length === 0) {
|
||||||
setError(`A ${type} must be provided`);
|
setError(`A ${type} must be provided`);
|
||||||
@@ -127,7 +166,14 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleShowAdmin = () => setShowAdmin((show) => !show);
|
const handleShowAdmin = () => setShowAdmin((show) => !show);
|
||||||
const handleShowSettings = () => setShowSettings((show) => !show);
|
const handleShowSettings = () => {
|
||||||
|
setShowSettings((show) => !show)
|
||||||
|
setShowValidatorSettings(false);
|
||||||
|
};
|
||||||
|
const handleShowValidatorSettings = () => {
|
||||||
|
setShowValidatorSettings((show) => !show)
|
||||||
|
setShowSettings(false);
|
||||||
|
};
|
||||||
const switchNetwork = (_network: Network) => setNetwork(_network);
|
const switchNetwork = (_network: Network) => setNetwork(_network);
|
||||||
|
|
||||||
const memoizedValue = useMemo(
|
const memoizedValue = useMemo(
|
||||||
@@ -140,6 +186,8 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode
|
|||||||
userBalance,
|
userBalance,
|
||||||
showAdmin,
|
showAdmin,
|
||||||
showSettings,
|
showSettings,
|
||||||
|
showValidatorSettings,
|
||||||
|
validatorsUrl,
|
||||||
network,
|
network,
|
||||||
currency,
|
currency,
|
||||||
setIsLoading,
|
setIsLoading,
|
||||||
@@ -147,12 +195,15 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode
|
|||||||
signInWithPassword,
|
signInWithPassword,
|
||||||
switchNetwork,
|
switchNetwork,
|
||||||
getBondDetails,
|
getBondDetails,
|
||||||
|
fetchValidatorsUrl,
|
||||||
|
selectValidatorNymd,
|
||||||
handleShowSettings,
|
handleShowSettings,
|
||||||
|
handleShowValidatorSettings,
|
||||||
handleShowAdmin,
|
handleShowAdmin,
|
||||||
logIn,
|
logIn,
|
||||||
logOut,
|
logOut,
|
||||||
}),
|
}),
|
||||||
[mode, isLoading, error, clientDetails, mixnodeDetails, userBalance, showAdmin, showSettings, network, currency],
|
[mode, isLoading, error, clientDetails, mixnodeDetails, userBalance, showAdmin, showSettings, showValidatorSettings, validatorsUrl, selectValidatorNymd, network, currency],
|
||||||
);
|
);
|
||||||
|
|
||||||
return <ClientContext.Provider value={memoizedValue}>{children}</ClientContext.Provider>;
|
return <ClientContext.Provider value={memoizedValue}>{children}</ClientContext.Provider>;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { SnackbarProvider } from 'notistack';
|
|||||||
import { AppRoutes, SignInRoutes } from './routes';
|
import { AppRoutes, SignInRoutes } from './routes';
|
||||||
import { ClientContext, ClientContextProvider } from './context/main';
|
import { ClientContext, ClientContextProvider } from './context/main';
|
||||||
import { ApplicationLayout } from './layouts';
|
import { ApplicationLayout } from './layouts';
|
||||||
import { Admin, Settings } from './pages';
|
import { Admin, Settings, ValidatorSettingsModal } from './pages';
|
||||||
import { ErrorFallback } from './components';
|
import { ErrorFallback } from './components';
|
||||||
import { NymWalletTheme, WelcomeTheme } from './theme';
|
import { NymWalletTheme, WelcomeTheme } from './theme';
|
||||||
import { maximizeWindow } from './utils';
|
import { maximizeWindow } from './utils';
|
||||||
@@ -29,6 +29,7 @@ const App = () => {
|
|||||||
<NymWalletTheme>
|
<NymWalletTheme>
|
||||||
<ApplicationLayout>
|
<ApplicationLayout>
|
||||||
<Settings />
|
<Settings />
|
||||||
|
<ValidatorSettingsModal />
|
||||||
<Admin />
|
<Admin />
|
||||||
<AppRoutes />
|
<AppRoutes />
|
||||||
</ApplicationLayout>
|
</ApplicationLayout>
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ export * from './sign-in';
|
|||||||
export * from './settings';
|
export * from './settings';
|
||||||
export * from './unbond';
|
export * from './unbond';
|
||||||
export * from './undelegate';
|
export * from './undelegate';
|
||||||
|
export * from './validators';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { ValidatorSettingsModal } from './validatorModal';
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ComponentMeta } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Button, Paper } from '@mui/material';
|
||||||
|
import { ValidatorSettingsModal } from './validatorModal';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Modals/Validator Setting Modal',
|
||||||
|
component: ValidatorSettingsModal,
|
||||||
|
} as ComponentMeta<typeof ValidatorSettingsModal>;
|
||||||
|
|
||||||
|
export const Default = () => {
|
||||||
|
const [open, setOpen] = React.useState<boolean>(true);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Paper elevation={0} sx={{ px: 4, pt: 2, pb: 4 }}>
|
||||||
|
<h2>Lorem ipsum</h2>
|
||||||
|
<Button variant="contained" onClick={() => setOpen(true)}>
|
||||||
|
Show modal
|
||||||
|
</Button>
|
||||||
|
<p>
|
||||||
|
Veniam dolor laborum labore sit reprehenderit enim mollit magna nulla adipisicing fugiat. Est ex irure quis
|
||||||
|
sunt velit elit do minim mollit non duis reprehenderit. Eiusmod dolore adipisicing ex nostrud consectetur
|
||||||
|
culpa exercitation do. Ad elit esse ipsum aliqua labore irure laborum qui culpa.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Occaecat commodo excepteur anim ut officia dolor laboris dolore id occaecat enim qui eiusmod occaecat aliquip
|
||||||
|
ad tempor. Labore amet laborum magna amet consequat dolor cupidatat in consequat sunt aliquip magna laboris
|
||||||
|
tempor culpa est magna. Sit tempor cillum culpa sint ipsum nostrud ullamco voluptate exercitation dolore magna
|
||||||
|
elit ut mollit.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Labore voluptate elit amet ipsum qui officia duis in et occaecat culpa ex do non labore mollit. Cillum
|
||||||
|
cupidatat duis ea dolore laboris laboris sunt duis anim consectetur cupidatat nulla ad minim sunt ea. Aliqua
|
||||||
|
amet commodo est irure sint magna sunt. Pariatur dolore commodo labore quis incididunt proident duis voluptate
|
||||||
|
exercitation in duis. Occaecat aliqua laboris reprehenderit nostrud est aute pariatur fugiat anim. Dolore sunt
|
||||||
|
cillum ea aliquip consectetur laborum ipsum qui veniam Lorem consectetur adipisicing velit magna aute. Amet
|
||||||
|
tempor quis excepteur minim culpa velit Lorem enim ad.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Mollit laborum exercitation excepteur laboris adipisicing ipsum veniam cillum mollit voluptate do. Amet et
|
||||||
|
anim Lorem mollit minim duis cupidatat non. Consectetur sit deserunt nisi nisi non excepteur dolor eiusmod
|
||||||
|
aute aute irure anim dolore ipsum et veniam.
|
||||||
|
</p>
|
||||||
|
</Paper>
|
||||||
|
<ValidatorSettingsModal/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NoSubheader = () => {
|
||||||
|
const [open, setOpen] = React.useState<boolean>(true);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Paper elevation={0} sx={{ px: 4, pt: 2, pb: 4 }}>
|
||||||
|
<h2>Lorem ipsum</h2>
|
||||||
|
<Button variant="contained" onClick={() => setOpen(true)}>
|
||||||
|
Show modal
|
||||||
|
</Button>
|
||||||
|
<p>
|
||||||
|
Veniam dolor laborum labore sit reprehenderit enim mollit magna nulla adipisicing fugiat. Est ex irure quis
|
||||||
|
sunt velit elit do minim mollit non duis reprehenderit. Eiusmod dolore adipisicing ex nostrud consectetur
|
||||||
|
culpa exercitation do. Ad elit esse ipsum aliqua labore irure laborum qui culpa.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Occaecat commodo excepteur anim ut officia dolor laboris dolore id occaecat enim qui eiusmod occaecat aliquip
|
||||||
|
ad tempor. Labore amet laborum magna amet consequat dolor cupidatat in consequat sunt aliquip magna laboris
|
||||||
|
tempor culpa est magna. Sit tempor cillum culpa sint ipsum nostrud ullamco voluptate exercitation dolore magna
|
||||||
|
elit ut mollit.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Labore voluptate elit amet ipsum qui officia duis in et occaecat culpa ex do non labore mollit. Cillum
|
||||||
|
cupidatat duis ea dolore laboris laboris sunt duis anim consectetur cupidatat nulla ad minim sunt ea. Aliqua
|
||||||
|
amet commodo est irure sint magna sunt. Pariatur dolore commodo labore quis incididunt proident duis voluptate
|
||||||
|
exercitation in duis. Occaecat aliqua laboris reprehenderit nostrud est aute pariatur fugiat anim. Dolore sunt
|
||||||
|
cillum ea aliquip consectetur laborum ipsum qui veniam Lorem consectetur adipisicing velit magna aute. Amet
|
||||||
|
tempor quis excepteur minim culpa velit Lorem enim ad.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Mollit laborum exercitation excepteur laboris adipisicing ipsum veniam cillum mollit voluptate do. Amet et
|
||||||
|
anim Lorem mollit minim duis cupidatat non. Consectetur sit deserunt nisi nisi non excepteur dolor eiusmod
|
||||||
|
aute aute irure anim dolore ipsum et veniam.
|
||||||
|
</p>
|
||||||
|
</Paper>
|
||||||
|
<ValidatorSettingsModal />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
|
import { Button, Box, Dialog, CircularProgress, Typography } from '@mui/material';
|
||||||
|
import { NymCard } from '../../components';
|
||||||
|
import { ClientContext } from '../../context/main';
|
||||||
|
import { ValidatorSelector } from './validatorSelector';
|
||||||
|
import { Delegate as DelegateIcon } from '../../svg-icons';
|
||||||
|
import { Console } from '../../utils/console';
|
||||||
|
|
||||||
|
export const ValidatorSettingsModal = () => {
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
const [validatorSelectedSuccessfully, setValidatorSelectedSuccessfully] = useState(false);
|
||||||
|
const [validator, setValidator] = useState('');
|
||||||
|
|
||||||
|
const { showValidatorSettings, getBondDetails, handleShowValidatorSettings, network, selectValidatorNymd } = useContext(ClientContext);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (showValidatorSettings) {
|
||||||
|
getBondDetails();
|
||||||
|
} else {
|
||||||
|
setValidatorSelectedSuccessfully(false);
|
||||||
|
};
|
||||||
|
}, [showValidatorSettings]);
|
||||||
|
|
||||||
|
const onDataChanged = (selectedValidator: string) => {
|
||||||
|
if (selectedValidator) {
|
||||||
|
setValidator(selectedValidator);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
setIsSubmitting(true);
|
||||||
|
try {
|
||||||
|
if (network) {
|
||||||
|
selectValidatorNymd(validator, network).then(res => console.log('res', res));
|
||||||
|
setValidatorSelectedSuccessfully(true);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Console.error(e as string);
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return showValidatorSettings ? (
|
||||||
|
<Dialog open onClose={handleShowValidatorSettings} maxWidth="md" fullWidth>
|
||||||
|
<NymCard
|
||||||
|
title={
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<DelegateIcon sx={{ mr: 1 }} />
|
||||||
|
Settings
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
noPadding
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 3,
|
||||||
|
borderTop: '1px solid',
|
||||||
|
borderColor: 'grey.300',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
}}>
|
||||||
|
Wallet Settings
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
p: 2,
|
||||||
|
pl: 3,
|
||||||
|
borderTop: '1px solid',
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: 'grey.300',
|
||||||
|
bgcolor: 'grey.200',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
}}>
|
||||||
|
Validators
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'start',
|
||||||
|
minHeight: 300,
|
||||||
|
padding: 3,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ValidatorSelector
|
||||||
|
type="Validator API Url"
|
||||||
|
onChangeValidatorSelection={(selectedValidator) => onDataChanged(selectedValidator)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{validatorSelectedSuccessfully && (
|
||||||
|
<Typography sx={{ pt: 2, fontSize: 12, color: (theme) => theme.palette.success.light }}>
|
||||||
|
Successfully selected the validator: {validator}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
padding: 3,
|
||||||
|
bgcolor: 'grey.200',
|
||||||
|
borderTop: '1px solid',
|
||||||
|
borderColor: 'grey.300',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
size="large"
|
||||||
|
variant="contained"
|
||||||
|
data-testid="validatorsSettings-button"
|
||||||
|
color="primary"
|
||||||
|
disableElevation
|
||||||
|
onClick={() => handleSubmit()}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
endIcon={isSubmitting && <CircularProgress size={20} />}
|
||||||
|
>
|
||||||
|
Save Changes
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</NymCard>
|
||||||
|
</Dialog>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
|
import { FormControl, InputLabel, ListItemText, MenuItem, Select, SelectChangeEvent, Typography, useMediaQuery } from '@mui/material';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import { ClientContext } from '../../context/main';
|
||||||
|
|
||||||
|
type TValidatorUrl = string;
|
||||||
|
|
||||||
|
export const ValidatorSelector: React.FC<{ onChangeValidatorSelection: (validator: TValidatorUrl) => void, type: string }> = ({
|
||||||
|
onChangeValidatorSelection,
|
||||||
|
}) => {
|
||||||
|
const [selectedValidator, setSelectedValidator] = useState<TValidatorUrl>('');
|
||||||
|
|
||||||
|
const {
|
||||||
|
validatorsUrl
|
||||||
|
} = useContext(ClientContext);
|
||||||
|
const theme = useTheme();
|
||||||
|
const matches = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onChangeValidatorSelection(selectedValidator);
|
||||||
|
}, [selectedValidator]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<InputLabel id="validatorSelect_label">Validator API Url</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="validatorSelect_label"
|
||||||
|
id="validatorSelect"
|
||||||
|
sx={{
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
value={selectedValidator || ''}
|
||||||
|
label="Choose a Validator"
|
||||||
|
onChange={(e: SelectChangeEvent) => {
|
||||||
|
setSelectedValidator(e.target.value as TValidatorUrl);
|
||||||
|
}}
|
||||||
|
renderValue={(value) => <Typography sx={{ textTransform: 'capitalize' }}>{value}</Typography>}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
validatorsUrl && validatorsUrl.urls.map((validator) => (
|
||||||
|
<MenuItem value={validator} key={validator}>
|
||||||
|
<ListItemText>{validator}</ListItemText>
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)
|
||||||
|
};
|
||||||
@@ -5,3 +5,4 @@ export * from './contract';
|
|||||||
export * from './vesting';
|
export * from './vesting';
|
||||||
export * from './network';
|
export * from './network';
|
||||||
export * from './queries';
|
export * from './queries';
|
||||||
|
export * from './validators';
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { invoke } from '@tauri-apps/api';
|
||||||
|
import { Network } from '../types';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ValidatorUrls
|
||||||
|
} from '../types';
|
||||||
|
|
||||||
|
export const getValidatorUrls = async (network: Network): Promise<ValidatorUrls> => {
|
||||||
|
const res: ValidatorUrls = await invoke('get_validator_nymd_urls', { network });
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const selectValidatorNymdUrl = async (validator: string, network: Network): Promise<void> => {
|
||||||
|
const res: void = await invoke('select_validator_nymd_url', { url: validator, network });
|
||||||
|
return res;
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { ComponentMeta } from '@storybook/react';
|
||||||
|
import { Playground } from '@nymproject/react';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Playground',
|
||||||
|
component: Playground,
|
||||||
|
} as ComponentMeta<typeof Playground>;
|
||||||
|
|
||||||
|
export const AllControls = () => <Playground />;
|
||||||
@@ -23,3 +23,4 @@ export * from './vestingperiod';
|
|||||||
export * from './pendingundelegate';
|
export * from './pendingundelegate';
|
||||||
export * from './delegationevent';
|
export * from './delegationevent';
|
||||||
export * from './epoch';
|
export * from './epoch';
|
||||||
|
export * from './validatorurls';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { invoke } from '@tauri-apps/api';
|
|||||||
import { appWindow } from '@tauri-apps/api/window';
|
import { appWindow } from '@tauri-apps/api/window';
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
import { valid } from 'semver';
|
import { valid } from 'semver';
|
||||||
import { userBalance, majorToMinor, getLockedCoins, getSpendableCoins } from '../requests';
|
import { userBalance, majorToMinor, getLockedCoins, getSpendableCoins, getValidatorUrls } from '../requests';
|
||||||
import { Coin, Network, TCurrency } from '../types';
|
import { Coin, Network, TCurrency } from '../types';
|
||||||
import { Console } from './console';
|
import { Console } from './console';
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export * from './components';
|
export * from './components';
|
||||||
export * from './hooks';
|
export * from './hooks';
|
||||||
export { Playground } from './playground';
|
export { Playground } from './playground/Playground';
|
||||||
|
|||||||
Reference in New Issue
Block a user