diff --git a/frontends/mit-learn/src/pages/ErrorPage/ForbiddenPage.test.tsx b/frontends/main/src/app-pages/ErrorPage/ForbiddenPage.test.tsx
similarity index 57%
rename from frontends/mit-learn/src/pages/ErrorPage/ForbiddenPage.test.tsx
rename to frontends/main/src/app-pages/ErrorPage/ForbiddenPage.test.tsx
index f8c0383b7c..5ba855929f 100644
--- a/frontends/mit-learn/src/pages/ErrorPage/ForbiddenPage.test.tsx
+++ b/frontends/main/src/app-pages/ErrorPage/ForbiddenPage.test.tsx
@@ -1,7 +1,6 @@
import React from "react"
-import { waitFor } from "@testing-library/react"
import { renderWithProviders, screen } from "../../test-utils"
-import { HOME, login } from "@/common/urls"
+import { HOME } from "@/common/urls"
import ForbiddenPage from "./ForbiddenPage"
import { setMockResponse, urls } from "api/test-utils"
import { Permissions } from "@/common/permissions"
@@ -25,19 +24,6 @@ afterAll(() => {
window.location = oldWindowLocation
})
-test("The ForbiddenPage loads with meta", async () => {
- setMockResponse.get(urls.userMe.get(), {
- [Permissions.Authenticated]: true,
- })
- renderWithProviders()
- await waitFor(() => {
- expect(document.title).toBe("Not Allowed | MIT Learn")
- })
-
- const meta = document.head.querySelector('meta[name="robots"]')
- expect(meta).toHaveProperty("content", "noindex,noarchive")
-})
-
test("The ForbiddenPage loads with Correct Title", () => {
setMockResponse.get(urls.userMe.get(), {
[Permissions.Authenticated]: true,
@@ -54,17 +40,3 @@ test("The ForbiddenPage loads with a link that directs to HomePage", () => {
const homeLink = screen.getByRole("link", { name: "Home" })
expect(homeLink).toHaveAttribute("href", HOME)
})
-
-test("Redirects unauthenticated users to login", async () => {
- setMockResponse.get(urls.userMe.get(), {
- [Permissions.Authenticated]: false,
- })
- renderWithProviders(, { url: "/some/url?foo=bar#baz" })
-
- const expectedUrl = login({
- pathname: "/some/url",
- search: "?foo=bar",
- hash: "#baz",
- })
- expect(window.location.assign).toHaveBeenCalledWith(expectedUrl)
-})
diff --git a/frontends/mit-learn/src/pages/ErrorPage/ForbiddenPage.tsx b/frontends/main/src/app-pages/ErrorPage/ForbiddenPage.tsx
similarity index 77%
rename from frontends/mit-learn/src/pages/ErrorPage/ForbiddenPage.tsx
rename to frontends/main/src/app-pages/ErrorPage/ForbiddenPage.tsx
index df8efb636b..4079ba5603 100644
--- a/frontends/mit-learn/src/pages/ErrorPage/ForbiddenPage.tsx
+++ b/frontends/main/src/app-pages/ErrorPage/ForbiddenPage.tsx
@@ -2,18 +2,18 @@ import React, { useEffect } from "react"
import ErrorPageTemplate from "./ErrorPageTemplate"
import { useUserMe } from "api/hooks/user"
import { Typography } from "ol-components"
-import { login } from "@/common/urls"
-import { useLocation } from "react-router"
+import { redirect } from "next/navigation"
+import * as urls from "@/common/urls"
const ForbiddenPage: React.FC = () => {
- const location = useLocation()
const { data: user } = useUserMe()
useEffect(() => {
if (!user?.is_authenticated) {
- window.location.assign(login(location))
+ const loginUrl = urls.login()
+ redirect(loginUrl)
}
- })
+ }, [user])
return (
diff --git a/frontends/main/src/app-pages/ErrorPage/NotFoundPage.test.tsx b/frontends/main/src/app-pages/ErrorPage/NotFoundPage.test.tsx
index ae832d7aba..83213c82b8 100644
--- a/frontends/main/src/app-pages/ErrorPage/NotFoundPage.test.tsx
+++ b/frontends/main/src/app-pages/ErrorPage/NotFoundPage.test.tsx
@@ -1,17 +1,8 @@
import React from "react"
-import { waitFor } from "@testing-library/react"
import { renderWithProviders, screen } from "@/test-utils"
import { HOME } from "@/common/urls"
import NotFoundPage from "./NotFoundPage"
-test.skip("The NotFoundPage loads with meta", async () => {
- renderWithProviders(, {})
- await waitFor(() => {
- const meta = document.head.querySelector('meta[name="robots"]')
- expect(meta).toHaveProperty("content", "noindex,noarchive")
- })
-})
-
test("The NotFoundPage loads with Correct Title", () => {
renderWithProviders(, {})
screen.getByRole("heading", { name: "404 Not Found Error" })
diff --git a/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx b/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx
index 6cfd91673f..082710c443 100644
--- a/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx
+++ b/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx
@@ -3,6 +3,8 @@ import DashboardPage from "@/app-pages/DashboardPage/DashboardPage"
import { Metadata } from "next"
import { standardizeMetadata } from "@/common/metadata"
+import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
+import { Permissions } from "@/common/permissions"
export const metadata: Metadata = standardizeMetadata({
title: "Your MIT Learning Journey",
@@ -10,7 +12,11 @@ export const metadata: Metadata = standardizeMetadata({
})
const Page: React.FC = () => {
- return
+ return (
+
+
+
+ )
}
export default Page
diff --git a/frontends/main/src/app/dashboard/[tab]/page.tsx b/frontends/main/src/app/dashboard/[tab]/page.tsx
index d89e7d5b3e..3586bb6208 100644
--- a/frontends/main/src/app/dashboard/[tab]/page.tsx
+++ b/frontends/main/src/app/dashboard/[tab]/page.tsx
@@ -3,13 +3,19 @@ import DashboardPage from "@/app-pages/DashboardPage/DashboardPage"
import { Metadata } from "next"
import { standardizeMetadata } from "@/common/metadata"
+import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
+import { Permissions } from "@/common/permissions"
export const metadata: Metadata = standardizeMetadata({
title: "Your MIT Learning Journey",
social: false,
})
const Page: React.FC = () => {
- return
+ return (
+
+
+
+ )
}
export default Page
diff --git a/frontends/main/src/app/dashboard/page.tsx b/frontends/main/src/app/dashboard/page.tsx
index 05c7f8aefc..151f80f864 100644
--- a/frontends/main/src/app/dashboard/page.tsx
+++ b/frontends/main/src/app/dashboard/page.tsx
@@ -2,13 +2,20 @@ import React from "react"
import { Metadata } from "next"
import DashboardPage from "@/app-pages/DashboardPage/DashboardPage"
import { standardizeMetadata } from "@/common/metadata"
+import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
+import { Permissions } from "@/common/permissions"
+
export const metadata: Metadata = standardizeMetadata({
title: "Your MIT Learning Journey",
social: false,
})
const Page: React.FC = () => {
- return
+ return (
+
+
+
+ )
}
export default Page
diff --git a/frontends/main/src/app/getQueryClient.ts b/frontends/main/src/app/getQueryClient.ts
index 03e1626b8f..91be906e05 100644
--- a/frontends/main/src/app/getQueryClient.ts
+++ b/frontends/main/src/app/getQueryClient.ts
@@ -10,6 +10,7 @@ type MaybeHasStatus = {
const RETRY_STATUS_CODES = [408, 429, 502, 503, 504]
const MAX_RETRIES = 3
+const THROW_ERROR_CODES: (number | undefined)[] = [404, 403, 401]
const makeQueryClient = (): QueryClient => {
return new QueryClient({
@@ -17,6 +18,14 @@ const makeQueryClient = (): QueryClient => {
queries: {
refetchOnWindowFocus: false,
staleTime: Infinity,
+ // Throw runtime errors instead of marking query as errored.
+ // The runtime error will be caught by an error boundary.
+ // For now, only do this for 404s, 403s, and 401s. Other errors should
+ // be handled locally by components.
+ useErrorBoundary: (error) => {
+ const status = (error as MaybeHasStatus)?.response?.status
+ return THROW_ERROR_CODES.includes(status)
+ },
retry: (failureCount, error) => {
const status = (error as MaybeHasStatus)?.response?.status
/**
diff --git a/frontends/main/src/app/layout.tsx b/frontends/main/src/app/layout.tsx
index 2f3f280abe..3580696819 100644
--- a/frontends/main/src/app/layout.tsx
+++ b/frontends/main/src/app/layout.tsx
@@ -7,6 +7,7 @@ import { PageWrapper, PageWrapperInner } from "./styled"
import Providers from "./providers"
import { MITLearnGlobalStyles } from "ol-components"
import Script from "next/script"
+import ErrorBoundary from "@/components/ErrorBoundary/ErrorBoundary"
import "./GlobalStyles"
@@ -22,7 +23,9 @@ export default function RootLayout({
- {children}
+
+ {children}
+
diff --git a/frontends/main/src/app/learningpaths/[id]/page.tsx b/frontends/main/src/app/learningpaths/[id]/page.tsx
index 1e2394f541..2d6cfc35b0 100644
--- a/frontends/main/src/app/learningpaths/[id]/page.tsx
+++ b/frontends/main/src/app/learningpaths/[id]/page.tsx
@@ -1,8 +1,14 @@
import React from "react"
import LearningPathDetailsPage from "@/app-pages/LearningPathDetailsPage/LearningPathDetailsPage"
+import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
+import { Permissions } from "@/common/permissions"
const Page: React.FC = () => {
- return
+ return (
+
+
+
+ )
}
export default Page
diff --git a/frontends/main/src/app/learningpaths/page.tsx b/frontends/main/src/app/learningpaths/page.tsx
index 2ecf26fa1f..b48a847c31 100644
--- a/frontends/main/src/app/learningpaths/page.tsx
+++ b/frontends/main/src/app/learningpaths/page.tsx
@@ -3,12 +3,19 @@ import LearningPathListingPage from "@/app-pages/LearningPathListingPage/Learnin
import { Metadata } from "next"
import { standardizeMetadata } from "@/common/metadata"
+import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
+import { Permissions } from "@/common/permissions"
+
export const metadata: Metadata = standardizeMetadata({
title: "Learning Paths",
})
const Page: React.FC = () => {
- return
+ return (
+
+
+
+ )
}
export default Page
diff --git a/frontends/main/src/app/onboarding/page.tsx b/frontends/main/src/app/onboarding/page.tsx
index ddf07d6d21..34a51559db 100644
--- a/frontends/main/src/app/onboarding/page.tsx
+++ b/frontends/main/src/app/onboarding/page.tsx
@@ -2,6 +2,8 @@ import React from "react"
import { Metadata } from "next"
import OnboardingPage from "@/app-pages/OnboardingPage/OnboardingPage"
import { standardizeMetadata } from "@/common/metadata"
+import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
+import { Permissions } from "@/common/permissions"
export const metadata: Metadata = standardizeMetadata({
title: "Onboarding",
@@ -9,7 +11,11 @@ export const metadata: Metadata = standardizeMetadata({
})
const Page: React.FC = () => {
- return
+ return (
+
+
+
+ )
}
export default Page
diff --git a/frontends/main/src/components/ErrorBoundary/ErrorBoundary.tsx b/frontends/main/src/components/ErrorBoundary/ErrorBoundary.tsx
new file mode 100644
index 0000000000..1cb3d5f864
--- /dev/null
+++ b/frontends/main/src/components/ErrorBoundary/ErrorBoundary.tsx
@@ -0,0 +1,81 @@
+"use client"
+
+import React, { Component } from "react"
+import NotFoundPage from "@/app-pages/ErrorPage/NotFoundPage"
+import ForbiddenPage from "@/app-pages/ErrorPage/ForbiddenPage"
+import { ForbiddenError } from "@/common/permissions"
+import { usePathname } from "next/navigation"
+
+interface ErrorBoundaryProps {
+ children: React.ReactNode
+}
+
+interface ErrorBoundaryHandlerProps extends ErrorBoundaryProps {
+ pathname: string
+}
+
+interface ErrorBoundaryHandlerState {
+ hasError: boolean
+ error: unknown
+ previousPathname: string
+}
+const isForbiddenError = (error: unknown) => error instanceof ForbiddenError
+
+class ErrorBoundaryHandler extends Component<
+ ErrorBoundaryHandlerProps,
+ ErrorBoundaryHandlerState
+> {
+ constructor(props: ErrorBoundaryHandlerProps) {
+ super(props)
+ this.state = {
+ hasError: false,
+ error: null,
+ previousPathname: this.props.pathname,
+ }
+ }
+
+ static getDerivedStateFromError(error: unknown) {
+ return { hasError: true, error: error }
+ }
+
+ static getDerivedStateFromProps(
+ props: ErrorBoundaryHandlerProps,
+ state: ErrorBoundaryHandlerState,
+ ): ErrorBoundaryHandlerState | null {
+ if (props.pathname !== state.previousPathname && state.error) {
+ return {
+ error: null,
+ hasError: false,
+ previousPathname: props.pathname,
+ }
+ }
+ return {
+ error: state.error,
+ hasError: state.hasError,
+ previousPathname: props.pathname,
+ }
+ }
+
+ render() {
+ if (this.state.hasError) {
+ if (isForbiddenError(this.state.error)) {
+ return
+ } else {
+ return
+ }
+ }
+
+ return this.props.children
+ }
+}
+
+export function ErrorBoundary({
+ children,
+}: ErrorBoundaryProps & { children: React.ReactNode }): JSX.Element {
+ const pathname = usePathname()
+ return (
+ {children}
+ )
+}
+
+export default ErrorBoundary
diff --git a/frontends/main/src/components/RestrictedRoute/RestrictedRoute.test.tsx b/frontends/main/src/components/RestrictedRoute/RestrictedRoute.test.tsx
new file mode 100644
index 0000000000..c8814db844
--- /dev/null
+++ b/frontends/main/src/components/RestrictedRoute/RestrictedRoute.test.tsx
@@ -0,0 +1,42 @@
+import React from "react"
+import { renderWithProviders, screen } from "../../test-utils"
+import RestrictedRoute from "./RestrictedRoute"
+import { Permissions } from "@/common/permissions"
+import { allowConsoleErrors } from "ol-test-utilities"
+
+test("Renders children if permission check satisfied", () => {
+ const errors: unknown[] = []
+
+ renderWithProviders(
+
+ Hello, world!
+ ,
+
+ {
+ user: { [Permissions.Authenticated]: true },
+ },
+ )
+
+ screen.getByText("Hello, world!")
+ expect(!errors.length).toBe(true)
+})
+
+test.each(Object.values(Permissions))(
+ "Throws error if and only if lacking required permission",
+ async (permission) => {
+ // if a user is not authenticated they are redirected to login before an error is thrown
+ if (permission === Permissions.Authenticated) {
+ return
+ }
+ allowConsoleErrors()
+
+ expect(() =>
+ renderWithProviders(
+ Hello, world!,
+ {
+ user: { [permission]: false },
+ },
+ ),
+ ).toThrow("Not allowed.")
+ },
+)
diff --git a/frontends/mit-learn/src/components/RestrictedRoute/RestrictedRoute.tsx b/frontends/main/src/components/RestrictedRoute/RestrictedRoute.tsx
similarity index 80%
rename from frontends/mit-learn/src/components/RestrictedRoute/RestrictedRoute.tsx
rename to frontends/main/src/components/RestrictedRoute/RestrictedRoute.tsx
index 5c143127c3..99db115022 100644
--- a/frontends/mit-learn/src/components/RestrictedRoute/RestrictedRoute.tsx
+++ b/frontends/main/src/components/RestrictedRoute/RestrictedRoute.tsx
@@ -1,8 +1,10 @@
+"use client"
+
import React from "react"
-import { Outlet, useLocation } from "react-router"
import { ForbiddenError, Permissions } from "@/common/permissions"
import { useUserMe } from "api/hooks/user"
-import { login } from "@/common/urls"
+import { redirect } from "next/navigation"
+import * as urls from "@/common/urls"
type RestrictedRouteProps = {
children?: React.ReactNode
@@ -39,23 +41,20 @@ const RestrictedRoute: React.FC = ({
children,
requires,
}) => {
- const location = useLocation()
const { isLoading, data: user } = useUserMe()
if (isLoading) return null
if (!user?.is_authenticated) {
// Redirect unauthenticated users to login
- window.location.assign(login(location))
+ const loginUrl = urls.login()
+ redirect(loginUrl)
return null
}
if (!isLoading && !user?.[requires]) {
// This error should be caught by an [`errorElement`](https://reactrouter.com/en/main/route/error-element).
throw new ForbiddenError("Not allowed.")
}
- /**
- * Rendering an Outlet allows this to be used as a layout route grouping many
- * child routes with the same auth condition.
- */
- return children ? children :
+
+ return children
}
export default RestrictedRoute
diff --git a/frontends/mit-learn/src/components/RestrictedRoute/RestrictedRoute.test.tsx b/frontends/mit-learn/src/components/RestrictedRoute/RestrictedRoute.test.tsx
deleted file mode 100644
index 65c684beab..0000000000
--- a/frontends/mit-learn/src/components/RestrictedRoute/RestrictedRoute.test.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import React from "react"
-import { renderRoutesWithProviders, screen, waitFor } from "../../test-utils"
-import RestrictedRoute from "./RestrictedRoute"
-import { ForbiddenError, Permissions } from "@/common/permissions"
-import { allowConsoleErrors } from "ol-test-utilities"
-import { useRouteError } from "react-router"
-
-const ErrorRecord: React.FC<{ errors: unknown[] }> = ({ errors }) => {
- const error = useRouteError()
- if (error) {
- errors.push(error)
- }
- return null
-}
-
-test("Renders children if permission check satisfied", () => {
- const errors: unknown[] = []
-
- renderRoutesWithProviders(
- [
- {
- path: "*",
- element: (
-
- Hello, world!
-
- ),
- errorElement: ,
- },
- ],
- {
- user: { [Permissions.Authenticated]: true },
- },
- )
-
- screen.getByText("Hello, world!")
- expect(!errors.length).toBe(true)
-})
-
-test("Renders child routes if permission check satisfied.", () => {
- const errors: unknown[] = []
-
- renderRoutesWithProviders(
- [
- {
- element: ,
- children: [
- {
- element: "Hello, world!",
- path: "*",
- },
- ],
- errorElement: ,
- },
- ],
- {
- user: { [Permissions.Authenticated]: true },
- },
- )
-
- screen.getByText("Hello, world!")
- expect(!errors.length).toBe(true)
-})
-
-test.each(Object.values(Permissions))(
- "Throws error if and only if lacking required permission",
- async (permission) => {
- // if a user is not authenticated they are redirected to login before an error is thrown
- if (permission === Permissions.Authenticated) {
- return
- }
- const errors: unknown[] = []
-
- allowConsoleErrors()
-
- renderRoutesWithProviders(
- [
- {
- path: "*",
- element: (
-
- Hello, world!
-
- ),
- errorElement: ,
- },
- ],
- {
- user: { [permission]: false },
- },
- )
-
- await waitFor(() => {
- expect(errors.length > 0).toBe(true)
- })
-
- expect(errors[0]).toBeInstanceOf(ForbiddenError)
- },
-)
diff --git a/frontends/mit-learn/src/pages/ErrorPage/ErrorPage.test.tsx b/frontends/mit-learn/src/pages/ErrorPage/ErrorPage.test.tsx
deleted file mode 100644
index 9f04b5a414..0000000000
--- a/frontends/mit-learn/src/pages/ErrorPage/ErrorPage.test.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-import React from "react"
-import { waitFor } from "@testing-library/react"
-import { useQuery } from "@tanstack/react-query"
-import { renderRoutesWithProviders, renderTestApp } from "../../test-utils"
-import type { TestAppOptions } from "../../test-utils"
-import ErrorPage from "./ErrorPage"
-import { setMockResponse, mockAxiosInstance as axios } from "api/test-utils"
-import { allowConsoleErrors } from "ol-test-utilities"
-import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
-import { Permissions } from "@/common/permissions"
-
-/**
- * Renders an erroring-component within a react-router ErrorBoundary using
- * ErrorPage as its display. The component errors via a react-query API call
- * that resolves with the given status code.
- */
-const setup = (statusCode: number, opts?: Partial) => {
- setMockResponse.get("/foo", null, { code: statusCode })
-
- const TestComponent = () => {
- useQuery({
- queryFn: async () => axios.get("/foo"),
- queryKey: ["key"],
- })
- return null
- }
-
- return renderRoutesWithProviders(
- [
- {
- path: "*",
- errorElement: ,
- element: ,
- },
- ],
- opts,
- )
-}
-
-test.each([{ status: 401 }, { status: 403 }])(
- "ErrorPage shows ForbiddenPage on $status errors",
- async ({ status }) => {
- allowConsoleErrors()
- // 401 for authenticated users is unrealisted, but we test the login
- // redirect elsewhere.
- setup(status, { user: { is_authenticated: true } })
- await waitFor(() => {
- expect(document.title).toBe("Not Allowed | MIT Learn")
- })
- },
-)
-
-test("ErrorPage shows NotFound on API 404 errors", async () => {
- allowConsoleErrors()
- setup(404)
- await waitFor(() => {
- expect(document.title).toBe("Not Found | MIT Learn")
- })
-})
-
-test("ErrorPage shows NotFound on frontend routing 404 errors", async () => {
- allowConsoleErrors()
- renderTestApp({ url: "/some-fake-route" })
- await waitFor(() => {
- expect(document.title).toBe("Not Found | MIT Learn")
- })
-})
-
-test("ErrorPage shows ForbiddenPage on restricted routes.", async () => {
- allowConsoleErrors()
- renderRoutesWithProviders(
- [
- {
- errorElement: ,
- children: [
- {
- element: (
-
- You shall not pass.
-
- ),
- path: "*",
- },
- ],
- },
- ],
- { user: { is_authenticated: true } },
- )
- await waitFor(() => {
- expect(document.title).toBe("Not Allowed | MIT Learn")
- })
-})
-
-test("ErrorPage shows fallback and logs unexpected errors", async () => {
- const { consoleError } = allowConsoleErrors()
- const ThrowError = () => {
- throw new Error("Some Error")
- }
- renderRoutesWithProviders(
- [
- {
- errorElement: ,
- element: ,
- path: "*",
- },
- ],
- { user: { is_authenticated: true } },
- )
- await waitFor(() => {
- expect(document.title).toBe("Error | MIT Learn")
- })
- expect(consoleError).toHaveBeenCalledWith(Error("Some Error"))
-})
diff --git a/frontends/mit-learn/src/pages/ErrorPage/ErrorPage.tsx b/frontends/mit-learn/src/pages/ErrorPage/ErrorPage.tsx
deleted file mode 100644
index 7a1103f109..0000000000
--- a/frontends/mit-learn/src/pages/ErrorPage/ErrorPage.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from "react"
-import { AxiosError } from "axios"
-import ForbiddenPage from "./ForbiddenPage"
-import NotFoundPage from "./NotFoundPage"
-import { useRouteError, isRouteErrorResponse } from "react-router"
-import ErrorPageTemplate from "./ErrorPageTemplate"
-import { ForbiddenError as ClientSideForbiddenError } from "@/common/permissions"
-import { Typography } from "ol-components"
-
-const AUTH_STATUS_CODES = [401, 403]
-const NOT_FOUND_STATUS_CODES = [404]
-
-const isNotFoundError = (error: unknown) =>
- // frontend routing 404
- (isRouteErrorResponse(error) &&
- NOT_FOUND_STATUS_CODES.includes(error.status)) ||
- // api response 404
- (error instanceof AxiosError &&
- error.response &&
- NOT_FOUND_STATUS_CODES.includes(Number(error.response.status)))
-
-const isForbiddenError = (error: unknown) =>
- error instanceof ClientSideForbiddenError ||
- (error instanceof AxiosError &&
- error.response &&
- AUTH_STATUS_CODES.includes(error.response.status))
-
-const ErrorPage = () => {
- const error = useRouteError()
-
- if (isForbiddenError(error)) {
- return
- } else if (isNotFoundError(error)) {
- return
- } else {
- console.error(error)
- }
-
- return (
- /**
- * This should not happen, but it's better than the app crashing.
- */
-
-
- Something went wrong.
-
-
- )
-}
-
-export default ErrorPage