diff --git a/app/features/components/ErrorBoundary/index.tsx b/app/features/components/ErrorBoundary/index.tsx new file mode 100644 index 0000000..39ae31e --- /dev/null +++ b/app/features/components/ErrorBoundary/index.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import { ErrorBoundary } from 'react-error-boundary' + +type FallbackRenderProps = { + error: Error + resetErrorBoundary: () => void +} + +const FallbackRender = ({ error }: FallbackRenderProps) => { + // eslint-disable-next-line no-console + console.error('Error description: ', error.message) + + return ( +
+

+ We encountered an internal error. Please try again. +

+
+ ) +} + +type CatchErrorBoundaryProps = { + children: React.ReactNode +} + +export const CatchErrorBoundary = ({ children }: CatchErrorBoundaryProps) => { + return ( + {children} + ) +} diff --git a/app/features/components/index.tsx b/app/features/components/index.tsx index 323fe65..202fc6c 100644 --- a/app/features/components/index.tsx +++ b/app/features/components/index.tsx @@ -8,3 +8,4 @@ export * from './Breadcrumbs' export * from './Page' export * from './Show' export * from './Spinner' +export * from './ErrorBoundary' diff --git a/app/pages/Events/components/PastEvents/index.tsx b/app/pages/Events/components/PastEvents/index.tsx deleted file mode 100644 index 969f073..0000000 --- a/app/pages/Events/components/PastEvents/index.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useAsyncValue } from '@remix-run/react' -import { Section, H2 } from '~/features/components' -import { EventList } from '../EventList' -import type { LoaderData } from '../../loader' - -export const PastEvents = () => { - const res = useAsyncValue() as Awaited - - if (res.success === false) { - return null - } - - return ( -
-

Past events

- -
- ) -} diff --git a/app/pages/Events/components/UpcomingEvents/index.tsx b/app/pages/Events/components/UpcomingEvents/index.tsx deleted file mode 100644 index 5bd5f5e..0000000 --- a/app/pages/Events/components/UpcomingEvents/index.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useAsyncValue } from '@remix-run/react' -import { Section, H2 } from '~/features/components' -import { EventList } from '../EventList' -import type { LoaderData } from '../../loader' - -export const UpcomingEvents = () => { - const res = useAsyncValue() as Awaited - - if (res.success === false) { - return null - } - - return ( -
-

Upcoming events

- -
- ) -} diff --git a/app/pages/Events/index.tsx b/app/pages/Events/index.tsx index 588f18a..589206c 100644 --- a/app/pages/Events/index.tsx +++ b/app/pages/Events/index.tsx @@ -8,12 +8,13 @@ import { Page, Spinner } from '~/features/components' -import { PastEvents } from './components/PastEvents' -import { UpcomingEvents } from './components/UpcomingEvents' import { Suspense } from 'react' +import { Section, H2 } from '~/features/components' +import { EventList } from './components/EventList' +import { CatchErrorBoundary } from '~/features/components' const Events = () => { - const { pastEventsPromise, upcomingEventsPromise } = + const { upcomingEventsPromise, pastEventsPromise } = useLoaderData() as LoaderData return ( @@ -28,14 +29,36 @@ const Events = () => {

Events

- }> - - - - - - - +
+

Upcoming events

+ }> + + + {(res) => { + if (res.success === false) { + throw new Error(res.message) + } + return + }} + + + +
+
+

Past events

+ }> + + + {(res) => { + if (res.success === false) { + throw new Error(res.message) + } + return + }} + + + +
) diff --git a/package.json b/package.json index dc06a6b..c07a3e8 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "marked": "^4.2.12", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-error-boundary": "^4.0.11", "react-schemaorg": "^2.0.0", "remix-image": "^1.4.0", "schema-dts": "^1.1.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bcd7187..814e0dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + dependencies: '@headlessui/react': specifier: ^1.7.12 @@ -49,6 +53,9 @@ dependencies: react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + react-error-boundary: + specifier: ^4.0.11 + version: 4.0.11(react@18.2.0) react-schemaorg: specifier: ^2.0.0 version: 2.0.0(react@18.2.0)(schema-dts@1.1.2)(typescript@4.9.5) @@ -1528,7 +1535,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 - dev: true /@babel/template@7.20.7: resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} @@ -4844,6 +4850,7 @@ packages: /bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + requiresBuild: true dependencies: file-uri-to-path: 1.0.0 dev: true @@ -6872,6 +6879,7 @@ packages: /file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + requiresBuild: true dev: true optional: true @@ -9478,6 +9486,7 @@ packages: /node-addon-api@1.7.2: resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} + requiresBuild: true dev: true optional: true @@ -10411,6 +10420,15 @@ packages: react: 18.2.0 scheduler: 0.23.0 + /react-error-boundary@4.0.11(react@18.2.0): + resolution: {integrity: sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==} + peerDependencies: + react: '>=16.13.1' + dependencies: + '@babel/runtime': 7.21.0 + react: 18.2.0 + dev: false + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: true @@ -10566,7 +10584,6 @@ packages: /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - dev: true /regenerator-transform@0.15.1: resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==}