import React, { Component, StatelessComponent, ReactNode, ErrorInfo } from "react"; import * as Sentry from "@sentry/browser"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBomb } from "@fortawesome/free-solid-svg-icons/faBomb"; interface InternalErrorProps { message: ReactNode; secondsLeft: number; progressLeft: number; } const InternalError: StatelessComponent = props => (

Internal error

{props.message}

This page will auto refresh in {props.secondsLeft}s

); interface ErrorBoundaryProps { children: React.ReactNode; } interface ErrorBoundaryState { cachedError: Error | null; reloadSeconds: number; } class ErrorBoundary extends Component { timer: ReturnType | null; state: Readonly = { cachedError: null, reloadSeconds: 60 }; constructor(props: ErrorBoundaryProps) { super(props); this.timer = null; } reloadApp = () => { if (this.state.reloadSeconds <= 1) { window.location.reload(); } else { this.setState({ reloadSeconds: this.state.reloadSeconds - 1 }); } }; componentDidCatch(error: Error | null, errorInfo: ErrorInfo) { this.setState({ cachedError: error }); Sentry.withScope(scope => { scope.setExtras(errorInfo); Sentry.captureException(error); }); // reload after 60s, this is to fix wall monitors automatically // but only if the timer isn't set yet if (this.timer === null) { this.timer = setInterval(this.reloadApp, 1000); } } render() { if (this.state.cachedError !== null) { return ( ); } return this.props.children; } } export { ErrorBoundary };