Commit abdd2a51 authored by tom's avatar tom

custom error screen for 403

parent 90a73c95
......@@ -63,6 +63,9 @@ export const RESOURCES = {
user_info: {
path: '/api/account/v1/user/info',
},
email_resend: {
path: '/api/account/v1/email/resend',
},
custom_abi: {
path: '/api/account/v1/user/custom_abis/:id?',
pathParams: [ 'id' as const ],
......
import getErrorCause from './getErrorCause';
export default function getErrorStatusCode(error: Error | undefined): number | undefined {
export default function getErrorCauseStatusCode(error: Error | undefined): number | undefined {
const cause = getErrorCause(error);
return cause && 'status' in cause && typeof cause.status === 'number' ? cause.status : undefined;
}
export default function getErrorObj(error: unknown) {
if (typeof error !== 'object') {
return;
}
if (Array.isArray(error)) {
return;
}
if (error === null) {
return;
}
return error;
}
import getErrorObj from './getErrorObj';
export default function getErrorObjPayload<Payload extends object>(error: unknown): Payload | undefined {
const errorObj = getErrorObj(error);
if (!errorObj || !('payload' in errorObj)) {
return;
}
if (typeof errorObj.payload !== 'object') {
return;
}
if (errorObj === null) {
return;
}
if (Array.isArray(errorObj)) {
return;
}
return errorObj.payload as Payload;
}
import getErrorObj from './getErrorObj';
export default function getErrorObjStatusCode(error: unknown) {
const errorObj = getErrorObj(error);
if (!errorObj || !('statusCode' in errorObj) || typeof errorObj.statusCode !== 'number') {
return;
}
return errorObj.statusCode;
}
......@@ -9,7 +9,7 @@ import type { ResourceError } from 'lib/api/resources';
import { AppContextProvider } from 'lib/appContext';
import { Chakra } from 'lib/Chakra';
import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection';
import getErrorStatusCode from 'lib/errors/getErrorStatusCode';
import getErrorCauseStatusCode from 'lib/errors/getErrorCauseStatusCode';
import useConfigSentry from 'lib/hooks/useConfigSentry';
import { SocketProvider } from 'lib/socket/context';
import theme from 'theme';
......@@ -27,7 +27,7 @@ function MyApp({ Component, pageProps }: AppProps) {
refetchOnWindowFocus: false,
retry: (failureCount, _error) => {
const error = _error as ResourceError<{ status: number }>;
const status = error?.status || error?.payload?.status;
const status = error?.payload?.status || error?.status;
if (status && status >= 400 && status < 500) {
// don't do retry for client error responses
return false;
......@@ -40,7 +40,7 @@ function MyApp({ Component, pageProps }: AppProps) {
}));
const renderErrorScreen = React.useCallback((error?: Error) => {
const statusCode = getErrorStatusCode(error);
const statusCode = getErrorCauseStatusCode(error);
return (
<AppError
......
......@@ -4,13 +4,16 @@ import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import ApiKeys from 'ui/pages/ApiKeys';
import Page from 'ui/shared/Page/Page';
const ApiKeysPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head><title>{ title }</title></Head>
<ApiKeys/>
<Page>
<ApiKeys/>
</Page>
</>
);
};
......
......@@ -4,13 +4,16 @@ import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import CustomAbi from 'ui/pages/CustomAbi';
import Page from 'ui/shared/Page/Page';
const CustomAbiPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head><title>{ title }</title></Head>
<CustomAbi/>
<Page>
<CustomAbi/>
</Page>
</>
);
};
......
......@@ -4,13 +4,16 @@ import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import PublicTags from 'ui/pages/PublicTags';
import Page from 'ui/shared/Page/Page';
const PublicTagsPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head><title>{ title }</title></Head>
<PublicTags/>
<Page>
<PublicTags/>
</Page>
</>
);
};
......
......@@ -4,13 +4,16 @@ import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import PrivateTags from 'ui/pages/PrivateTags';
import Page from 'ui/shared/Page/Page';
const AddressTagsPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head><title>{ title }</title></Head>
<PrivateTags/>
<Page>
<PrivateTags/>
</Page>
</>
);
};
......
......@@ -4,6 +4,7 @@ import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import WatchList from 'ui/pages/Watchlist';
import Page from 'ui/shared/Page/Page';
const WatchListPage: NextPage = () => {
const title = getNetworkTitle();
......@@ -12,7 +13,9 @@ const WatchListPage: NextPage = () => {
<Head>
<title>{ title }</title>
</Head>
<WatchList/>
<Page>
<WatchList/>
</Page>
</>
);
};
......
......@@ -3,12 +3,15 @@ import Head from 'next/head';
import React from 'react';
import MyProfile from 'ui/pages/MyProfile';
import Page from 'ui/shared/Page/Page';
const MyProfilePage: NextPage = () => {
return (
<>
<Head><title>My profile</title></Head>
<MyProfile/>
<Page>
<MyProfile/>
</Page>
</>
);
};
......
......@@ -7,10 +7,12 @@ import type { UserInfo } from 'types/api/account';
import starFilledIcon from 'icons/star_filled.svg';
import starOutlineIcon from 'icons/star_outline.svg';
import type { ResourceError } from 'lib/api/resources';
import { resourceKey } from 'lib/api/resources';
import { getResourceKey } from 'lib/api/useApiQuery';
import useLoginUrl from 'lib/hooks/useLoginUrl';
import usePreventFocusAfterModalClosing from 'lib/hooks/usePreventFocusAfterModalClosing';
import useToast from 'lib/hooks/useToast';
import WatchlistAddModal from 'ui/watchlist/AddressModal/AddressModal';
import DeleteAddressModal from 'ui/watchlist/DeleteAddressModal';
......@@ -25,18 +27,35 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
const deleteModalProps = useDisclosure();
const queryClient = useQueryClient();
const router = useRouter();
const toast = useToast();
const profileData = queryClient.getQueryData<UserInfo>([ resourceKey('user_info') ]);
const profileState = queryClient.getQueryState<unknown, ResourceError<{ message: string }>>([ resourceKey('user_info') ]);
const isAuth = Boolean(profileData);
const loginUrl = useLoginUrl();
const handleClick = React.useCallback(() => {
if (profileState?.error?.status === 403) {
const isUnverifiedEmail = profileState.error.payload?.message.includes('Unverified email');
if (isUnverifiedEmail) {
toast({
position: 'top-right',
title: 'Error',
description: 'Unable to add address to watch list. Please go to the watch list page instead.',
status: 'error',
variant: 'subtle',
isClosable: true,
});
return;
}
}
if (!isAuth) {
window.location.assign(loginUrl);
return;
}
watchListId ? deleteModalProps.onOpen() : addModalProps.onOpen();
}, [ addModalProps, deleteModalProps, watchListId, isAuth, loginUrl ]);
}, [ profileState?.error, isAuth, watchListId, deleteModalProps, addModalProps, loginUrl, toast ]);
const handleAddOrDeleteSuccess = React.useCallback(async() => {
const queryKey = getResourceKey('address', { pathParams: { hash: router.query.hash?.toString() } });
......
......@@ -12,8 +12,6 @@ import ApiKeyListItem from 'ui/apiKey/ApiKeyTable/ApiKeyListItem';
import ApiKeyTable from 'ui/apiKey/ApiKeyTable/ApiKeyTable';
import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal';
import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import SkeletonListAccount from 'ui/shared/skeletons/SkeletonListAccount';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
......@@ -29,7 +27,7 @@ const ApiKeysPage: React.FC = () => {
const [ apiKeyModalData, setApiKeyModalData ] = useState<ApiKey>();
const [ deleteModalData, setDeleteModalData ] = useState<ApiKey>();
const { data, isLoading, isError } = useApiQuery('api_keys');
const { data, isLoading, isError, error } = useApiQuery('api_keys');
const onEditClick = useCallback((data: ApiKey) => {
setApiKeyModalData(data);
......@@ -76,7 +74,7 @@ const ApiKeysPage: React.FC = () => {
}
if (isError) {
return <DataFetchAlert/>;
throw new Error('API keys fetch error', { cause: error });
}
const list = isMobile ? (
......@@ -130,12 +128,10 @@ const ApiKeysPage: React.FC = () => {
})();
return (
<Page>
<Box h="100%">
<PageTitle text="API keys"/>
{ content }
</Box>
</Page>
<>
<PageTitle text="API keys"/>
{ content }
</>
);
};
......
......@@ -11,8 +11,6 @@ import CustomAbiListItem from 'ui/customAbi/CustomAbiTable/CustomAbiListItem';
import CustomAbiTable from 'ui/customAbi/CustomAbiTable/CustomAbiTable';
import DeleteCustomAbiModal from 'ui/customAbi/DeleteCustomAbiModal';
import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import SkeletonListAccount from 'ui/shared/skeletons/SkeletonListAccount';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
......@@ -26,7 +24,7 @@ const CustomAbiPage: React.FC = () => {
const [ customAbiModalData, setCustomAbiModalData ] = useState<CustomAbi>();
const [ deleteModalData, setDeleteModalData ] = useState<CustomAbi>();
const { data, isLoading, isError } = useApiQuery('custom_abi');
const { data, isLoading, isError, error } = useApiQuery('custom_abi');
const onEditClick = useCallback((data: CustomAbi) => {
setCustomAbiModalData(data);
......@@ -72,7 +70,7 @@ const CustomAbiPage: React.FC = () => {
}
if (isError) {
return <DataFetchAlert/>;
throw new Error('Custom ABI fetch error', { cause: error });
}
const list = isMobile ? (
......@@ -113,12 +111,10 @@ const CustomAbiPage: React.FC = () => {
})();
return (
<Page>
<Box h="100%">
<PageTitle text="Custom ABI"/>
{ content }
</Box>
</Page>
<>
<PageTitle text="Custom ABI"/>
{ content }
</>
);
};
......
......@@ -4,13 +4,11 @@ import React from 'react';
import useFetchProfileInfo from 'lib/hooks/useFetchProfileInfo';
import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken';
import ContentLoader from 'ui/shared/ContentLoader';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import UserAvatar from 'ui/shared/UserAvatar';
const MyProfile = () => {
const { data, isLoading, isError, isFetched } = useFetchProfileInfo();
const { data, isLoading, isError, error, isFetched } = useFetchProfileInfo();
useRedirectForInvalidAuthToken();
const content = (() => {
......@@ -19,7 +17,7 @@ const MyProfile = () => {
}
if (isError) {
return <DataFetchAlert/>;
throw new Error('My profile fetch error', { cause: error });
}
return (
......@@ -54,10 +52,10 @@ const MyProfile = () => {
})();
return (
<Page>
<>
<PageTitle text="My profile"/>
{ content }
</Page>
</>
);
};
......
......@@ -5,7 +5,6 @@ import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken';
import PrivateAddressTags from 'ui/privateTags/PrivateAddressTags';
import PrivateTransactionTags from 'ui/privateTags/PrivateTransactionTags';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import RoutedTabs from 'ui/shared/RoutedTabs/RoutedTabs';
......@@ -18,10 +17,10 @@ const PrivateTags = () => {
useRedirectForInvalidAuthToken();
return (
<Page>
<>
<PageTitle text="Private tags"/>
<RoutedTabs tabs={ TABS }/>
</Page>
</>
);
};
......
......@@ -10,7 +10,6 @@ import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthT
import useToast from 'lib/hooks/useToast';
import PublicTagsData from 'ui/publicTags/PublicTagsData';
import PublicTagsForm from 'ui/publicTags/PublicTagsForm/PublicTagsForm';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
type TScreen = 'data' | 'form';
......@@ -78,7 +77,7 @@ const PublicTagsComponent: React.FC = () => {
}
return (
<Page>
<>
{ screen === 'form' && (
<Link display="inline-flex" alignItems="center" mb={ 6 } onClick={ onGoBack }>
<Icon as={ eastArrowIcon } boxSize={ 6 } transform="rotate(180deg)"/>
......@@ -87,7 +86,7 @@ const PublicTagsComponent: React.FC = () => {
) }
<PageTitle text={ header } display={{ base: 'block', lg: 'inline-flex' }} ml={{ base: 0, lg: 3 }}/>
{ content }
</Page>
</>
);
};
......
......@@ -10,8 +10,6 @@ import useApiFetch from 'lib/api/useApiFetch';
import useIsMobile from 'lib/hooks/useIsMobile';
import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken';
import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import SkeletonListAccount from 'ui/shared/skeletons/SkeletonListAccount';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
......@@ -22,31 +20,27 @@ import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable';
const WatchList: React.FC = () => {
const apiFetch = useApiFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, TWatchlist>([ resourceKey('watchlist') ], async() => {
try {
const watchlistAddresses = await apiFetch<'watchlist', Array<WatchlistAddress>>('watchlist');
const { data, isLoading, isError, error } = useQuery<unknown, unknown, TWatchlist>([ resourceKey('watchlist') ], async() => {
const watchlistAddresses = await apiFetch<'watchlist', Array<WatchlistAddress>>('watchlist');
if (!Array.isArray(watchlistAddresses)) {
throw Error();
}
const watchlistTokens = await Promise.all(watchlistAddresses.map(({ address }) => {
if (!address?.hash) {
return Promise.resolve(0);
}
return apiFetch<'old_api', WatchlistTokensResponse>('old_api', { queryParams: { address: address.hash, module: 'account', action: 'tokenlist' } })
.then((response) => {
if ('result' in response && Array.isArray(response.result)) {
return response.result.length;
}
return 0;
});
}));
return watchlistAddresses.map((item, index) => ({ ...item, tokens_count: watchlistTokens[index] }));
} catch (error) {
return error;
if (!Array.isArray(watchlistAddresses)) {
return;
}
const watchlistTokens = await Promise.all(watchlistAddresses.map(({ address }) => {
if (!address?.hash) {
return Promise.resolve(0);
}
return apiFetch<'old_api', WatchlistTokensResponse>('old_api', { queryParams: { address: address.hash, module: 'account', action: 'tokenlist' } })
.then((response) => {
if ('result' in response && Array.isArray(response.result)) {
return response.result.length;
}
return 0;
});
}));
return watchlistAddresses.map((item, index) => ({ ...item, tokens_count: watchlistTokens[index] }));
});
const queryClient = useQueryClient();
......@@ -96,24 +90,27 @@ const WatchList: React.FC = () => {
</AccountPageDescription>
);
let content;
if (isLoading && !data) {
const loader = isMobile ? <SkeletonListAccount showFooterSlot/> : (
<>
<SkeletonTable columns={ [ '70%', '30%', '160px', '108px' ] }/>
<Skeleton height="44px" width="156px" marginTop={ 8 }/>
</>
);
if (isError) {
throw new Error('Watch list fetch error', { cause: error });
}
const content = (() => {
if (isLoading && !data) {
const loader = isMobile ? <SkeletonListAccount showFooterSlot/> : (
<>
<SkeletonTable columns={ [ '70%', '30%', '160px', '108px' ] }/>
<Skeleton height="44px" width="156px" marginTop={ 8 }/>
</>
);
return (
<>
{ description }
{ loader }
</>
);
}
content = (
<>
{ description }
{ loader }
</>
);
} else if (isError) {
content = <DataFetchAlert/>;
} else {
const list = isMobile ? (
<Box>
{ data.map((item) => (
......@@ -133,7 +130,7 @@ const WatchList: React.FC = () => {
/>
);
content = (
return (
<>
{ description }
{ Boolean(data?.length) && list }
......@@ -142,7 +139,7 @@ const WatchList: React.FC = () => {
size="lg"
onClick={ addressModalProps.onOpen }
>
Add address
Add address
</Button>
</Box>
<AddressModal
......@@ -162,15 +159,13 @@ const WatchList: React.FC = () => {
) }
</>
);
}
})();
return (
<Page>
<Box h="100%">
<PageTitle text="Watch list"/>
{ content }
</Box>
</Page>
<>
<PageTitle text="Watch list"/>
{ content }
</>
);
};
......
......@@ -7,7 +7,6 @@ import useApiQuery from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
import { PRIVATE_TAG_ADDRESS } from 'stubs/account';
import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import AddressModal from './AddressModal/AddressModal';
import AddressTagListItem from './AddressTagTable/AddressTagListItem';
......@@ -15,7 +14,7 @@ import AddressTagTable from './AddressTagTable/AddressTagTable';
import DeletePrivateTagModal from './DeletePrivateTagModal';
const PrivateAddressTags = () => {
const { data: addressTagsData, isError, isPlaceholderData } = useApiQuery('private_tags_address', {
const { data: addressTagsData, isError, error, isPlaceholderData } = useApiQuery('private_tags_address', {
queryOptions: {
refetchOnMount: false,
placeholderData: Array(3).fill(PRIVATE_TAG_ADDRESS),
......@@ -50,7 +49,7 @@ const PrivateAddressTags = () => {
}, [ deleteModalProps ]);
if (isError) {
return <DataFetchAlert/>;
throw new Error('Private tags fetch error', { cause: error });
}
const list = isMobile ? (
......
......@@ -6,7 +6,6 @@ import type { TransactionTag } from 'types/api/account';
import useApiQuery from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import SkeletonListAccount from 'ui/shared/skeletons/SkeletonListAccount';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
......@@ -16,7 +15,7 @@ import TransactionTagListItem from './TransactionTagTable/TransactionTagListItem
import TransactionTagTable from './TransactionTagTable/TransactionTagTable';
const PrivateTransactionTags = () => {
const { data: transactionTagsData, isLoading, isError } = useApiQuery('private_tags_tx', { queryOptions: { refetchOnMount: false } });
const { data: transactionTagsData, isLoading, isError, error } = useApiQuery('private_tags_tx', { queryOptions: { refetchOnMount: false } });
const transactionModalProps = useDisclosure();
const deleteModalProps = useDisclosure();
......@@ -69,7 +68,7 @@ const PrivateTransactionTags = () => {
}
if (isError) {
return <DataFetchAlert/>;
throw new Error('Private tags fetch error', { cause: error });
}
const list = isMobile ? (
......
......@@ -7,7 +7,6 @@ import useApiQuery from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
import PublicTagListItem from 'ui/publicTags/PublicTagTable/PublicTagListItem';
import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import SkeletonListAccount from 'ui/shared/skeletons/SkeletonListAccount';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
......@@ -24,7 +23,7 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
const [ deleteModalData, setDeleteModalData ] = useState<PublicTag>();
const isMobile = useIsMobile();
const { data, isLoading, isError } = useApiQuery('public_tags');
const { data, isLoading, isError, error } = useApiQuery('public_tags');
const onDeleteModalClose = useCallback(() => {
setDeleteModalData(undefined);
......@@ -70,7 +69,7 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
}
if (isError) {
return <DataFetchAlert/>;
throw new Error('Public tags fetch error', { cause: error });
}
const list = isMobile ? (
......
......@@ -4,7 +4,7 @@ import React from 'react';
import txIcon from 'icons/transactions.svg';
const ErrorInvalidTxHash = () => {
const AppErrorInvalidTxHash = () => {
const textColor = useColorModeValue('gray.500', 'gray.400');
const snippet = {
borderColor: useColorModeValue('blackAlpha.300', 'whiteAlpha.300'),
......@@ -54,4 +54,4 @@ const ErrorInvalidTxHash = () => {
);
};
export default ErrorInvalidTxHash;
export default AppErrorInvalidTxHash;
import { Box, Text, Button, Heading, Icon, chakra } from '@chakra-ui/react';
import React from 'react';
import icon404 from 'icons/error-pages/404.svg';
import useApiFetch from 'lib/api/useApiFetch';
import getErrorObjPayload from 'lib/errors/getErrorObjPayload';
import getErrorObjStatusCode from 'lib/errors/getErrorObjStatusCode';
import useToast from 'lib/hooks/useToast';
interface Props {
className?: string;
}
const AppErrorUnverifiedEmail = ({ className }: Props) => {
const apiFetch = useApiFetch();
const toast = useToast();
const handleButtonClick = React.useCallback(async() => {
const toastId = 'resend-email-error';
try {
await apiFetch('email_resend');
toast({
id: toastId,
position: 'top-right',
title: 'Success',
description: 'Email successfully resent.',
status: 'success',
variant: 'subtle',
isClosable: true,
});
} catch (error) {
const statusCode = getErrorObjStatusCode(error);
const payload = getErrorObjPayload<{ message: string }>(error);
const message = statusCode === 429 ? payload?.message : undefined;
!toast.isActive(toastId) && toast({
id: toastId,
position: 'top-right',
title: 'Error',
description: message || 'Something went wrong. Try again later.',
status: 'error',
variant: 'subtle',
isClosable: true,
});
}
}, [ apiFetch, toast ]);
return (
<Box className={ className }>
<Icon as={ icon404 } width="200px" height="auto"/>
<Heading mt={ 8 } size="2xl" fontFamily="body">Email is not verified</Heading>
<Text variant="secondary" mt={ 3 }>
Please confirm your email address to use the My Account feature. A confirmation email was sent to test@gmail.com on signup. { `Didn't receive?` }
</Text>
<Button
mt={ 8 }
size="lg"
variant="outline"
onClick={ handleButtonClick }
>
Resend verification email
</Button>
</Box>
);
};
export default chakra(AppErrorUnverifiedEmail);
import { Flex } from '@chakra-ui/react';
import React from 'react';
import getErrorStatusCode from 'lib/errors/getErrorStatusCode';
import getErrorCauseStatusCode from 'lib/errors/getErrorCauseStatusCode';
import getResourceErrorPayload from 'lib/errors/getResourceErrorPayload';
import useAdblockDetect from 'lib/hooks/useAdblockDetect';
import useGetCsrfToken from 'lib/hooks/useGetCsrfToken';
import AppError from 'ui/shared/AppError/AppError';
import AppErrorBlockConsensus from 'ui/shared/AppError/AppErrorBlockConsensus';
import AppErrorInvalidTxHash from 'ui/shared/AppError/AppErrorInvalidTxHash';
import AppErrorUnverifiedEmail from 'ui/shared/AppError/AppErrorUnverifiedEmail';
import ErrorBoundary from 'ui/shared/ErrorBoundary';
import ErrorInvalidTxHash from 'ui/shared/ErrorInvalidTxHash';
import PageContent from 'ui/shared/Page/PageContent';
import Header from 'ui/snippets/header/Header';
import NavigationDesktop from 'ui/snippets/navigation/NavigationDesktop';
......@@ -32,7 +33,7 @@ const Page = ({
useAdblockDetect();
const renderErrorScreen = React.useCallback((error?: Error) => {
const statusCode = getErrorStatusCode(error) || 500;
const statusCode = getErrorCauseStatusCode(error) || 500;
const resourceErrorPayload = getResourceErrorPayload(error);
const messageInPayload = resourceErrorPayload && 'message' in resourceErrorPayload && typeof resourceErrorPayload.message === 'string' ?
resourceErrorPayload.message :
......@@ -40,9 +41,14 @@ const Page = ({
const isInvalidTxHash = error?.message.includes('Invalid tx hash');
const isBlockConsensus = messageInPayload?.includes('Block lost consensus');
const isUnverifiedEmail = statusCode === 403 && messageInPayload?.includes('Unverified email');
if (isInvalidTxHash) {
return <PageContent isHomePage={ isHomePage }><ErrorInvalidTxHash/></PageContent>;
return <PageContent isHomePage={ isHomePage }><AppErrorInvalidTxHash/></PageContent>;
}
if (isUnverifiedEmail) {
return <PageContent isHomePage={ isHomePage }><AppErrorUnverifiedEmail mt="50px"/></PageContent>;
}
if (isBlockConsensus) {
......
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