diff --git a/packages/react/package-lock.json b/packages/react/package-lock.json index e0a5d6601..205258f38 100644 --- a/packages/react/package-lock.json +++ b/packages/react/package-lock.json @@ -40,6 +40,7 @@ "oauth-open": "^1.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-error-boundary": "^4.0.11", "react-grid-layout": "^1.4.2", "react-helmet-async": "^1.3.0", "react-i18next": "^13.2.2", @@ -49,7 +50,8 @@ "react-virtuoso": "^4.6.1", "tailwind-merge": "^1.14.0", "tailwindcss-animate": "^1.0.7", - "use-seconds": "^1.7.0" + "use-seconds": "^1.7.0", + "usehooks-ts": "^2.9.1" }, "devDependencies": { "@iconify/json": "^2.2.126", @@ -7289,6 +7291,17 @@ "node": ">=6" } }, + "node_modules/react-error-boundary": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.11.tgz", + "integrity": "sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", @@ -9072,6 +9085,19 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/usehooks-ts": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz", + "integrity": "sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==", + "engines": { + "node": ">=16.15.0", + "npm": ">=8" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -14210,6 +14236,14 @@ } } }, + "react-error-boundary": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.11.tgz", + "integrity": "sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==", + "requires": { + "@babel/runtime": "^7.12.5" + } + }, "react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", @@ -15443,6 +15477,12 @@ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", "requires": {} }, + "usehooks-ts": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz", + "integrity": "sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/packages/react/package.json b/packages/react/package.json index ce33131f6..be782a4e1 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -44,6 +44,7 @@ "oauth-open": "^1.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-error-boundary": "^4.0.11", "react-grid-layout": "^1.4.2", "react-helmet-async": "^1.3.0", "react-i18next": "^13.2.2", @@ -53,7 +54,8 @@ "react-virtuoso": "^4.6.1", "tailwind-merge": "^1.14.0", "tailwindcss-animate": "^1.0.7", - "use-seconds": "^1.7.0" + "use-seconds": "^1.7.0", + "usehooks-ts": "^2.9.1" }, "devDependencies": { "@iconify/json": "^2.2.126", diff --git a/packages/react/src/components/common/ErrorFallback.tsx b/packages/react/src/components/common/ErrorFallback.tsx new file mode 100644 index 000000000..88fcacbb9 --- /dev/null +++ b/packages/react/src/components/common/ErrorFallback.tsx @@ -0,0 +1,62 @@ +import { FallbackProps } from "react-error-boundary"; +import { Trans, useTranslation } from "react-i18next"; +import { TwitterFeed } from "./TwitterFeed"; +import { useRouteError } from "react-router-dom"; +import { Button } from "@/shadcn/ui/button"; +import { useAuth } from "@/hooks/useAuth"; + +export function ErrorFallback(props?: FallbackProps | {}) { + const routeError = useRouteError() as Error | null; + const { t } = useTranslation(); + const { logout } = useAuth(); + + // @ts-ignore + const error = routeError ?? (props?.error as Error | null); + + return ( +
+
+ {error?.message}
+
+
+ {error?.stack}
+
+