Commit c76bd75e authored by tom's avatar tom

show pending toast until data is fetched

parent 48d6f5b5
...@@ -14,6 +14,7 @@ const defaultOptions: UseToastOptions & { toastComponent?: React.FC<ToastProps> ...@@ -14,6 +14,7 @@ const defaultOptions: UseToastOptions & { toastComponent?: React.FC<ToastProps>
containerStyle: { containerStyle: {
margin: 8, margin: 8,
}, },
variant: 'subtle',
}; };
export default function useToastModified() { export default function useToastModified() {
......
...@@ -20,7 +20,7 @@ function getBgColor(status?: AlertStatus) { ...@@ -20,7 +20,7 @@ function getBgColor(status?: AlertStatus) {
} }
} }
const Toast = ({ onClose, title, description, id, isClosable, status }: ToastProps) => { const Toast = ({ onClose, title, description, id, isClosable, status, icon }: ToastProps) => {
const ids = id ? const ids = id ?
{ {
...@@ -48,7 +48,7 @@ const Toast = ({ onClose, title, description, id, isClosable, status }: ToastPro ...@@ -48,7 +48,7 @@ const Toast = ({ onClose, title, description, id, isClosable, status }: ToastPro
maxWidth="400px" maxWidth="400px"
> >
<chakra.div flex="1" maxWidth="100%"> <chakra.div flex="1" maxWidth="100%">
{ title && <AlertTitle id={ ids?.title }>{ title }</AlertTitle> } { title && <AlertTitle id={ ids?.title } display="flex" alignItems="center">{ icon }{ title }</AlertTitle> }
{ description && ( { description && (
<AlertDescription id={ ids?.description } display="block"> <AlertDescription id={ ids?.description } display="block">
{ description } { description }
......
import { chakra, Alert, Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay } from '@chakra-ui/react'; import type { ToastId } from '@chakra-ui/react';
import { chakra, Alert, Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay, Spinner } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import ReCaptcha from 'react-google-recaptcha'; import ReCaptcha from 'react-google-recaptcha';
...@@ -9,7 +10,7 @@ import type { TokenInstance } from 'types/api/token'; ...@@ -9,7 +10,7 @@ import type { TokenInstance } from 'types/api/token';
import config from 'configs/app'; import config from 'configs/app';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import { getResourceKey } from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
import { MINUTE } from 'lib/consts'; import { MINUTE, SECOND } from 'lib/consts';
import useToast from 'lib/hooks/useToast'; import useToast from 'lib/hooks/useToast';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
...@@ -23,6 +24,7 @@ interface Props { ...@@ -23,6 +24,7 @@ interface Props {
const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => { const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => {
const timeoutId = React.useRef<number>(); const timeoutId = React.useRef<number>();
const toastId = React.useRef<ToastId>();
const { status, setStatus } = useMetadataUpdateContext() || {}; const { status, setStatus } = useMetadataUpdateContext() || {};
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
...@@ -31,12 +33,12 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => { ...@@ -31,12 +33,12 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => {
const handleRefreshError = React.useCallback(() => { const handleRefreshError = React.useCallback(() => {
setStatus?.('ERROR'); setStatus?.('ERROR');
toast.closeAll(); toastId.current && toast.update(toastId.current, {
toast({
title: 'Error', title: 'Error',
description: 'The refreshing process has failed. Please try again.', description: 'The refreshing process has failed. Please try again.',
status: 'warning', status: 'warning',
variant: 'subtle', duration: 5 * SECOND,
isClosable: true,
}); });
}, [ setStatus, toast ]); }, [ setStatus, toast ]);
...@@ -49,13 +51,15 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => { ...@@ -49,13 +51,15 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => {
}, },
}) })
.then(() => { .then(() => {
toast({ setStatus?.('WAITING_FOR_RESPONSE');
toastId.current = toast({
title: 'Please wait', title: 'Please wait',
description: 'Refetching metadata request sent', description: 'Refetching metadata request sent',
icon: <Spinner size="sm" mr={ 2 }/>,
status: 'warning', status: 'warning',
variant: 'subtle', duration: null,
isClosable: false,
}); });
setStatus?.('WAITING_FOR_RESPONSE');
timeoutId.current = window.setTimeout(handleRefreshError, 2 * MINUTE); timeoutId.current = window.setTimeout(handleRefreshError, 2 * MINUTE);
}) })
.catch(() => { .catch(() => {
...@@ -63,7 +67,6 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => { ...@@ -63,7 +67,6 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => {
title: 'Error', title: 'Error',
description: 'Unable to initialize metadata update', description: 'Unable to initialize metadata update',
status: 'warning', status: 'warning',
variant: 'subtle',
}); });
setStatus?.('ERROR'); setStatus?.('ERROR');
}); });
...@@ -112,12 +115,12 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => { ...@@ -112,12 +115,12 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => {
}; };
}); });
toast.closeAll(); toastId.current && toast.update(toastId.current, {
toast({
title: 'Success!', title: 'Success!',
description: 'Metadata has been refreshed', description: 'Metadata has been refreshed',
status: 'success', status: 'success',
variant: 'subtle', duration: 5 * SECOND,
isClosable: true,
}); });
setStatus?.('SUCCESS'); setStatus?.('SUCCESS');
...@@ -138,6 +141,15 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => { ...@@ -138,6 +141,15 @@ const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => {
handler: handleSocketMessage, handler: handleSocketMessage,
}); });
React.useEffect(() => {
return () => {
timeoutId.current && window.clearTimeout(timeoutId.current);
toastId.current && toast.close(toastId.current);
};
// run only on mount/unmount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return ( return (
<Modal isOpen={ status === 'MODAL_OPENED' } onClose={ handleModalClose } size={{ base: 'full', lg: 'sm' }}> <Modal isOpen={ status === 'MODAL_OPENED' } onClose={ handleModalClose } size={{ base: 'full', lg: 'sm' }}>
<ModalOverlay/> <ModalOverlay/>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment