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'; const goHome = () => location.href = '/'; const mapStateToProps = (state: RootState) => { const { links, logo } = getSoapboxConfig(state); return { siteTitle: state.instance.title, logo, links, }; }; 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(/* webpackChunkName: "error" */'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 && (