import Client from '../templates/client/Client';
import { getLoginPath } from './pathUtils';
import { ConfigConfigError, ConfigConfigLoading } from './ConfigConfig';
+import { FeatureCheck } from './FeatureCheck';
const createRouter = (clientConfig: ClientConfig) => {
const { hashRouter } = clientConfig;
// TODO: app crash boundary
function App() {
return (
- <ClientConfigLoader
- fallback={() => <ConfigConfigLoading />}
- error={(err, retry, ignore) => (
- <ConfigConfigError error={err} retry={retry} ignore={ignore} />
- )}
- >
- {(clientConfig) => (
- <ClientConfigProvider value={clientConfig}>
- <JotaiProvider>
- <RouterProvider router={createRouter(clientConfig)} />
- </JotaiProvider>
- </ClientConfigProvider>
- )}
- </ClientConfigLoader>
+ <FeatureCheck>
+ <ClientConfigLoader
+ fallback={() => <ConfigConfigLoading />}
+ error={(err, retry, ignore) => (
+ <ConfigConfigError error={err} retry={retry} ignore={ignore} />
+ )}
+ >
+ {(clientConfig) => (
+ <ClientConfigProvider value={clientConfig}>
+ <JotaiProvider>
+ <RouterProvider router={createRouter(clientConfig)} />
+ </JotaiProvider>
+ </ClientConfigProvider>
+ )}
+ </ClientConfigLoader>
+ </FeatureCheck>
);
}
--- /dev/null
+import React, { ReactNode, useEffect } from 'react';
+import { Box, Dialog, Text, config } from 'folds';
+import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
+import { checkIndexedDBSupport } from '../utils/featureCheck';
+import { SplashScreen } from '../components/splash-screen';
+
+export function FeatureCheck({ children }: { children: ReactNode }) {
+ const [idbSupportState, checkIDBSupport] = useAsyncCallback(checkIndexedDBSupport);
+
+ useEffect(() => {
+ checkIDBSupport();
+ }, [checkIDBSupport]);
+
+ if (idbSupportState.status === AsyncStatus.Success && idbSupportState.data === false) {
+ return (
+ <SplashScreen>
+ <Box grow="Yes" alignItems="Center" justifyContent="Center">
+ <Dialog>
+ <Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
+ <Text>Missing Browser Feature</Text>
+ <Text size="T300" priority="400">
+ No IndexedDB support found. This application requires IndexedDB to store session
+ data locally. Please make sure your browser support IndexedDB and have it enabled.
+ </Text>
+ <Text size="T200">
+ <a
+ href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API"
+ rel="noreferrer noopener"
+ target="_blank"
+ >
+ What is IndexedDB?
+ </a>
+ </Text>
+ </Box>
+ </Dialog>
+ </Box>
+ </SplashScreen>
+ );
+ }
+
+ return children;
+}
--- /dev/null
+export const checkIndexedDBSupport = async (): Promise<boolean> => {
+ const ts = new Date().getTime();
+ const dbName = `checkIndexedDBSupport-${ts}`;
+ return new Promise((resolve) => {
+ let db;
+ try {
+ db = indexedDB.open(dbName);
+ } catch {
+ resolve(false);
+ return;
+ }
+ db.onsuccess = () => {
+ resolve(true);
+ indexedDB.deleteDatabase(dbName);
+ };
+ db.onerror = () => {
+ resolve(false);
+ indexedDB.deleteDatabase(dbName);
+ };
+ });
+};