Commit 5920dba7 authored by tom's avatar tom

404 and 422 errors

parent 6c2f65d5
<svg viewBox="0 0 201 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M100.027 8.408c-2.187 0-4.238.41-6.152 1.23a15.973 15.973 0 0 0-4.922 3.35c-1.413 1.413-2.53 3.076-3.35 4.99-.82 1.869-1.23 3.897-1.23 6.084a3.372 3.372 0 0 1-3.913 3.328l-2.409-.392a2.974 2.974 0 0 1-2.496-2.936c0-3.326.615-6.448 1.845-9.365 1.276-2.916 3.008-5.468 5.196-7.656 2.187-2.187 4.74-3.896 7.656-5.127C93.169.638 96.29 0 99.617 0h4.17c3.327 0 6.449.592 9.365 1.777 2.963 1.185 5.537 2.894 7.725 5.127 2.187 2.233 3.896 4.922 5.127 8.067 1.276 3.099 1.914 6.608 1.914 10.527 0 3.874-.592 7.77-1.777 11.69a67.002 67.002 0 0 1-4.58 11.552 87.122 87.122 0 0 1-6.495 11.006 147.24 147.24 0 0 1-7.451 10.049c-5.97 7.337-12.737 14.401-20.302 21.191h32.88a8.409 8.409 0 0 1 8.409 8.408H73.436v-2.253c0-2.988 1.345-5.81 3.612-7.756 7.075-6.073 13.482-12.33 19.22-18.77a162.094 162.094 0 0 0 8.408-10.322 100.413 100.413 0 0 0 7.314-11.211c2.142-3.874 3.851-7.793 5.127-11.758 1.322-4.01 1.983-7.952 1.983-11.826 0-2.871-.433-5.378-1.299-7.52-.866-2.141-2.028-3.919-3.487-5.332a13.909 13.909 0 0 0-5.058-3.144 16.03 16.03 0 0 0-5.879-1.094h-3.35ZM48.193 82.441v16.953a8.818 8.818 0 0 1-8.818-8.818v-8.135H3.3a3.3 3.3 0 0 1-2.872-4.926L42.701 2.857a2.937 2.937 0 0 1 5.492 1.447v69.73h8.409a8.408 8.408 0 0 1-8.409 8.407Zm-8.818-56.943L12.373 74.033h27.002V25.498Zm126.5-15.86c1.914-.82 3.965-1.23 6.152-1.23h3.35c2.051 0 4.01.365 5.879 1.094 1.914.683 3.6 1.732 5.058 3.144 1.459 1.413 2.621 3.19 3.487 5.332.866 2.142 1.299 4.649 1.299 7.52 0 3.874-.661 7.816-1.983 11.826-1.276 3.965-2.985 7.884-5.127 11.758a100.413 100.413 0 0 1-7.314 11.211 162.124 162.124 0 0 1-8.408 10.322c-5.738 6.44-12.145 12.697-19.22 18.77-2.267 1.946-3.612 4.768-3.612 7.756v2.253h55.166a8.409 8.409 0 0 0-8.409-8.408h-32.881c7.566-6.79 14.333-13.854 20.303-21.191a147.24 147.24 0 0 0 7.451-10.049 87.122 87.122 0 0 0 6.495-11.006 67.002 67.002 0 0 0 4.58-11.553c1.185-3.919 1.777-7.815 1.777-11.689 0-3.92-.638-7.428-1.914-10.527-1.231-3.145-2.94-5.834-5.127-8.067-2.188-2.233-4.762-3.942-7.725-5.127C182.236.592 179.114 0 175.787 0h-4.17c-3.327 0-6.448.638-9.365 1.914-2.917 1.23-5.469 2.94-7.656 5.127-2.188 2.188-3.92 4.74-5.196 7.656-1.23 2.917-1.845 6.039-1.845 9.366a2.974 2.974 0 0 0 2.496 2.935l2.409.392a3.371 3.371 0 0 0 3.913-3.328c0-2.187.41-4.215 1.231-6.084.82-1.914 1.936-3.577 3.349-4.99a15.982 15.982 0 0 1 4.922-3.35Z" fill="currentColor"/>
</svg>
...@@ -54,6 +54,10 @@ const AddressDetails = ({ addressQuery }: Props) => { ...@@ -54,6 +54,10 @@ const AddressDetails = ({ addressQuery }: Props) => {
}, },
); );
if (addressQuery.isError) {
throw Error('Address fetch error', { cause: addressQuery.error as unknown as Error });
}
if (countersQuery.isLoading || addressQuery.isLoading || tokenBalancesQuery.isLoading) { if (countersQuery.isLoading || addressQuery.isLoading || tokenBalancesQuery.isLoading) {
return <AddressDetailsSkeleton/>; return <AddressDetailsSkeleton/>;
} }
......
import { Grid, GridItem, Text, Icon, Link, Box, Tooltip, Alert } from '@chakra-ui/react'; import { Grid, GridItem, Text, Icon, Link, Box, Tooltip } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import capitalize from 'lodash/capitalize'; import capitalize from 'lodash/capitalize';
...@@ -66,8 +66,15 @@ const BlockDetails = () => { ...@@ -66,8 +66,15 @@ const BlockDetails = () => {
} }
if (isError) { if (isError) {
const is404 = error?.error?.status === 404; if (error?.error?.status === 404) {
return is404 ? <Alert>This block has not been processed yet.</Alert> : <DataFetchAlert/>; return <span>This block has not been processed yet.</span>;
}
if (error?.error?.status === 422) {
throw Error('Invalid block number', { cause: error as unknown as Error });
}
return <DataFetchAlert/>;
} }
const sectionGap = <GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>; const sectionGap = <GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>;
......
...@@ -2,6 +2,7 @@ import { Box, Button, Heading, Icon, Text, chakra } from '@chakra-ui/react'; ...@@ -2,6 +2,7 @@ import { Box, Button, Heading, Icon, Text, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import icon404 from 'icons/error-pages/404.svg'; import icon404 from 'icons/error-pages/404.svg';
import icon422 from 'icons/error-pages/422.svg';
import icon500 from 'icons/error-pages/500.svg'; import icon500 from 'icons/error-pages/500.svg';
import link from 'lib/link/link'; import link from 'lib/link/link';
...@@ -16,6 +17,11 @@ const ERRORS: Record<string, {icon: React.FunctionComponent<React.SVGAttributes< ...@@ -16,6 +17,11 @@ const ERRORS: Record<string, {icon: React.FunctionComponent<React.SVGAttributes<
title: 'Page not found', title: 'Page not found',
text: 'This page is no longer explorable! If you are lost, use the search bar to find what you are looking for.', text: 'This page is no longer explorable! If you are lost, use the search bar to find what you are looking for.',
}, },
'422': {
icon: icon422,
title: 'Request cannot be processed',
text: 'Your request contained an error, perhaps a mistyped tx/block/address hash. Try again, and check the developer tools console for more info.',
},
'500': { '500': {
icon: icon500, icon: icon500,
title: 'Oops! Something went wrong', title: 'Oops! Something went wrong',
......
...@@ -2,17 +2,22 @@ import React from 'react'; ...@@ -2,17 +2,22 @@ import React from 'react';
interface Props { interface Props {
children: React.ReactNode; children: React.ReactNode;
renderErrorScreen: () => React.ReactNode; renderErrorScreen: (error?: Error) => React.ReactNode;
onError?: (error: Error) => void; onError?: (error: Error) => void;
} }
class ErrorBoundary extends React.PureComponent<Props> { interface State {
state = { hasError: boolean;
error?: Error;
}
class ErrorBoundary extends React.PureComponent<Props, State> {
state: State = {
hasError: false, hasError: false,
}; };
static getDerivedStateFromError() { static getDerivedStateFromError(error: Error) {
return { hasError: true }; return { hasError: true, error };
} }
componentDidCatch(error: Error) { componentDidCatch(error: Error) {
...@@ -21,7 +26,7 @@ class ErrorBoundary extends React.PureComponent<Props> { ...@@ -21,7 +26,7 @@ class ErrorBoundary extends React.PureComponent<Props> {
render() { render() {
if (this.state.hasError) { if (this.state.hasError) {
return this.props.renderErrorScreen(); return this.props.renderErrorScreen(this.state.error);
} }
return this.props.children; return this.props.children;
......
/* eslint-disable max-len */
import { Box, Heading, OrderedList, ListItem, Icon, useColorModeValue, Flex } from '@chakra-ui/react';
import React from 'react';
import txIcon from 'icons/transactions.svg';
const ErrorInvalidTxHash = () => {
const textColor = useColorModeValue('gray.500', 'gray.400');
const snippet = {
borderColor: useColorModeValue('blackAlpha.300', 'whiteAlpha.300'),
iconBg: useColorModeValue('blackAlpha.800', 'whiteAlpha.800'),
iconColor: useColorModeValue('white', 'black'),
};
return (
<Box mt="50px">
<Box p={ 4 } borderColor={ snippet.borderColor } borderRadius="md" w="230px" borderWidth="1px">
<Flex alignItems="center" pb={ 4 } borderBottomWidth="1px" borderColor={ snippet.borderColor }>
<Icon as={ txIcon } boxSize={ 8 } color={ snippet.iconColor } bgColor={ snippet.iconBg } p={ 1 } borderRadius="md"/>
<Box ml={ 2 }>
<Box w="125px" h="8px" borderRadius="full" bgColor={ snippet.iconBg }/>
<Box w="30px" h="8px" borderRadius="full" bgColor={ snippet.borderColor } mt={ 1.5 }/>
</Box>
</Flex>
<Flex justifyContent="space-between" alignItems="center" mt={ 3 }>
<Flex alignItems="center">
<Box boxSize={ 5 } borderRadius="full" bgColor={ snippet.borderColor }/>
<Box w="65px" h="8px" borderRadius="full" bgColor={ snippet.borderColor } ml={ 1.5 }/>
</Flex>
<Flex alignItems="center">
<Box boxSize={ 5 } borderRadius="full" bgColor={ snippet.borderColor }/>
<Box w="65px" h="8px" borderRadius="full" bgColor={ snippet.borderColor } ml={ 1.5 }/>
</Flex>
</Flex>
</Box>
<Heading size="2xl" fontFamily="body" mt={ 6 }>
Sorry, we are unable to locate this transaction hash
</Heading>
<OrderedList color={ textColor } mt={ 3 } spacing={ 3 }>
<ListItem>
If you have just submitted this transaction please wait for at least 30 seconds before refreshing this page.
</ListItem>
<ListItem>
It could still be in the TX Pool of a different node, waiting to be broadcasted.
</ListItem>
<ListItem>
During times when the network is busy (i.e during ICOs) it can take a while for your transaction to propagate through the network and for us to index it.
</ListItem>
<ListItem>
If it still does not show up after 1 hour, please check with your sender/exchange/wallet/transaction provider for additional information.
</ListItem>
</OrderedList>
</Box>
);
};
export default ErrorInvalidTxHash;
...@@ -8,6 +8,7 @@ import * as cookies from 'lib/cookies'; ...@@ -8,6 +8,7 @@ import * as cookies from 'lib/cookies';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import AppError from 'ui/shared/AppError/AppError'; import AppError from 'ui/shared/AppError/AppError';
import ErrorBoundary from 'ui/shared/ErrorBoundary'; import ErrorBoundary from 'ui/shared/ErrorBoundary';
import ErrorInvalidTxHash from 'ui/shared/ErrorInvalidTxHash';
import PageContent from 'ui/shared/Page/PageContent'; import PageContent from 'ui/shared/Page/PageContent';
import Header from 'ui/snippets/header/Header'; import Header from 'ui/snippets/header/Header';
import NavigationDesktop from 'ui/snippets/navigation/NavigationDesktop'; import NavigationDesktop from 'ui/snippets/navigation/NavigationDesktop';
...@@ -31,10 +32,17 @@ const Page = ({ ...@@ -31,10 +32,17 @@ const Page = ({
enabled: Boolean(cookies.get(cookies.NAMES.API_TOKEN)), enabled: Boolean(cookies.get(cookies.NAMES.API_TOKEN)),
}); });
const renderErrorScreen = React.useCallback(() => { const renderErrorScreen = React.useCallback((error?: Error) => {
return wrapChildren ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
<PageContent isHomePage={ isHomePage }><AppError statusCode={ 500 } mt="50px"/></PageContent> : const statusCode = (error?.cause as any)?.error?.status || 500;
<AppError statusCode={ 500 }/>; const isInvalidTxHash = error?.message.includes('Invalid tx hash');
if (wrapChildren) {
const content = isInvalidTxHash ? <ErrorInvalidTxHash/> : <AppError statusCode={ statusCode } mt="50px"/>;
return <PageContent isHomePage={ isHomePage }>{ content }</PageContent>;
}
return isInvalidTxHash ? <ErrorInvalidTxHash/> : <AppError statusCode={ 500 }/>;
}, [ isHomePage, wrapChildren ]); }, [ isHomePage, wrapChildren ]);
const renderedChildren = wrapChildren ? ( const renderedChildren = wrapChildren ? (
......
...@@ -32,7 +32,7 @@ import TxSocketAlert from 'ui/tx/TxSocketAlert'; ...@@ -32,7 +32,7 @@ import TxSocketAlert from 'ui/tx/TxSocketAlert';
import useFetchTxInfo from 'ui/tx/useFetchTxInfo'; import useFetchTxInfo from 'ui/tx/useFetchTxInfo';
const TxDetails = () => { const TxDetails = () => {
const { data, isLoading, isError, socketStatus } = useFetchTxInfo(); const { data, isLoading, isError, socketStatus, error } = useFetchTxInfo();
const [ isExpanded, setIsExpanded ] = React.useState(false); const [ isExpanded, setIsExpanded ] = React.useState(false);
...@@ -49,6 +49,14 @@ const TxDetails = () => { ...@@ -49,6 +49,14 @@ const TxDetails = () => {
} }
if (isError) { if (isError) {
if (error?.error?.status === 422) {
throw Error('Invalid tx hash', { cause: error as unknown as Error });
}
if (error?.error?.status === 404) {
throw Error('Tx fetch failed', { cause: error as unknown as Error });
}
return <DataFetchAlert/>; return <DataFetchAlert/>;
} }
......
...@@ -8,6 +8,7 @@ import type { Transaction } from 'types/api/transaction'; ...@@ -8,6 +8,7 @@ import type { Transaction } from 'types/api/transaction';
import { QueryKeys } from 'types/client/queries'; import { QueryKeys } from 'types/client/queries';
import delay from 'lib/delay'; import delay from 'lib/delay';
import type { ErrorType } from 'lib/hooks/useFetch';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
...@@ -17,7 +18,7 @@ interface Params { ...@@ -17,7 +18,7 @@ interface Params {
updateDelay?: number; updateDelay?: number;
} }
type ReturnType = UseQueryResult<Transaction, unknown> & { type ReturnType = UseQueryResult<Transaction, ErrorType<{ status: number }>> & {
socketStatus: 'close' | 'error' | undefined; socketStatus: 'close' | 'error' | undefined;
} }
...@@ -27,7 +28,7 @@ export default function useFetchTxInfo({ onTxStatusUpdate, updateDelay }: Params ...@@ -27,7 +28,7 @@ export default function useFetchTxInfo({ onTxStatusUpdate, updateDelay }: Params
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [ socketStatus, setSocketStatus ] = React.useState<'close' | 'error'>(); const [ socketStatus, setSocketStatus ] = React.useState<'close' | 'error'>();
const queryResult = useQuery<unknown, unknown, Transaction>( const queryResult = useQuery<unknown, ErrorType<{ status: number }>, Transaction>(
[ QueryKeys.tx, router.query.id ], [ QueryKeys.tx, router.query.id ],
async() => await fetch(`/node-api/transactions/${ router.query.id }`), async() => await fetch(`/node-api/transactions/${ router.query.id }`),
{ {
......
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