diff --git a/package-lock.json b/package-lock.json index dd2c320..21405e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,6 +71,7 @@ "react-copy-to-clipboard": "^5.1.0", "react-datepicker": "^4.7.0", "react-dom": "^18.0.0", + "react-error-boundary": "^3.1.4", "react-file-drop": "^3.1.4", "react-helmet": "^6.1.0", "react-hook-form": "^7.30.0", @@ -62242,6 +62243,21 @@ "node": ">=0.10.0" } }, + "node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", @@ -118430,6 +118446,14 @@ } } }, + "react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "requires": { + "@babel/runtime": "^7.12.5" + } + }, "react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", diff --git a/package.json b/package.json index 612144f..a7e5946 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "react-copy-to-clipboard": "^5.1.0", "react-datepicker": "^4.7.0", "react-dom": "^18.0.0", + "react-error-boundary": "^3.1.4", "react-file-drop": "^3.1.4", "react-helmet": "^6.1.0", "react-hook-form": "^7.30.0", diff --git a/src/Components/ErrorBoundary/ErrorBoundary.tsx b/src/Components/ErrorBoundary/ErrorBoundary.tsx index 7fcfef3..6ddc18b 100644 --- a/src/Components/ErrorBoundary/ErrorBoundary.tsx +++ b/src/Components/ErrorBoundary/ErrorBoundary.tsx @@ -1,5 +1,5 @@ import React, { Component, ErrorInfo, ReactNode } from "react"; -import ErrorMessage from "../ErrorMessage/ErrorMessage"; +import ErrorMessage from "../Errors/ErrorMessage/ErrorMessage"; interface Props { place?: string diff --git a/src/Components/Errors/ErrorCard/ErrorCard.stories.tsx b/src/Components/Errors/ErrorCard/ErrorCard.stories.tsx new file mode 100644 index 0000000..a73c3d2 --- /dev/null +++ b/src/Components/Errors/ErrorCard/ErrorCard.stories.tsx @@ -0,0 +1,21 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import ErrorCard from './ErrorCard'; + +export default { + title: 'Shared/ErrorCard', + component: ErrorCard, + +} as ComponentMeta; + +const Template: ComponentStory = (args) => ; + +export const Default = Template.bind({}); +Default.args = { + error: { + name: "Error Name", + message: "Error Message", + } +} + + diff --git a/src/Components/Errors/ErrorCard/ErrorCard.tsx b/src/Components/Errors/ErrorCard/ErrorCard.tsx new file mode 100644 index 0000000..d9ee8e6 --- /dev/null +++ b/src/Components/Errors/ErrorCard/ErrorCard.tsx @@ -0,0 +1,40 @@ +import { useToggle } from "@react-hookz/web"; +import { FallbackProps } from "react-error-boundary"; +import { RiErrorWarningFill } from "react-icons/ri"; +import Button from "src/Components/Button/Button"; +import Card from "src/Components/Card/Card"; + + + +export default function ErrorCard({ error, resetErrorBoundary }: FallbackProps) { + + const [showDetails, toggleDetails] = useToggle(false) + + + + return ( + +
+
+

Ooops...
Looks like something unexpected went wrong, please check your internet connection & try again.

