From a741209d1b58dbc6596b5646d8012e97f9bc948a Mon Sep 17 00:00:00 2001 From: James Gentes Date: Wed, 22 Nov 2023 14:38:52 -0800 Subject: [PATCH 1/4] removed notistack and moved errorboundary --- app/api/db/appState.ts | 10 ----- app/components/InitialLoader.tsx | 2 + app/components/layout/Layout.tsx | 42 ------------------ app/root.tsx | 73 +++++++++++++++++++++++-------- app/routes/_index.tsx | 74 ++++++++++++++++---------------- app/theme.tsx | 4 -- app/utils/notifications.tsx | 10 ++--- package.json | 1 - yarn.lock | 31 +------------ 9 files changed, 101 insertions(+), 146 deletions(-) delete mode 100644 app/components/layout/Layout.tsx diff --git a/app/api/db/appState.ts b/app/api/db/appState.ts index 6788cb7..37d2c11 100644 --- a/app/api/db/appState.ts +++ b/app/api/db/appState.ts @@ -94,22 +94,12 @@ const { useStore: modalState, setStore: setModalState } = createStore< openState: false }) -// NotificationState is an alert handler -const { useStore: notificationState } = createStore<{ - message: string | null - variant: 'success' | 'error' | 'warning' | 'info' -}>({ - message: '', - variant: 'error' -}) - export { AppState, audioState, getAppState, getAudioState, modalState, - notificationState, setAppState, setAudioState, setModalState diff --git a/app/components/InitialLoader.tsx b/app/components/InitialLoader.tsx index fc2083f..50e7049 100644 --- a/app/components/InitialLoader.tsx +++ b/app/components/InitialLoader.tsx @@ -1,3 +1,5 @@ +// InitialLoader is used to hide the flash of unstyled content + import { Icon } from '@iconify-icon/react' import { CircularProgress, styled } from '@mui/joy' import Logo from '~/components/layout/MixpointLogo' diff --git a/app/components/layout/Layout.tsx b/app/components/layout/Layout.tsx deleted file mode 100644 index 997e1a5..0000000 --- a/app/components/layout/Layout.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Sheet } from '@mui/joy' -import { useEffect } from 'react' -import { setAppState } from '~/api/db/appState' -import { getPrefs, useLiveQuery } from '~/api/db/dbHandlers' -import Header from '~/components/layout/Header' -import MixView from '~/components/mixes/MixView' -import DrawerButton from '~/components/tracks/DrawerButton' -import TrackDrawer from '~/components/tracks/TrackDrawer' -import TrackTable from '~/components/tracks/TrackTable' - -const Layout: React.FunctionComponent = () => { - const { tracks } = useLiveQuery(() => getPrefs('mix', 'tracks')) || {} - const mixViewVisible = !!tracks?.filter(t => t).length - - useEffect(() => { - if (!mixViewVisible) setAppState.openDrawer(false) - }, [mixViewVisible]) - - return ( - -
- {mixViewVisible ? ( - <> - - - - ) : ( - - )} - - - - ) -} - -export { Layout as default } diff --git a/app/root.tsx b/app/root.tsx index 1ec8aed..d55335f 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,6 +1,7 @@ // this file establishes the root component that renders all subsequent / child routes // it also injects top level styling, HTML meta tags, links, and javascript for browser rendering import PublicSansFont from '@fontsource/public-sans/latin.css' +import { Snackbar } from '@mui/joy' import { CssVarsProvider as JoyCssVarsProvider } from '@mui/joy/styles' import { CssBaseline } from '@mui/material' import { @@ -20,15 +21,17 @@ import { Meta, Outlet, Scripts, - useLoaderData + isRouteErrorResponse, + useLoaderData, + useRouteError } from '@remix-run/react' -import { SnackbarProvider } from 'notistack' import { useEffect, useState } from 'react' import { createHead } from 'remix-island' import ConfirmModal from '~/components/ConfirmModal' import InitialLoader from '~/components/InitialLoader' import styles from '~/root.css' import { theme as joyTheme } from '~/theme' +import { Notification, errorHandler } from '~/utils/notifications' const materialTheme = materialExtendTheme() @@ -69,13 +72,27 @@ const HtmlDoc = ({ children }: { children: React.ReactNode }) => { const ThemeLoader = ({ noSplash }: { noSplash?: boolean }) => { const [loading, setLoading] = useState(true) + const [notification, setNotification] = useState() - // InitialLoader is used to hide the flash of unstyled content useEffect(() => { + // initial loading screen timeout const timer = setTimeout(() => { setLoading(false) }, 500) - return () => clearTimeout(timer) + + // for snackbar notifications + const notify = (e: CustomEventInit) => + setNotification({ + message: e.detail.message, + color: e.detail.color || 'danger' + }) + + window.addEventListener('notify', notify) + + return () => { + clearTimeout(timer) + window.removeEventListener('notify', notify) + } }, []) return ( @@ -84,18 +101,26 @@ const ThemeLoader = ({ noSplash }: { noSplash?: boolean }) => { defaultMode={'dark'} > - - {/* CSS Baseline is used to inject global styles */} - - {loading && !noSplash ? ( - - ) : ( - <> - - - - )} - + {/* CSS Baseline is used to inject global styles */} + + {loading && !noSplash ? ( + + ) : ( + <> + + + + )} + setNotification(undefined)} + > + {notification?.message} + ) @@ -127,4 +152,18 @@ const App = () => { ) } -export { ThemeLoader, App as default, links, meta } +// exporting this automatically uses it to capture errors +const ErrorBoundary = () => { + const error = useRouteError() as Error + console.error('error boundary: ', error) + + const message = isRouteErrorResponse(error) + ? error.data.message + : error.message || JSON.stringify(error) + + errorHandler(message) + + return +} + +export { ThemeLoader, App as default, links, meta, ErrorBoundary } diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 68dbc76..dc6db57 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -1,42 +1,42 @@ -// this file provides top level error and catch boundaries, plus notification handling -import { VariantType, useSnackbar } from 'notistack' +import { Sheet } from '@mui/joy' import { useEffect } from 'react' - -import { isRouteErrorResponse, useRouteError } from '@remix-run/react' - -import InitialLoader from '~/components/InitialLoader' -import Layout from '~/components/layout/Layout' - -const boundaryHandler = (message: string, variant: VariantType = 'error') => { - const { enqueueSnackbar } = useSnackbar() - enqueueSnackbar(message, { variant }) - return -} - -// exporting this automatically uses it to capture errors -const ErrorBoundary = () => { - const error = useRouteError() as Error - console.error('error boundary: ', error) - if (isRouteErrorResponse(error)) { - return boundaryHandler(error.data.message, 'warning') - } - - boundaryHandler(error.message || JSON.stringify(error)) -} - -const Boundary = () => { - const { enqueueSnackbar } = useSnackbar() +import { setAppState } from '~/api/db/appState' +import { getPrefs, useLiveQuery } from '~/api/db/dbHandlers' +import Header from '~/components/layout/Header' +import MixView from '~/components/mixes/MixView' +import DrawerButton from '~/components/tracks/DrawerButton' +import TrackDrawer from '~/components/tracks/TrackDrawer' +import TrackTable from '~/components/tracks/TrackTable' + +const Index: React.FunctionComponent = () => { + const { tracks } = useLiveQuery(() => getPrefs('mix', 'tracks')) || {} + const mixViewVisible = !!tracks?.filter(t => t).length useEffect(() => { - const notify = (e: CustomEventInit) => - enqueueSnackbar(e.detail.message, { variant: e.detail.variant }) - - window.addEventListener('notify', notify) - - return () => window.removeEventListener('notify', notify) - }, [enqueueSnackbar]) - - return + if (!mixViewVisible) setAppState.openDrawer(false) + }, [mixViewVisible]) + + return ( + +
+ {mixViewVisible ? ( + <> + + + + ) : ( + + )} + + + + ) } -export { Boundary as default, ErrorBoundary } +export { Index as default } diff --git a/app/theme.tsx b/app/theme.tsx index 8805297..4035164 100644 --- a/app/theme.tsx +++ b/app/theme.tsx @@ -6,10 +6,6 @@ import { } from '@mui/material/styles' import { deepmerge } from '@mui/utils' -// ; -// -// - const muiTheme = extendMuiTheme({ // This is required to point to `var(--joy-*)` because we are using `CssVarsProvider` from Joy UI. cssVarPrefix: 'joy', diff --git a/app/utils/notifications.tsx b/app/utils/notifications.tsx index ca76363..f047fc7 100644 --- a/app/utils/notifications.tsx +++ b/app/utils/notifications.tsx @@ -1,8 +1,8 @@ -import { notificationState } from '~/api/db/appState' +import { SnackbarProps } from '@mui/joy' type Notification = { - message?: string - variant?: 'success' | 'error' | 'warning' | 'info' + message: string + color?: SnackbarProps['color'] } const errorHandler = (error: Error | string) => { @@ -12,10 +12,10 @@ const errorHandler = (error: Error | string) => { window.dispatchEvent( new CustomEvent('notify', { - detail: { message: err?.message, variant: 'error' } + detail: { message: err?.message, color: 'danger' } }) ) } -export { errorHandler, notificationState } +export { errorHandler } export type { Notification } diff --git a/package.json b/package.json index 6e81600..d06e6c3 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "isbot": "latest", "jsdom": "^21.1.1", "moment": "~2.29.4", - "notistack": "~2.0.5", "react": "~18", "react-dom": "~18", "remix-island": "^0.1.2", diff --git a/yarn.lock b/yarn.lock index 477bb5f..2475b73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2983,13 +2983,6 @@ __metadata: languageName: node linkType: hard -"clsx@npm:^1.1.0": - version: 1.2.1 - resolution: "clsx@npm:1.2.1" - checksum: 30befca8019b2eb7dbad38cff6266cf543091dae2825c856a62a8ccf2c3ab9c2907c4d12b288b73101196767f66812365400a227581484a05f968b0307cfaf12 - languageName: node - linkType: hard - "clsx@npm:^2.0.0": version: 2.0.0 resolution: "clsx@npm:2.0.0" @@ -4484,7 +4477,7 @@ __metadata: languageName: node linkType: hard -"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1": +"hoist-non-react-statics@npm:^3.3.1": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: @@ -5981,7 +5974,6 @@ isbot@latest: isbot: latest jsdom: ^21.1.1 moment: ~2.29.4 - notistack: ~2.0.5 react: ~18 react-dom: ~18 remix-island: ^0.1.2 @@ -6187,27 +6179,6 @@ isbot@latest: languageName: node linkType: hard -"notistack@npm:~2.0.5": - version: 2.0.8 - resolution: "notistack@npm:2.0.8" - dependencies: - clsx: ^1.1.0 - hoist-non-react-statics: ^3.3.0 - peerDependencies: - "@emotion/react": ^11.4.1 - "@emotion/styled": ^11.3.0 - "@mui/material": ^5.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - "@emotion/react": - optional: true - "@emotion/styled": - optional: true - checksum: f95952ea7209840f6f05a65e74f0fb4e7a1bb321753b2955ae6052f2205d47a6a3c50a42b72db11eac2fc491c4105b4687bed89e79287399530973fa133a5380 - languageName: node - linkType: hard - "npm-install-checks@npm:^6.0.0": version: 6.2.0 resolution: "npm-install-checks@npm:6.2.0" From 5dc44423af540657ffa8751bb4c09e0d34d0af40 Mon Sep 17 00:00:00 2001 From: James Gentes Date: Thu, 23 Nov 2023 08:04:43 -0800 Subject: [PATCH 2/4] added go back button --- app/components/InitialLoader.tsx | 63 +++++++++++++++++++++----------- app/entry.server.tsx | 4 ++ app/root.tsx | 25 ++++++------- app/routes/auth.callback.tsx | 13 +++++-- app/routes/auth.confirm.tsx | 6 ++- 5 files changed, 72 insertions(+), 39 deletions(-) diff --git a/app/components/InitialLoader.tsx b/app/components/InitialLoader.tsx index 50e7049..8a01c1d 100644 --- a/app/components/InitialLoader.tsx +++ b/app/components/InitialLoader.tsx @@ -1,7 +1,8 @@ // InitialLoader is used to hide the flash of unstyled content import { Icon } from '@iconify-icon/react' -import { CircularProgress, styled } from '@mui/joy' +import { Button, CircularProgress, styled } from '@mui/joy' +import { useNavigate } from '@remix-run/react' import Logo from '~/components/layout/MixpointLogo' const LoaderWrapDiv = styled('div')` @@ -35,26 +36,44 @@ const LoaderSubtext = styled('span')(({ theme }) => ({ color: theme.palette.text.primary })) -const InitialLoader = ({ message }: { message?: string }) => ( - - - - - {message ? ( - - ) : ( - - )} - - - {message || 'Please Wait. Loading...'} - - - -) +const InitialLoader = ({ message }: { message?: string }) => { + const navigate = useNavigate() + return ( + + {!message ? null : ( + + )} + + + + {message ? ( + + ) : ( + + )} + + + {message || 'Please Wait. Loading...'} + + + + ) +} export default InitialLoader diff --git a/app/entry.server.tsx b/app/entry.server.tsx index 12d5436..5a33e55 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -75,3 +75,7 @@ async function handleBrowserRequest( status: didError ? 500 : responseStatusCode }) } + +export function handleError(error: Error) { + console.error(error) +} diff --git a/app/root.tsx b/app/root.tsx index d55335f..50c0e25 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -31,7 +31,7 @@ import ConfirmModal from '~/components/ConfirmModal' import InitialLoader from '~/components/InitialLoader' import styles from '~/root.css' import { theme as joyTheme } from '~/theme' -import { Notification, errorHandler } from '~/utils/notifications' +import { Notification } from '~/utils/notifications' const materialTheme = materialExtendTheme() @@ -70,7 +70,7 @@ const HtmlDoc = ({ children }: { children: React.ReactNode }) => { ) } -const ThemeLoader = ({ noSplash }: { noSplash?: boolean }) => { +const ThemeLoader = ({ error }: { error?: string }) => { const [loading, setLoading] = useState(true) const [notification, setNotification] = useState() @@ -103,8 +103,8 @@ const ThemeLoader = ({ noSplash }: { noSplash?: boolean }) => { {/* CSS Baseline is used to inject global styles */} - {loading && !noSplash ? ( - + {loading || error ? ( + ) : ( <> @@ -136,8 +136,8 @@ export async function loader({ context }: LoaderFunctionArgs) { }) } -const App = () => { - const data = useLoaderData() +const App = ({ error }: { error?: string }) => { + const data = error ? {} : useLoaderData() return (