diff --git a/src/components/crashmessage/crashmessage.jsx b/src/components/crashmessage/crashmessage.jsx new file mode 100644 index 000000000..d66a3c610 --- /dev/null +++ b/src/components/crashmessage/crashmessage.jsx @@ -0,0 +1,38 @@ +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); +const FormattedMessage = require('react-intl').FormattedMessage; + +const Button = require('../forms/button.jsx'); + +require('./crashmessage.scss'); + +const CrashMessage = props => ( +
+ +
+

+ +

+

+ +

+ +
+
+); + +CrashMessage.propTypes = { + className: PropTypes.string, + onBack: PropTypes.func +}; + +module.exports = CrashMessage; diff --git a/src/components/crashmessage/crashmessage.scss b/src/components/crashmessage/crashmessage.scss new file mode 100644 index 000000000..5466d61aa --- /dev/null +++ b/src/components/crashmessage/crashmessage.scss @@ -0,0 +1,22 @@ +.crash-container { + @import "../../colors"; + @import "../../frameless"; + + margin: 3rem auto; + + border: 1px solid $ui-border; + border-radius: 10px; + background-color: $background-color; + width: 60%; + overflow: hidden; + text-align: center; + + img { + width: 100%; + } + + .crash-message { + margin: 2rem; + } + +} diff --git a/src/components/errorboundary/errorboundary.jsx b/src/components/errorboundary/errorboundary.jsx new file mode 100644 index 000000000..d678e995d --- /dev/null +++ b/src/components/errorboundary/errorboundary.jsx @@ -0,0 +1,36 @@ +const PropTypes = require('prop-types'); +const React = require('react'); + +const CrashMessageComponent = require('../crashmessage/crashmessage.jsx'); +import log from '../../lib/log.js'; + +class ErrorBoundary extends React.Component { + constructor (props) { + super(props); + this.state = { + hasError: false + }; + } + + componentDidCatch (error, info) { + // Display fallback UI + this.setState({hasError: true}); + log.error(`Unhandled Error: ${error}, info: ${info}`); + } + + handleBack () { + window.history.back(); + } + + render () { + if (this.state.hasError) { + return ; + } + return this.props.children; + } +} +ErrorBoundary.propTypes = { + children: PropTypes.node +}; + +module.exports = ErrorBoundary; diff --git a/src/components/page/www/page.jsx b/src/components/page/www/page.jsx index d286deb2b..b66d7ae97 100644 --- a/src/components/page/www/page.jsx +++ b/src/components/page/www/page.jsx @@ -4,24 +4,27 @@ const React = require('react'); const Navigation = require('../../navigation/www/navigation.jsx'); const Footer = require('../../footer/www/footer.jsx'); +const ErrorBoundary = require('../../errorboundary/errorboundary.jsx'); const Page = props => ( -
- + ); Page.propTypes = { diff --git a/src/l10n.json b/src/l10n.json index a717e23ad..fe4b152ce 100644 --- a/src/l10n.json +++ b/src/l10n.json @@ -2,6 +2,7 @@ "general.accountSettings": "Account settings", "general.about": "About", "general.aboutScratch": "About Scratch", + "general.back": "Back", "general.birthMonth": "Birth Month", "general.birthYear": "Birth Year", "general.donate": "Donate", @@ -73,6 +74,7 @@ "general.tips": "Tips", "general.tipsWindow": "Tips Window", "general.termsOfUse": "Terms of Use", + "general.unhandledError": "We are so sorry, but it looks like Scratch has crashed. This bug has been automatically reported to the Scratch Team.", "general.username": "Username", "general.validationEmail": "Please enter a valid email address", "general.validationEmailMatch": "The emails do not match", diff --git a/static/images/unhandled.png b/static/images/unhandled.png new file mode 100644 index 000000000..ae28ed639 Binary files /dev/null and b/static/images/unhandled.png differ