import React, { ErrorInfo, useRef, useState } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { FormattedMessage } from 'react-intl'; import { NODE_ENV } from 'soapbox/build-config'; import { HStack, Text, Stack } from 'soapbox/components/ui'; import { useSoapboxConfig } from 'soapbox/hooks'; import { captureSentryException } from 'soapbox/sentry'; import KVStore from 'soapbox/storage/kv-store'; import sourceCode from 'soapbox/utils/code'; import { unregisterSW } from 'soapbox/utils/sw'; import SiteLogo from './site-logo'; interface ISiteErrorBoundary { children: React.ReactNode; } /** Application-level error boundary. Fills the whole screen. */ const SiteErrorBoundary: React.FC = ({ children }) => { const { links } = useSoapboxConfig(); const textarea = useRef(null); const [error, setError] = useState(); const [componentStack, setComponentStack] = useState(); const [browser, setBrowser] = useState(); const isProduction = NODE_ENV === 'production'; const errorText = error + componentStack; const clearCookies: React.MouseEventHandler = (e) => { localStorage.clear(); sessionStorage.clear(); KVStore.clear(); if ('serviceWorker' in navigator) { e.preventDefault(); unregisterSW().then(goHome).catch(goHome); } }; const handleCopy: React.MouseEventHandler = () => { if (!textarea.current) return; textarea.current.select(); textarea.current.setSelectionRange(0, 99999); document.execCommand('copy'); }; function handleError(error: Error, info: ErrorInfo) { setError(error); setComponentStack(info.componentStack); captureSentryException(error, { tags: { // Allow page crashes to be easily searched in Sentry. ErrorBoundary: 'yes', }, }); import('bowser') .then(({ default: Bowser }) => setBrowser(Bowser.getParser(window.navigator.userAgent))) .catch(() => {}); } function goHome() { location.href = '/'; } const fallback = (

), }} />

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