Bring back NetworkError column

This commit is contained in:
Alex Gleason 2023-11-14 14:41:35 -06:00
parent c777d767d2
commit cdb89ae8fd
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
3 changed files with 75 additions and 16 deletions

View file

@ -0,0 +1,45 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { Column, Stack, Text, IconButton } from 'soapbox/components/ui';
import { isNetworkError } from 'soapbox/utils/errors';
const messages = defineMessages({
title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' },
body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this page.' },
retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' },
});
interface IErrorColumn {
error: Error;
onRetry?: () => void;
}
const ErrorColumn: React.FC<IErrorColumn> = ({ error, onRetry = () => location.reload() }) => {
const intl = useIntl();
const handleRetry = () => {
onRetry?.();
};
if (!isNetworkError(error)) {
throw error;
}
return (
<Column label={intl.formatMessage(messages.title)}>
<Stack space={4} alignItems='center' justifyContent='center' className='min-h-[160px] rounded-lg p-10'>
<IconButton
iconClassName='h-10 w-10'
title={intl.formatMessage(messages.retry)}
src={require('@tabler/icons/refresh.svg')}
onClick={handleRetry}
/>
<Text align='center' theme='muted'>{intl.formatMessage(messages.body)}</Text>
</Stack>
</Column>
);
};
export default ErrorColumn;

View file

@ -1,4 +1,5 @@
import React, { Suspense } from 'react';
import React, { ComponentProps, Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { Redirect, Route, useHistory, RouteProps, RouteComponentProps, match as MatchType } from 'react-router-dom';
import { Layout } from 'soapbox/components/ui';
@ -7,6 +8,7 @@ import { useOwnAccount, useSettings } from 'soapbox/hooks';
import ColumnForbidden from '../components/column-forbidden';
import ColumnLoading from '../components/column-loading';
import ColumnsArea from '../components/columns-area';
import ErrorColumn from '../components/error-column';
type PageProps = {
params?: MatchType['params'];
@ -46,24 +48,28 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
const renderComponent = ({ match }: RouteComponentProps) => {
if (Page) {
return (
<Suspense fallback={renderLoading()}>
<Page params={match.params} layout={layout} {...componentParams}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</Page>
</Suspense>
<ErrorBoundary FallbackComponent={renderError}>
<Suspense fallback={renderLoading()}>
<Page params={match.params} layout={layout} {...componentParams}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</Page>
</Suspense>
</ErrorBoundary>
);
}
return (
<Suspense fallback={renderLoading()}>
<ColumnsArea layout={layout}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</ColumnsArea>
</Suspense>
<ErrorBoundary FallbackComponent={renderError}>
<Suspense fallback={renderLoading()}>
<ColumnsArea layout={layout}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</ColumnsArea>
</Suspense>
</ErrorBoundary>
);
};
@ -79,6 +85,7 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
const renderLoading = () => renderWithLayout(<ColumnLoading />);
const renderForbidden = () => renderWithLayout(<ColumnForbidden />);
const renderError = (props: ComponentProps<typeof ErrorColumn>) => renderWithLayout(<ErrorColumn {...props} />);
const loginRedirect = () => {
const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`);

View file

@ -200,4 +200,11 @@ const httpErrorMessages: { code: number; name: string; description: string }[] =
},
];
export { buildErrorMessage, httpErrorMessages };
/** Whether the error is caused by a JS chunk failing to load. */
function isNetworkError(error: unknown): boolean {
return error instanceof Error
&& error.name === 'TypeError'
&& error.message.startsWith('Failed to fetch dynamically imported module: ');
}
export { buildErrorMessage, httpErrorMessages, isNetworkError };