diff --git a/web/package.json b/web/package.json index 0e0f3c17c..c12dbc666 100644 --- a/web/package.json +++ b/web/package.json @@ -106,7 +106,7 @@ "react": "^18.3.1", "react-chartjs-2": "^4.3.1", "react-dom": "^18.3.1", - "react-error-boundary": "^3.1.4", + "react-error-boundary": "^4.1.2", "react-identicons": "^1.2.5", "react-is": "^18.3.1", "react-loading-skeleton": "^3.5.0", diff --git a/web/src/app.tsx b/web/src/app.tsx index a961e70ca..23a158b6c 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -1,9 +1,11 @@ import React, { lazy, Suspense } from "react"; +import { ErrorBoundary } from "react-error-boundary"; import { Route } from "react-router-dom"; import "react-loading-skeleton/dist/skeleton.css"; import "react-toastify/dist/ReactToastify.css"; + import AtlasProvider from "context/AtlasProvider"; import GraphqlBatcherProvider from "context/GraphqlBatcher"; import IsListProvider from "context/IsListProvider"; @@ -22,84 +24,87 @@ import Web3Provider from "context/Web3Provider"; import Loader from "components/Loader"; import Layout from "layout/index"; +import ErrorFallback from "./components/ErrorFallback"; import { SentryRoutes } from "./utils/sentry"; const App: React.FC = () => { return ( - - - - - - - - }> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯} /> - - - - - - - - + + + + + + + + + }> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯} /> + + + + + + + + + ); }; diff --git a/web/src/components/ErrorFallback.tsx b/web/src/components/ErrorFallback.tsx new file mode 100644 index 000000000..6b9fef67b --- /dev/null +++ b/web/src/components/ErrorFallback.tsx @@ -0,0 +1,129 @@ +import React from "react"; +import styled, { css } from "styled-components"; + +import { FallbackProps } from "react-error-boundary"; + +import { Button } from "@kleros/ui-components-library"; + +import ErrorIcon from "svgs/icons/warning-outline.svg"; + +import { landscapeStyle } from "styles/landscapeStyle"; +import { responsiveSize } from "styles/responsiveSize"; + +import HeroImage from "./HeroImage"; + +const Container = styled.div` + width: 100%; + height: 100vh; + background-color: ${({ theme }) => theme.lightBackground}; + padding: ${responsiveSize(32, 80)} ${responsiveSize(24, 136)} ${responsiveSize(76, 96)}; + max-width: 1780px; + margin: 0 auto; +`; + +const ErrorContainer = styled.div` + display: flex; + width: 100%; + gap: 48px 16px; + flex-direction: column; + justify-content: center; + align-items: center; + ${landscapeStyle( + () => css` + flex-direction: row; + justify-content: space-between; + ` + )} +`; + +const InfoWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 32px; + align-items: center; + flex: 1; + ${landscapeStyle( + () => css` + align-items: start; + ` + )} +`; + +const textCss = css` + margin: 0; + text-align: center; + white-space: pre-line; + + ${landscapeStyle( + () => css` + text-align: left; + ` + )} +`; + +const Header = styled.h1` + ${textCss} +`; + +const Subtitle = styled.h3` + ${textCss} + max-width: 735px; +`; + +const HeaderIconContainer = styled.div` + svg { + width: 64px; + height: 64px; + path { + fill: ${({ theme }) => theme.error}; + } + } +`; + +const ButtonsContainer = styled.div` + display: flex; + gap: 16px; +`; + +const IconContainer = styled.div` + svg { + width: 250px; + height: 250px; + path { + fill: ${({ theme }) => theme.whiteBackground}; + } + } +`; + +const ErrorFallback: React.FC = ({ error, resetErrorBoundary }) => { + // eslint-disable-next-line no-console + console.log("Error:", { error }); + + return ( + <> + + + + + + + +
Ooops, Something went wrong in Athens!
+ Please reload the page or contact us if the issue is not resolved. + +