// Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { ReactNode, ErrorInfo } from 'react'; import React, { Component, useCallback } from 'react'; import * as log from '../../../logging/log'; import * as Errors from '../../../types/errors'; import { ToastType } from '../../../types/Toast'; type ErrorBoundaryProps = Readonly<{ onError: (error: unknown, info: ErrorInfo) => void; fallback: (error: unknown) => ReactNode; children: ReactNode; }>; type ErrorBoundaryState = { caught?: { error: unknown }; }; class ErrorBoundary extends Component { // eslint-disable-next-line react/state-in-constructor override state: ErrorBoundaryState = {}; static getDerivedStateFromError(error: unknown) { return { caught: { error } }; } override componentDidCatch(error: unknown, info: ErrorInfo) { this.props.onError(error, info); } override render() { if (this.state.caught != null) { return this.props.fallback(this.state.caught.error); } return this.props.children; } } export type FunErrorBoundaryProps = Readonly<{ children: ReactNode; }>; export function FunErrorBoundary(props: FunErrorBoundaryProps): JSX.Element { const fallback = useCallback(() => { return
; }, []); const handleError = useCallback((error: unknown, info: ErrorInfo) => { log.error( 'ErrorBoundary: Caught error', Errors.toLogFormat(error), info.componentStack ); window.reduxActions?.toast.showToast({ toastType: ToastType.Error }); }, []); return ( {props.children} ); }