+
+ + +
+ +
+ + + {showDetails && +
+

{error.name}

+

{error.message}

+

{error.stack}

+
+ } +
+
+
+ + ) +} diff --git a/src/Components/ErrorMessage/ErrorMessage.stories.tsx b/src/Components/Errors/ErrorMessage/ErrorMessage.stories.tsx similarity index 100% rename from src/Components/ErrorMessage/ErrorMessage.stories.tsx rename to src/Components/Errors/ErrorMessage/ErrorMessage.stories.tsx diff --git a/src/Components/ErrorMessage/ErrorMessage.tsx b/src/Components/Errors/ErrorMessage/ErrorMessage.tsx similarity index 100% rename from src/Components/ErrorMessage/ErrorMessage.tsx rename to src/Components/Errors/ErrorMessage/ErrorMessage.tsx diff --git a/src/Components/Errors/ErrorPage/ErrorPage.tsx b/src/Components/Errors/ErrorPage/ErrorPage.tsx new file mode 100644 index 0000000..5357f4c --- /dev/null +++ b/src/Components/Errors/ErrorPage/ErrorPage.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import { Helmet } from 'react-helmet' +import { FallbackProps } from 'react-error-boundary' +import ErrorCard from '../ErrorCard/ErrorCard' + + +export default function ErrorPage({ error, resetErrorBoundary }: FallbackProps) { + return ( +
+ + {`Something went wrong...`} + +
+ +
+
+ ) +} diff --git a/src/features/Auth/pages/LoginPage/LoginPage.tsx b/src/features/Auth/pages/LoginPage/LoginPage.tsx index 2916293..afdb7cb 100644 --- a/src/features/Auth/pages/LoginPage/LoginPage.tsx +++ b/src/features/Auth/pages/LoginPage/LoginPage.tsx @@ -10,6 +10,7 @@ import Button from "src/Components/Button/Button"; import { FiCopy } from "react-icons/fi"; import useCopyToClipboard from "src/utils/hooks/useCopyToClipboard"; import { getPropertyFromUnknown, trimText, } from "src/utils/helperFunctions"; +import { useErrorHandler } from 'react-error-boundary'; @@ -33,7 +34,7 @@ export const useLnurlQuery = () => { const doFetch = async () => { const res = await fetchLnurlAuth(); if (!res?.encoded) - setError(true) + setError(new Error("Response doesn't contain data")) else { setLoading(false); setData({ @@ -43,7 +44,7 @@ export const useLnurlQuery = () => { timeOut = setTimeout(doFetch, 1000 * 60 * 2) } } - doFetch() + doFetch().catch(err => setError(err)); return () => clearTimeout(timeOut) }, []) @@ -64,8 +65,9 @@ export default function LoginPage() { const canFetchIsLogged = useRef(true) const { loadingLnurl, data: { lnurl, session_token }, error } = useLnurlQuery(); - const clipboard = useCopyToClipboard() + useErrorHandler(error) + const clipboard = useCopyToClipboard() useEffect(() => { @@ -198,6 +200,8 @@ export default function LoginPage() { ; + + return ( <> diff --git a/src/features/Projects/pages/CategoryPage/CategoryPage.tsx b/src/features/Projects/pages/CategoryPage/CategoryPage.tsx index da6c204..9876d15 100644 --- a/src/features/Projects/pages/CategoryPage/CategoryPage.tsx +++ b/src/features/Projects/pages/CategoryPage/CategoryPage.tsx @@ -1,5 +1,5 @@ import { useParams, Navigate } from 'react-router-dom' -import ErrorMessage from 'src/Components/ErrorMessage/ErrorMessage'; +import ErrorMessage from 'src/Components/Errors/ErrorMessage/ErrorMessage'; import { useCategoryPageQuery } from 'src/graphql'; import HeaderImage from './HeaderImage/HeaderImage'; import ProjectsGrid from './ProjectsGrid/ProjectsGrid'; diff --git a/src/features/Projects/pages/HottestPage/HottestPage.tsx b/src/features/Projects/pages/HottestPage/HottestPage.tsx index f265f73..9441cf5 100644 --- a/src/features/Projects/pages/HottestPage/HottestPage.tsx +++ b/src/features/Projects/pages/HottestPage/HottestPage.tsx @@ -1,6 +1,6 @@ import ASSETS from 'src/assets'; -import ErrorMessage from 'src/Components/ErrorMessage/ErrorMessage'; +import ErrorMessage from 'src/Components/Errors/ErrorMessage/ErrorMessage'; import HeaderImage from 'src/features/Projects/pages/CategoryPage/HeaderImage/HeaderImage'; import ProjectsGrid from 'src/features/Projects/pages/CategoryPage/ProjectsGrid/ProjectsGrid'; import { Helmet } from "react-helmet"; diff --git a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx index 9e8de59..6d8b40b 100644 --- a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx +++ b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx @@ -13,7 +13,7 @@ import { Wallet_Service } from 'src/services' import { useProjectDetailsQuery } from 'src/graphql'; import Lightbox from 'src/Components/Lightbox/Lightbox' import linkifyHtml from 'linkify-html'; -import ErrorMessage from 'src/Components/ErrorMessage/ErrorMessage'; +import ErrorMessage from 'src/Components/Errors/ErrorMessage/ErrorMessage'; import { setVoteAmount } from 'src/redux/features/vote.slice'; import { numberFormatter } from 'src/utils/helperFunctions'; import { MEDIA_QUERIES } from 'src/utils/theme'; diff --git a/src/utils/Wrapper.tsx b/src/utils/Wrapper.tsx index 53ff00e..fe23740 100644 --- a/src/utils/Wrapper.tsx +++ b/src/utils/Wrapper.tsx @@ -13,8 +13,9 @@ import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import 'react-loading-skeleton/dist/skeleton.css' import THEME from './theme'; -import ErrorBoundary from 'src/Components/ErrorBoundary/ErrorBoundary'; import { NotificationsService } from 'src/services'; +import ErrorPage from 'src/Components/Errors/ErrorPage/ErrorPage'; +import { ErrorBoundary } from 'react-error-boundary'; THEME.injectStyles(); let basename = '/'; @@ -45,7 +46,9 @@ export default function Wrapper(props: any) { return ( <> - + diff --git a/src/utils/routing/layouts/NavbarLayout.tsx b/src/utils/routing/layouts/NavbarLayout.tsx index cc63068..1588446 100644 --- a/src/utils/routing/layouts/NavbarLayout.tsx +++ b/src/utils/routing/layouts/NavbarLayout.tsx @@ -1,9 +1,15 @@ +import { ErrorBoundary } from 'react-error-boundary'; import { Outlet, } from 'react-router-dom'; +import ErrorPage from 'src/Components/Errors/ErrorPage/ErrorPage'; import Navbar from "src/Components/Navbar/Navbar"; export const NavbarLayout = () => { return <> - + + + };