remnantchat/src/Init.tsx
Jeremy Kahn d697aa0482
feat(performance): Show loading indicator while app loads (#221)
* feat(performance): lazy-load bootstrap
2023-12-11 17:19:31 -06:00

88 lines
2.3 KiB
TypeScript

import { lazy, Suspense, useEffect, useState } from 'react'
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import { v4 as uuid } from 'uuid'
import { encryptionService } from 'services/Encryption'
import {
EnvironmentUnsupportedDialog,
isEnvironmentSupported,
} from 'components/Shell/EnvironmentUnsupportedDialog'
import { WholePageLoading } from 'components/Loading/Loading'
import { ColorMode, UserSettings } from 'models/settings'
import type { BootstrapProps } from './Bootstrap'
// @ts-expect-error
const Bootstrap = lazy(() => import('./Bootstrap.js'))
export interface InitProps extends Omit<BootstrapProps, 'initialUserSettings'> {
getUuid?: typeof uuid
}
// NOTE: This is meant to be a thin layer around the Bootstrap component that
// only handles asynchronous creation of the public/private keys that Bootstrap
// requires.
const Init = ({ getUuid = uuid, ...props }: InitProps) => {
const [userSettings, setUserSettings] = useState<UserSettings | null>(null)
const [errorMessage, setErrorMessage] = useState<string | null>(null)
useEffect(() => {
;(async () => {
if (userSettings !== null) return
try {
const { publicKey, privateKey } =
await encryptionService.generateKeyPair()
setUserSettings({
userId: getUuid(),
customUsername: '',
colorMode: ColorMode.DARK,
playSoundOnNewMessage: true,
showNotificationOnNewMessage: true,
showActiveTypingStatus: true,
publicKey,
privateKey,
})
} catch (e) {
console.error(e)
setErrorMessage(
'Chitchatter was unable to boot up. Please check the browser console.'
)
}
})()
}, [getUuid, userSettings])
if (!isEnvironmentSupported) {
return <EnvironmentUnsupportedDialog />
}
if (errorMessage) {
return (
<Box
sx={{
display: 'flex',
height: '100vh',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Typography>{errorMessage}</Typography>
</Box>
)
}
if (userSettings === null) {
return <WholePageLoading />
}
return (
<Suspense fallback={<WholePageLoading />}>
<Bootstrap {...props} initialUserSettings={userSettings} />
</Suspense>
)
}
export default Init