diff --git a/package.json b/package.json index 184153f0e..d90340b7f 100644 --- a/package.json +++ b/package.json @@ -63,9 +63,8 @@ "@reach/rect": "^0.18.0", "@reach/tabs": "^0.18.0", "@reduxjs/toolkit": "^1.8.1", - "@sentry/browser": "^7.37.2", - "@sentry/react": "^7.37.2", - "@sentry/tracing": "^7.37.2", + "@sentry/browser": "^7.74.1", + "@sentry/react": "^7.74.1", "@tabler/icons": "^2.0.0", "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/forms": "^0.5.3", @@ -134,6 +133,7 @@ "react-color": "^2.19.3", "react-datepicker": "^4.8.0", "react-dom": "^18.0.0", + "react-error-boundary": "^4.0.11", "react-helmet": "^6.1.0", "react-hot-toast": "^2.4.0", "react-hotkeys": "^1.1.4", diff --git a/src/components/error-boundary.tsx b/src/components/error-boundary.tsx deleted file mode 100644 index b25ca2aae..000000000 --- a/src/components/error-boundary.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import React from 'react'; -import { FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; - -import { getSoapboxConfig } from 'soapbox/actions/soapbox'; -import * as BuildConfig from 'soapbox/build-config'; -import { HStack, Text, Stack } from 'soapbox/components/ui'; -import { captureException } from 'soapbox/monitoring'; -import KVStore from 'soapbox/storage/kv-store'; -import sourceCode from 'soapbox/utils/code'; -import { unregisterSW } from 'soapbox/utils/sw'; - -import SiteLogo from './site-logo'; - -import type { RootState } from 'soapbox/store'; - -interface Props extends ReturnType { - children: React.ReactNode; -} - -type State = { - hasError: boolean; - error: any; - componentStack: any; - browser?: Bowser.Parser.Parser; -} - -class ErrorBoundary extends React.PureComponent { - - state: State = { - hasError: false, - error: undefined, - componentStack: undefined, - browser: undefined, - }; - - textarea: HTMLTextAreaElement | null = null; - - componentDidCatch(error: any, info: any): void { - captureException(error, { - tags: { - // Allow page crashes to be easily searched in Sentry. - ErrorBoundary: 'yes', - }, - }); - - this.setState({ - hasError: true, - error, - componentStack: info && info.componentStack, - }); - - import('bowser') - .then(({ default: Bowser }) => { - this.setState({ - browser: Bowser.getParser(window.navigator.userAgent), - }); - }) - .catch(() => {}); - } - - setTextareaRef: React.RefCallback = c => { - this.textarea = c; - }; - - handleCopy: React.MouseEventHandler = () => { - if (!this.textarea) return; - - this.textarea.select(); - this.textarea.setSelectionRange(0, 99999); - - document.execCommand('copy'); - }; - - getErrorText = (): string => { - const { error, componentStack } = this.state; - return error + componentStack; - }; - - clearCookies: React.MouseEventHandler = (e) => { - localStorage.clear(); - sessionStorage.clear(); - KVStore.clear(); - - if ('serviceWorker' in navigator) { - e.preventDefault(); - unregisterSW().then(goHome).catch(goHome); - } - }; - - render() { - const { browser, hasError } = this.state; - const { children, links } = this.props; - - if (!hasError) { - return children; - } - - const isProduction = BuildConfig.NODE_ENV === 'production'; - - const errorText = this.getErrorText(); - - return ( -
-
-
- - - -
- -
-
-

- -

-

- - - - ), - }} - /> -

- - - {sourceCode.displayName}: - - {' '}{sourceCode.version} - - - -
- - {!isProduction && ( -
- {errorText && ( -