From cd908fa35861309c5c18e9217b99541fa766e035 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Mon, 4 Mar 2019 20:40:26 +0100 Subject: [PATCH 1/3] Created ErrorHandler component --- src/common/ErrorHandler.js | 37 ++++++++++++++++++++++++++ src/common/ErrorHandler.scss | 9 +++++++ src/common/services/provideServices.js | 3 +++ src/index.js | 10 ++++--- 4 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 src/common/ErrorHandler.js create mode 100644 src/common/ErrorHandler.scss diff --git a/src/common/ErrorHandler.js b/src/common/ErrorHandler.js new file mode 100644 index 00000000..ec069b2f --- /dev/null +++ b/src/common/ErrorHandler.js @@ -0,0 +1,37 @@ +import React from 'react'; +import * as PropTypes from 'prop-types'; +import './ErrorHandler.scss'; +import { Button } from 'reactstrap'; + +const ErrorHandler = ({ location }) => class ErrorHandler extends React.Component { + static propTypes = { + children: PropTypes.node.isRequired, + }; + + constructor(props) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError() { + // Update state so the next render will show the fallback UI. + return { hasError: true }; + } + + render() { + if (this.state.hasError) { + return ( +
+

Oops! This is awkward :S

+

It seems that something went wrong. Try refreshing the page or just click this button.

+
+ +
+ ); + } + + return this.props.children; + } +}; + +export default ErrorHandler; diff --git a/src/common/ErrorHandler.scss b/src/common/ErrorHandler.scss new file mode 100644 index 00000000..0c757135 --- /dev/null +++ b/src/common/ErrorHandler.scss @@ -0,0 +1,9 @@ +@import '../utils/mixins/vertical-align.scss'; + +.error-handler { + @include vertical-align(); + + padding: 20px; + text-align: center; + width: 100%; +} diff --git a/src/common/services/provideServices.js b/src/common/services/provideServices.js index eb7e0c9d..6fcc775b 100644 --- a/src/common/services/provideServices.js +++ b/src/common/services/provideServices.js @@ -3,6 +3,7 @@ import MainHeader from '../MainHeader'; import Home from '../Home'; import MenuLayout from '../MenuLayout'; import AsideMenu from '../AsideMenu'; +import ErrorHandler from '../ErrorHandler'; const provideServices = (bottle, connect, withRouter) => { bottle.constant('window', global.window); @@ -29,6 +30,8 @@ const provideServices = (bottle, connect, withRouter) => { bottle.decorator('MenuLayout', withRouter); bottle.serviceFactory('AsideMenu', AsideMenu, 'DeleteServerButton'); + + bottle.serviceFactory('ErrorHandler', ErrorHandler, 'window'); }; export default provideServices; diff --git a/src/index.js b/src/index.js index c875ae06..5b6446f9 100644 --- a/src/index.js +++ b/src/index.js @@ -16,14 +16,16 @@ import './index.scss'; // This overwrites icons used for leaflet maps, fixing some issues caused by webpack while processing the CSS fixLeafletIcons(); -const { App, ScrollToTop } = container; +const { App, ScrollToTop, ErrorHandler } = container; render( - - - + + + + + , document.getElementById('root') From ad9f0c00d039a464506c8922e0f6d2dccc91c7c2 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Mon, 4 Mar 2019 20:49:18 +0100 Subject: [PATCH 2/3] Created ErrorHandler test --- src/common/ErrorHandler.js | 1 - test/common/ErrorHandler.test.js | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 test/common/ErrorHandler.test.js diff --git a/src/common/ErrorHandler.js b/src/common/ErrorHandler.js index ec069b2f..fb641a79 100644 --- a/src/common/ErrorHandler.js +++ b/src/common/ErrorHandler.js @@ -14,7 +14,6 @@ const ErrorHandler = ({ location }) => class ErrorHandler extends React.Componen } static getDerivedStateFromError() { - // Update state so the next render will show the fallback UI. return { hasError: true }; } diff --git a/test/common/ErrorHandler.test.js b/test/common/ErrorHandler.test.js new file mode 100644 index 00000000..58325a65 --- /dev/null +++ b/test/common/ErrorHandler.test.js @@ -0,0 +1,36 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { Button } from 'reactstrap'; +import createErrorHandler from '../../src/common/ErrorHandler'; + +describe('', () => { + const window = { + location: { + reload: jest.fn(), + }, + }; + let wrapper; + + beforeEach(() => { + const ErrorHandler = createErrorHandler(window); + + wrapper = shallow(Foo} />); + }); + + afterEach(() => wrapper.unmount()); + + it('renders children when no error has occurred', () => { + expect(wrapper.text()).toEqual('Foo'); + expect(wrapper.find(Button)).toHaveLength(0); + }); + + it('renders error page when error has occurred', () => { + wrapper.setState({ hasError: true }); + + expect(wrapper.text()).toContain('Oops! This is awkward :S'); + expect(wrapper.text()).toContain( + 'It seems that something went wrong. Try refreshing the page or just click this button.' + ); + expect(wrapper.find(Button)).toHaveLength(1); + }); +}); From d75eff62e3972efa9c99ac36827b92f1a04104aa Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Mon, 4 Mar 2019 20:50:05 +0100 Subject: [PATCH 3/3] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8499cd14..012b23ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), * [#103](https://github.com/shlinkio/shlink-web-client/issues/103) Fixed visits page getting freezed when loading large amounts of visits. * [#111](https://github.com/shlinkio/shlink-web-client/issues/111) Fixed crash when trying to load a map modal with only one location. +* [#115](https://github.com/shlinkio/shlink-web-client/issues/115) Created `ErrorHandler` component which will prevent crashes in app to make it unusable. ## 2.0.1 - 2019-03-03