feat: add error boundary

This commit is contained in:
Jeremy Kahn 2022-10-01 13:38:56 -05:00
parent 69a15443ce
commit 44c328fd1f
4 changed files with 80 additions and 2 deletions

View File

@ -0,0 +1,74 @@
import { Component, ErrorInfo, ReactNode } from 'react'
import { Link } from 'react-router-dom'
import Alert from '@mui/material/Alert'
import Box from '@mui/material/Box'
import IconButton from '@mui/material/IconButton'
import Typography from '@mui/material/Typography'
import CloseIcon from '@mui/icons-material/Close'
import { routes } from 'config/routes'
interface Props {
children?: ReactNode
}
interface State {
error: Error | null
showError: boolean
}
// Adapted from https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/error_boundaries/
export class ErrorBoundary extends Component<Props, State> {
public state: State = {
error: null,
showError: false,
}
public static getDerivedStateFromError(error: Error): State {
return { error, showError: true }
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('Uncaught error:', error, errorInfo)
}
public render() {
if (this.state.error && this.state.showError) {
const { name, message, stack } = this.state.error
return (
<Box>
<Alert
severity="error"
action={
<IconButton
aria-label="close"
color="inherit"
size="small"
onClick={() => {
this.setState({ error: null, showError: false })
}}
>
<Link to={routes.ROOT}>
<CloseIcon fontSize="inherit" />
</Link>
</IconButton>
}
>
<Typography variant="h2">
<pre>{name}</pre>
</Typography>
<Typography variant="h3">
<code>{message}</code>
</Typography>
<pre>{stack}</pre>
</Alert>
</Box>
)
}
return this.props.children
}
}
export default ErrorBoundary

View File

@ -0,0 +1 @@
export * from './ErrorBoundary'

View File

@ -15,6 +15,7 @@ import { AlertColor } from '@mui/material/Alert'
import { ShellContext } from 'contexts/ShellContext'
import { SettingsContext } from 'contexts/SettingsContext'
import { AlertOptions } from 'models/shell'
import { ErrorBoundary } from 'components/ErrorBoundary'
import { Drawer } from './Drawer'
import { UpgradeDialog } from './UpgradeDialog'
@ -170,7 +171,10 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
theme={theme}
userPeerId={userPeerId}
/>
<RouteContent isDrawerOpen={isDrawerOpen}>{children}</RouteContent>
<RouteContent isDrawerOpen={isDrawerOpen}>
<ErrorBoundary>{children}</ErrorBoundary>
</RouteContent>
</Box>
</ThemeProvider>
</ShellContext.Provider>

View File

@ -1,6 +1,5 @@
export enum routes {
ABOUT = '/about',
HOME = '/home',
INDEX_HTML = '/index.html',
PUBLIC_ROOM = '/public/:roomId',
ROOT = '/',