Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notification toast #581

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { FederationInfo } from '@fedimint/types';
import { useTranslation } from '@fedimint/utils';
import { useGatewayApi } from '../../../hooks';
import { useNotification } from '../../../home/NotificationProvider';

export interface ConnectFedModalProps {
isOpen: boolean;
Expand Down Expand Up @@ -89,6 +90,7 @@ export const ConnectFederation = React.memo(function ConnectFederation({
const [connectInfo, setConnectInfo] = useState<string>('');
const [loading, setLoading] = useState(false);
const theme = useTheme();
const { showError, showInfo } = useNotification();

const handleInputString = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
event.preventDefault();
Expand All @@ -97,15 +99,23 @@ export const ConnectFederation = React.memo(function ConnectFederation({

const handleConnectFederation = () => {
setLoading(true);
setErrorMsg('');
showInfo(t('connect-federation.progress-modal-text'));

api
.connectFederation(connectInfo.trim())
.then((federation) => {
renderConnectedFedCallback(federation);
setConnectInfo('');
onClose();
})
.catch(({ message, error }) => {
console.error(error);
setErrorMsg(t('connect-federation.error-message', { error: message }));
const errorMessage = t('connect-federation.error-message', {
error: message,
});
showError(errorMessage);
setErrorMsg(errorMessage);
})
.finally(() => {
setLoading(false);
Expand Down
7 changes: 6 additions & 1 deletion apps/router/src/guardian-ui/components/setup/RunDKG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { GuardianServerStatus } from '@fedimint/types';
import { useTranslation } from '@fedimint/utils';
import { useEllipsis } from '../../hooks';
import { formatApiErrorMessage } from '../../utils/api';
import { useNotification } from '../../../home/NotificationProvider';
import {
useConsensusPolling,
useGuardianSetupApi,
Expand All @@ -31,6 +32,7 @@ export const RunDKG: React.FC<Props> = ({ next }) => {
const [isWaitingForOthers, setIsWaitingForOthers] = useState(false);
const [error, setError] = useState<string>();
const ellipsis = useEllipsis();
const { showInfo, showSuccess } = useNotification();

// Poll for peers and configGenParams while on this page.
useConsensusPolling();
Expand All @@ -51,11 +53,14 @@ export const RunDKG: React.FC<Props> = ({ next }) => {
if (err.code === -32002) return;
throw err;
});
showInfo(t('run-dkg.waiting-header'));
break;
case GuardianServerStatus.ReadyForConfigGen:
setIsWaitingForOthers(true);
showInfo(t('connect-guardians.waiting-for-guardian'));
break;
case GuardianServerStatus.VerifyingConfigs:
showSuccess(t('connect-guardians.approved'));
next();
break;
case GuardianServerStatus.ConfigGenFailed:
Expand All @@ -75,7 +80,7 @@ export const RunDKG: React.FC<Props> = ({ next }) => {
clearTimeout(timeout);
canceled = true;
};
}, [next, api, t]);
}, [next, api, t, showInfo, showSuccess]);

const progress = useMemo(() => {
if (!peers.length) return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ import {
useGuardianSetupContext,
} from '../../../../../hooks';
import { GuardianRole } from '../../../../../types/guardian';
import { useNotification } from '../../../../../home/NotificationProvider';

interface Props {
next(): void;
}

export const ConnectGuardians: React.FC<Props> = ({ next }) => {
const { showSuccess } = useNotification();
const { t } = useTranslation();
const {
state: { role, peers, numPeers, configGenParams, ourCurrentId },
Expand All @@ -55,8 +57,9 @@ export const ConnectGuardians: React.FC<Props> = ({ next }) => {
}, [role, isAllAccepted, next]);

const handleApprove = useCallback(() => {
showSuccess(t('connect-guardians.approve'));
next();
}, [next]);
}, [next, showSuccess, t]);

let content: React.ReactNode;
if (!configGenParams) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ interface Props {

const MIN_BFT_NUM_PEERS = '4';

export const SetConfiguration: React.FC<Props> = ({ next }: Props) => {
export const SetConfiguration: React.FC<Props> = ({ next }) => {
const { t } = useTranslation();
const api = useGuardianSetupApi();
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
useGuardianSetupApi,
useGuardianSetupContext,
} from '../../../../../hooks';
import { useNotification } from '../../../../../home/NotificationProvider';

interface PeerWithHash {
id: string;
Expand Down Expand Up @@ -69,6 +70,7 @@ export const VerifyGuardians: React.FC<Props> = ({ next }) => {
const [error, setError] = useState<string>();
const [isOpen, setIsOpen] = useState(false);
const [ourPeerName, setOurPeerName] = useState('');
const { showSuccess, showError, showInfo } = useNotification();

// Poll for peers and configGenParams while on this page.
useConsensusPolling();
Expand Down Expand Up @@ -149,9 +151,12 @@ export const VerifyGuardians: React.FC<Props> = ({ next }) => {
.then(() => {
setVerifiedConfigs(true);
toggleConsensusPolling(false);
showSuccess(t('verify-guardians.verified'));
showInfo(t('verify-guardians.all-guardians-verified'));
})
.catch((err) => {
setError(formatApiErrorMessage(err));
showError(t('verify-guardians.error'));
});
}
}, [
Expand All @@ -162,18 +167,24 @@ export const VerifyGuardians: React.FC<Props> = ({ next }) => {
numPeers,
next,
toggleConsensusPolling,
showSuccess,
showError,
showInfo,
t,
]);

const handleNext = useCallback(async () => {
setIsStarting(true);
try {
await api.startConsensus();
showInfo(t('verify-guardians.starting-consensus'));
next();
} catch (err) {
setError(formatApiErrorMessage(err));
showError(t('verify-guardians.error'));
}
setIsStarting(false);
}, [api, next]);
}, [api, next, showInfo, showError, t]);

// Host of one immediately skips this step.
useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion apps/router/src/guardian-ui/setup/FederationSetup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import { VerifyGuardians } from '../components/setup/screens/verifyGuardians/Ver
import { SetupComplete } from '../components/setup/screens/setupComplete/SetupComplete';
import { SetupProgress as SetupStepper } from '../components/setup/SetupProgress';
import { TermsOfService } from '../components/TermsOfService';
import { useGuardianSetupApi, useGuardianSetupContext } from '../../hooks';

import { ReactComponent as ArrowLeftIcon } from '../assets/svgs/arrow-left.svg';
import { ReactComponent as CancelIcon } from '../assets/svgs/x-circle.svg';
import { GuardianServerStatus } from '@fedimint/types';
import { RestartModals } from './RestartModals';
import { useGuardianSetupApi, useGuardianSetupContext } from '../../hooks';

const PROGRESS_ORDER: SetupProgress[] = [
SetupProgress.Start,
Expand Down
79 changes: 79 additions & 0 deletions apps/router/src/home/NotificationProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { createContext, useContext, useCallback } from 'react';
import { useToast, UseToastOptions } from '@chakra-ui/react';

interface NotificationContextType {
showSuccess: (message: string, options?: UseToastOptions) => void;
showError: (message: string, options?: UseToastOptions) => void;
showWarning: (message: string, options?: UseToastOptions) => void;
showInfo: (message: string, options?: UseToastOptions) => void;
}

const NotificationContext = createContext<NotificationContextType | undefined>(
undefined
);

export const NotificationProvider: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const toast = useToast();

const showNotification = useCallback(
(
message: string,
status: UseToastOptions['status'],
options?: UseToastOptions
) => {
toast({
description: message,
status,
duration: 5000,
isClosable: true,
position: 'top-right',
...options,
});
},
[toast]
);

const showSuccess = useCallback(
(message: string, options?: UseToastOptions) =>
showNotification(message, 'success', options),
[showNotification]
);

const showError = useCallback(
(message: string, options?: UseToastOptions) =>
showNotification(message, 'error', options),
[showNotification]
);

const showWarning = useCallback(
(message: string, options?: UseToastOptions) =>
showNotification(message, 'warning', options),
[showNotification]
);

const showInfo = useCallback(
(message: string, options?: UseToastOptions) =>
showNotification(message, 'info', options),
[showNotification]
);

return (
<NotificationContext.Provider
value={{ showSuccess, showError, showWarning, showInfo }}
>
{children}
</NotificationContext.Provider>
);
};

export const useNotification = () => {
const context = useContext(NotificationContext);
if (context === undefined) {
throw new Error(
'useNotification must be used within a NotificationProvider'
);
}
return context;
};
21 changes: 13 additions & 8 deletions apps/router/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import { HomePage } from './home/HomePage';
import { GuardianContextProvider } from './context/guardian/GuardianContext';
import { GatewayContextProvider } from './context/gateway/GatewayContext';
import { Wrapper } from './components/Wrapper';
import { ChakraProvider } from '@chakra-ui/react';
import { NotificationProvider } from './home/NotificationProvider';
import { useAppContext } from './hooks';

i18nProvider(languages);

const App = () => {
Expand Down Expand Up @@ -116,12 +117,16 @@ const root = ReactDOM.createRoot(

root.render(
<React.StrictMode>
<SharedChakraProvider theme={theme}>
<ColorModeScript />
<Fonts spaceGroteskTtf={spaceGroteskTtf} interTtf={interTtf} />
<AppContextProvider>
<App />
</AppContextProvider>
</SharedChakraProvider>
<ChakraProvider>
<SharedChakraProvider theme={theme}>
<AppContextProvider>
<NotificationProvider>
<ColorModeScript />
<Fonts spaceGroteskTtf={spaceGroteskTtf} interTtf={interTtf} />
<App />
</NotificationProvider>
</AppContextProvider>
</SharedChakraProvider>
</ChakraProvider>
</React.StrictMode>
);
Loading
Loading