Add error boundary for tools

This commit is contained in:
Kevin Kandlbinder 2022-05-03 14:39:26 +02:00
parent c344942d40
commit e0edd29436
6 changed files with 100 additions and 8 deletions

View file

@ -1,6 +1,6 @@
{
"name": "kevins-data-toolbox",
"version": "2.0.0",
"version": "2.1.0",
"private": true,
"dependencies": {
"@loadable/component": "^5.15.0",
@ -9,6 +9,7 @@
"@testing-library/user-event": "^14.1.1",
"@types/jest": "^27.4.1",
"@types/loadable__component": "^5.13.4",
"@types/lodash": "^4.14.182",
"@types/node": "^17.0.31",
"@types/react": "^18.0.8",
"@types/react-dom": "^18.0.3",
@ -17,6 +18,7 @@
"i18next": "^21.6.16",
"i18next-browser-languagedetector": "^6.1.0",
"i18next-http-backend": "^1.2.1",
"lodash": "^4.17.21",
"lucide-react": "^0.35.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",

View file

@ -47,6 +47,12 @@
"system": {
"notfound": "Seite nicht gefunden",
"language": "Sprache",
"imprint": "Impressum"
"imprint": "Impressum",
"errors": {
"toolException": {
"title": "Ein fatales Problem ist aufgetreten.",
"description": "Im Werkzeug ist ein fatales Problem aufgetreten und die Aufgabe konnte nicht abgeschlossen werden. Bitte erneut versuchen."
}
}
}
}

View file

@ -47,6 +47,12 @@
"system": {
"notfound": "Page Not Found",
"language": "Language",
"imprint": "Imprint"
"imprint": "Imprint",
"errors": {
"toolException": {
"title": "The tool encountered a fatal error.",
"description": "The tool encountered a fatal error and was unable to complete its task. Please retry."
}
}
}
}

View file

@ -11,7 +11,7 @@ $layoutNavigationHeight: 50px;
max-width: $layoutWidth;
padding: 0 $layoutPadding;
margin: 0 auto;
width: 100%;
}
@mixin boxStyle {
@ -30,7 +30,33 @@ $layoutNavigationHeight: 50px;
}
}
@mixin button {
@include boxStyle;
background: rgba(white, .75);
color: $colorAccent;
border: none;
border-radius: 10px;
padding: 10px;
margin: 0;
cursor: pointer;
font: inherit;
transition: all .2s ease-in-out;
@media(prefers-color-scheme: dark) {
color: white;
}
&:hover {
background: white;
color: $colorAccent;
}
}
@mixin formStyles() {
button {
@include button;
}
input[type=text], input[type=password], textarea, input[type=number] {
@include boxStyle;

View file

@ -1,25 +1,72 @@
import React from "react";
import React, { useState } from "react";
import { useParams } from "react-router";
import _ from "lodash";
import prerenderedLoadable from "../helpers/prerenderedLoadable";
import NotFoundPage from "../pages/NotFound";
import * as styles from "../App.module.scss";
import { Trans } from "react-i18next";
import BoxMessage from "../components/BoxMessage";
import { AlertOctagon } from "lucide-react";
const HomePage = prerenderedLoadable(() => import('../pages/Home'));
const RotTool = prerenderedLoadable(() => import('./cyphers_and_cryptography/rot/RotTool'));
const Base64Tool = prerenderedLoadable(() => import('./cyphers_and_cryptography/base64/Base64Tool'));
type ErrorBoundaryProps = {
resetFunction: () => void
}
class ToolErrorBoundary extends React.Component<React.PropsWithChildren<ErrorBoundaryProps>, {hasError: boolean}> {
constructor(props: React.PropsWithChildren<ErrorBoundaryProps>) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error) {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <>
<div className={styles.layoutBox}>
<BoxMessage icon={<AlertOctagon/>}>
<b><Trans i18nKey={"system.errors.toolException.title"}>The tool encountered a fatal error.</Trans></b>
<p>
<Trans i18nKey={"system.errors.toolException.description"} />
</p>
<button onClick={() => this.props.resetFunction()}>Reset Tool and Retry</button>
</BoxMessage>
</div>
</>;
}
return this.props.children;
}
}
const ToolLoader = () => {
const {tool} = useParams();
const [key, setKey] = useState(_.uniqueId("toolLoader_"))
const forceReset = () => {
setKey(_.uniqueId("toolLoader_"))
}
switch(tool) {
case "test":
return <HomePage/>;
return <ToolErrorBoundary resetFunction={forceReset} key={key}><HomePage/></ToolErrorBoundary>;
case "rot":
return <RotTool/>;
return <ToolErrorBoundary resetFunction={forceReset} key={key}><RotTool/></ToolErrorBoundary>;
case "base64":
return <Base64Tool/>;
return <ToolErrorBoundary resetFunction={forceReset} key={key}><Base64Tool/></ToolErrorBoundary>;
default:
return <NotFoundPage/>;

View file

@ -1762,6 +1762,11 @@
dependencies:
"@types/react" "*"
"@types/lodash@^4.14.182":
version "4.14.182"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==
"@types/minimatch@*":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"