diff --git a/.env.example b/.env.example index 0b72555..507d2f7 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,5 @@ VITE_API_BASE_URL=/mock VITE_YEAR=2024 VITE_UMAMI_WEBSITE_ID= +VITE_FEEDBACK_FORM_URL= +VITE_FEEDBACK_FORM_URL_PREFILL_ERROR_MESSAGE= diff --git a/package.json b/package.json index ed236b7..7654f43 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "mutative": "^1.0.8", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-error-boundary": "^4.0.13", "react-i18next": "^15.0.2", "simple-zustand-devtools": "^1.1.0", "sonner": "^1.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a62e095..ec6790f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + react-error-boundary: + specifier: ^4.0.13 + version: 4.0.13(react@18.3.1) react-i18next: specifier: ^15.0.2 version: 15.0.2(i18next@23.15.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -3885,6 +3888,11 @@ packages: peerDependencies: react: ^18.3.1 + react-error-boundary@4.0.13: + resolution: {integrity: sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==} + peerDependencies: + react: '>=16.13.1' + react-i18next@15.0.2: resolution: {integrity: sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==} peerDependencies: @@ -9464,6 +9472,11 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 + react-error-boundary@4.0.13(react@18.3.1): + dependencies: + '@babel/runtime': 7.25.7 + react: 18.3.1 + react-i18next@15.0.2(i18next@23.15.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 @@ -9505,7 +9518,7 @@ snapshots: react-textarea-autosize@8.5.3(@types/react@18.3.3)(react@18.3.1): dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.7 react: 18.3.1 use-composed-ref: 1.3.0(react@18.3.1) use-latest: 1.2.1(@types/react@18.3.3)(react@18.3.1) diff --git a/src/components/Error.tsx b/src/components/Error.tsx new file mode 100644 index 0000000..450bf9e --- /dev/null +++ b/src/components/Error.tsx @@ -0,0 +1,35 @@ +import { Code, Link } from '@nextui-org/react'; +import type { FallbackProps } from 'react-error-boundary'; + +import { useMount } from '../utils/mount'; + +export const Error = ({ error }: FallbackProps) => { + const errorMessage = String(error); + const prefilledFeedbackForm = `${import.meta.env.VITE_FEEDBACK_FORM_URL_PREFILL_ERROR_MESSAGE}+${errorMessage}%0ACause:+`; + + useMount(() => { + // Clear local data to reset the app + localStorage.clear(); + }); + + return ( +
+ We're sorry, but we need to clear all saved data for this website + (including any locally stored courses and times). +
+
+ Error Message:
+ {errorMessage}
+
+ + Before refreshing the page, would you like to{' '} + + send us feedback + {' '} + along with the error message to help improve our app? +
+