woocommerce/plugins/woocommerce-admin/client/error-boundary/index.tsx

119 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* External dependencies
*/
import { Component, ReactNode, ErrorInfo } from 'react';
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { captureException } from '@woocommerce/remote-logging';
import { bumpStat } from '@woocommerce/tracks';
/**
* Internal dependencies
*/
import './style.scss';
type ErrorBoundaryProps = {
children: ReactNode;
};
type ErrorBoundaryState = {
hasError: boolean;
error: Error | null;
errorInfo: ErrorInfo | null;
};
export class ErrorBoundary extends Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
constructor( props: ErrorBoundaryProps ) {
super( props );
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(
error: Error
): Partial< ErrorBoundaryState > {
return { hasError: true, error };
}
componentDidCatch( error: Error, errorInfo: ErrorInfo ) {
this.setState( { errorInfo } );
bumpStat( 'error', 'unhandled-js-error-during-render' );
// Limit the component stack to 10 calls so we don't send too much data.
const componentStack = errorInfo.componentStack
.trim()
.split( '\n' )
.slice( 0, 10 )
.map( ( line ) => line.trim() );
captureException( error, {
severity: 'critical',
extra: {
componentStack,
},
} );
}
handleRefresh = () => {
window.location.reload();
};
handleOpenSupport = () => {
window.open(
'https://wordpress.org/support/plugin/woocommerce/',
'_blank'
);
};
render() {
if ( this.state.hasError ) {
return (
<div className="woocommerce-global-error-boundary">
<h1 className="woocommerce-global-error-boundary__heading">
{ __( 'Oops, something went wrong', 'woocommerce' ) }
</h1>
<p className="woocommerce-global-error-boundary__subheading">
{ __(
'Were sorry for the inconvenience. Please try reloading the page, or you can get support from the community forums.',
'woocommerce'
) }
</p>
<div className="woocommerce-global-error-boundary__actions">
<Button
variant="secondary"
onClick={ this.handleOpenSupport }
>
{ __( 'Get Support', 'woocommerce' ) }
</Button>
<Button
variant="primary"
onClick={ this.handleRefresh }
>
{ __( 'Reload Page', 'woocommerce' ) }
</Button>
</div>
<details className="woocommerce-global-error-boundary__details">
<summary>
{ __( 'Click for error details', 'woocommerce' ) }
</summary>
<div className="woocommerce-global-error-boundary__details-content">
<strong className="woocommerce-global-error-boundary__error">
{ this.state.error &&
this.state.error.toString() }
</strong>
<p>
{ this.state.errorInfo &&
this.state.errorInfo.componentStack }
</p>
</div>
</details>
</div>
);
}
return this.props.children;
}
}