lbry-desktop/ui/component/errorBoundary/view.jsx

128 lines
3.9 KiB
React
Raw Normal View History

// @flow
2019-08-13 07:35:13 +02:00
import type { Node } from 'react';
2020-01-03 20:45:34 +01:00
import React from 'react';
import { withRouter } from 'react-router';
import analytics from 'analytics';
2020-02-05 15:45:20 +01:00
import Native from 'native';
import { Lbry } from 'lbry-redux';
2021-06-11 08:06:29 +02:00
const Button = React.lazy(() => import('component/button' /* webpackChunkName: "button" */));
const I18nMessage = React.lazy(() => import('component/i18nMessage' /* webpackChunkName: "i18nMessage" */));
const Yrbl = React.lazy(() => import('component/yrbl' /* webpackChunkName: "yrbl" */));
type Props = {
2019-08-13 07:35:13 +02:00
children: Node,
history: {
2021-06-11 08:06:29 +02:00
replace: (string) => void,
},
};
type State = {
hasError: boolean,
2020-02-14 19:58:09 +01:00
sentryEventId: ?string,
desktopErrorReported: boolean,
};
class ErrorBoundary extends React.Component<Props, State> {
constructor() {
super();
2020-02-14 19:58:09 +01:00
this.state = { hasError: false, sentryEventId: undefined, desktopErrorReported: false };
(this: any).refresh = this.refresh.bind(this);
}
static getDerivedStateFromError() {
return { hasError: true };
}
2020-02-05 04:46:00 +01:00
componentDidCatch(error, errorInfo) {
2020-02-05 15:45:20 +01:00
// @if TARGET='web'
2021-06-11 08:06:29 +02:00
analytics.sentryError(error, errorInfo).then((sentryEventId) => {
2020-02-14 19:58:09 +01:00
this.setState({ sentryEventId });
});
2020-02-05 15:45:20 +01:00
// @endif
2020-02-14 19:58:09 +01:00
2020-02-05 15:45:20 +01:00
// @if TARGET='app'
2020-02-14 19:58:09 +01:00
let errorMessage = 'Uncaught error\n';
2020-02-05 15:45:20 +01:00
Native.getAppVersionInfo().then(({ localVersion }) => {
Lbry.version().then(({ lbrynet_version: sdkVersion }) => {
errorMessage += `app version: ${localVersion}\n`;
errorMessage += `sdk version: ${sdkVersion}\n`;
errorMessage += `page: ${window.location.href.split('.html')[1]}\n`;
errorMessage += `${error.stack}`;
2021-06-11 08:06:29 +02:00
analytics.error(errorMessage).then((isSharingData) => {
2020-02-14 19:58:09 +01:00
this.setState({ desktopErrorReported: isSharingData });
});
2020-02-05 15:45:20 +01:00
});
2019-05-20 18:02:22 +02:00
});
2020-02-05 15:45:20 +01:00
// @endif
2019-05-20 18:02:22 +02:00
}
refresh() {
const { history } = this.props;
2020-02-05 04:46:00 +01:00
// use history.replace instead of history.push so the user can't click back to the errored page
history.replace('');
this.setState({ hasError: false });
}
render() {
2020-02-05 15:45:20 +01:00
const { hasError } = this.state;
2020-02-14 19:58:09 +01:00
const { sentryEventId, desktopErrorReported } = this.state;
const errorWasReported = IS_WEB ? sentryEventId !== null : desktopErrorReported;
2020-02-05 04:46:00 +01:00
if (hasError) {
return (
<div className="main main--full-width main--empty">
2021-06-11 08:06:29 +02:00
<React.Suspense fallback={null}>
<Yrbl
type="sad"
title={__('Aw shucks!')}
subtitle={
<I18nMessage
tokens={{
refreshing_the_app_link: (
<Button
button="link"
className="load-screen__button"
label={__('refreshing the app')}
onClick={this.refresh}
/>
),
}}
>
There was an error. Try %refreshing_the_app_link% to fix it. If that doesn't work, try pressing
Ctrl+R/Cmd+R.
</I18nMessage>
}
/>
</React.Suspense>
2020-02-14 19:58:09 +01:00
{!errorWasReported && (
<div className="error__wrapper">
<span className="error__text">
2020-02-05 04:46:00 +01:00
{__('You are not currently sharing diagnostic data so this error was not reported.')}
</span>
</div>
)}
2020-02-14 19:58:09 +01:00
{errorWasReported && (
<div className="error__wrapper">
2020-02-14 19:58:09 +01:00
{/* @if TARGET='web' */}
<span className="error__text">{__('Error ID: %sentryEventId%', { sentryEventId })}</span>
2020-02-14 19:58:09 +01:00
{/* @endif */}
{/* @if TARGET='app' */}
<span className="error__text">{__('This error was reported and will be fixed.')}</span>
2020-02-14 19:58:09 +01:00
{/* @endif */}
2020-02-05 04:46:00 +01:00
</div>
2020-02-14 19:58:09 +01:00
)}
</div>
);
}
return this.props.children;
}
}
export default withRouter(ErrorBoundary);