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
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);
showInfo(t('connect-federation.progress-modal-text'));

api
.connectFederation(connectInfo.trim())
.then((federation) => {
// showSuccess(t('connect-federation.success-message'));
renderConnectedFedCallback(federation);
setConnectInfo('');
onClose();
kleysc marked this conversation as resolved.
Show resolved Hide resolved
})
.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);
kleysc marked this conversation as resolved.
Show resolved Hide resolved
})
.finally(() => {
setLoading(false);
Expand Down
3 changes: 3 additions & 0 deletions apps/router/src/guardian-ui/components/setup/RunDKG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,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('run-dkg.waiting-for-others'));
break;
case GuardianServerStatus.VerifyingConfigs:
//showSuccess(t('run-dkg.completed'));
kleysc marked this conversation as resolved.
Show resolved Hide resolved
next();
break;
case GuardianServerStatus.ConfigGenFailed:
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
11 changes: 8 additions & 3 deletions apps/router/src/guardian-ui/setup/FederationSetup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ 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 { useNotification } from '../../home/NotificationProvider';

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 All @@ -38,6 +39,7 @@ export const FederationSetup: React.FC = () => {
state: { progress, role, peers, tosConfig },
dispatch,
} = useGuardianSetupContext();
const { showSuccess, showError } = useNotification();
const [confirmRestart, setConfirmRestart] = useState(false);

const setTosConfig = useCallback(
Expand All @@ -59,7 +61,8 @@ export const FederationSetup: React.FC = () => {
if (!prevProgress) return;
dispatch({ type: SETUP_ACTION_TYPE.SET_PROGRESS, payload: prevProgress });
window.scrollTo(0, 0);
}, [dispatch, prevProgress]);
showSuccess(t('common.back'));
}, [dispatch, prevProgress, showSuccess, t]);
kleysc marked this conversation as resolved.
Show resolved Hide resolved

const handleNext = useCallback(() => {
if (!nextProgress) return;
Expand All @@ -73,11 +76,13 @@ export const FederationSetup: React.FC = () => {
.then(() => {
dispatch({ type: SETUP_ACTION_TYPE.SET_INITIAL_STATE, payload: null });
window.scrollTo(0, 0);
showSuccess(t('setup.common.restart-success'));
})
.catch((err) => {
console.error(err);
showError(t('setup.common.restart-error'));
});
}, [api, dispatch]);
}, [api, dispatch, showSuccess, showError, t]);

let title: React.ReactNode;
let subtitle: React.ReactNode;
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}>
<ColorModeScript />
<Fonts spaceGroteskTtf={spaceGroteskTtf} interTtf={interTtf} />
<AppContextProvider>
<NotificationProvider>
<App />
</NotificationProvider>
</AppContextProvider>
kleysc marked this conversation as resolved.
Show resolved Hide resolved
</SharedChakraProvider>
</ChakraProvider>
kleysc marked this conversation as resolved.
Show resolved Hide resolved
</React.StrictMode>
);
Loading