refactor: move shell into its own component

This commit is contained in:
Jeremy Kahn 2022-08-31 19:40:40 -05:00
parent 839628dc75
commit bf4b6b18d6
3 changed files with 128 additions and 110 deletions

View File

@ -1,42 +1,19 @@
import { import { useEffect, useState } from 'react'
forwardRef,
useCallback,
useEffect,
useMemo,
useState,
SyntheticEvent,
} from 'react'
import { Routes, Route } from 'react-router-dom' import { Routes, Route } from 'react-router-dom'
import { v4 as uuid } from 'uuid' import { v4 as uuid } from 'uuid'
import localforage from 'localforage' import localforage from 'localforage'
import AppBar from '@mui/material/AppBar'
import Toolbar from '@mui/material/Toolbar'
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import StepIcon from '@mui/material/StepIcon'
import Tooltip from '@mui/material/Tooltip'
import Snackbar from '@mui/material/Snackbar'
import MuiAlert, { AlertProps, AlertColor } from '@mui/material/Alert'
import { ShellContext } from 'ShellContext'
import { Home } from 'pages/Home/' import { Home } from 'pages/Home/'
import { PublicRoom } from 'pages/PublicRoom/' import { PublicRoom } from 'pages/PublicRoom/'
import { UserSettings } from 'models/settings' import { UserSettings } from 'models/settings'
import { PersistedStorageKeys } from 'models/storage' import { PersistedStorageKeys } from 'models/storage'
import { AlertOptions } from 'models/shell' import { Shell } from 'components/Shell'
export interface BootstrapProps { export interface BootstrapProps {
persistedStorage?: typeof localforage persistedStorage?: typeof localforage
getUuid?: typeof uuid getUuid?: typeof uuid
} }
const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(
props,
ref
) {
return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />
})
function Bootstrap({ function Bootstrap({
persistedStorage = localforage.createInstance({ persistedStorage = localforage.createInstance({
name: 'chitchatter', name: 'chitchatter',
@ -45,37 +22,8 @@ function Bootstrap({
getUuid = uuid, getUuid = uuid,
}: BootstrapProps) { }: BootstrapProps) {
const [hasLoadedSettings, setHasLoadedSettings] = useState(false) const [hasLoadedSettings, setHasLoadedSettings] = useState(false)
const [isAlertShowing, setIsAlertShowing] = useState(false)
const [alertSeverity, setAlertSeverity] = useState<AlertColor>('info')
const [settings, setSettings] = useState({ userId: getUuid() }) const [settings, setSettings] = useState({ userId: getUuid() })
const { userId } = settings const { userId } = settings
const [title, setTitle] = useState('')
const [alertText, setAlertText] = useState('')
const [numberOfPeers, setNumberOfPeers] = useState(1)
const showAlert = useCallback<
(message: string, options?: AlertOptions) => void
>((message, options) => {
setAlertText(message)
setAlertSeverity(options?.severity ?? 'info')
setIsAlertShowing(true)
}, [])
const shellContextValue = useMemo(
() => ({ numberOfPeers, setNumberOfPeers, setTitle, showAlert }),
[numberOfPeers, setNumberOfPeers, setTitle, showAlert]
)
const handleAlertClose = (
_event?: SyntheticEvent | Event,
reason?: string
) => {
if (reason === 'clickaway') {
return
}
setIsAlertShowing(false)
}
useEffect(() => { useEffect(() => {
;(async () => { ;(async () => {
@ -99,50 +47,8 @@ function Bootstrap({
})() })()
}, [hasLoadedSettings, persistedStorage, settings, userId]) }, [hasLoadedSettings, persistedStorage, settings, userId])
useEffect(() => {
document.title = title
}, [title])
return ( return (
<ShellContext.Provider value={shellContextValue}> <Shell>
<Box
className="Chitchatter"
sx={{
height: '100vh',
display: 'flex',
flexDirection: 'column',
paddingTop: 8,
}}
>
<Snackbar
open={isAlertShowing}
autoHideDuration={6000}
onClose={handleAlertClose}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
>
<Alert
onClose={handleAlertClose}
severity={alertSeverity}
variant="standard"
>
{alertText}
</Alert>
</Snackbar>
<AppBar position="fixed">
<Toolbar
variant="regular"
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<Typography variant="h6">{title}</Typography>
<Tooltip title="Number of peers in the room">
<StepIcon icon={numberOfPeers} sx={{ marginLeft: 'auto' }} />
</Tooltip>
</Toolbar>
</AppBar>
{hasLoadedSettings ? ( {hasLoadedSettings ? (
<Routes> <Routes>
{['/', '/index.html'].map(path => ( {['/', '/index.html'].map(path => (
@ -153,9 +59,10 @@ function Bootstrap({
element={<PublicRoom userId={userId} />} element={<PublicRoom userId={userId} />}
/> />
</Routes> </Routes>
) : null} ) : (
</Box> <></>
</ShellContext.Provider> )}
</Shell>
) )
} }

View File

@ -0,0 +1,110 @@
import {
forwardRef,
PropsWithChildren,
useCallback,
useEffect,
useMemo,
useState,
SyntheticEvent,
} from 'react'
import AppBar from '@mui/material/AppBar'
import Toolbar from '@mui/material/Toolbar'
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import StepIcon from '@mui/material/StepIcon'
import Tooltip from '@mui/material/Tooltip'
import Snackbar from '@mui/material/Snackbar'
import MuiAlert, { AlertProps, AlertColor } from '@mui/material/Alert'
import { ShellContext } from 'ShellContext'
import { AlertOptions } from 'models/shell'
interface ShellProps extends PropsWithChildren {}
const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(
props,
ref
) {
return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />
})
export const Shell = ({ children }: ShellProps) => {
const [isAlertShowing, setIsAlertShowing] = useState(false)
const [alertSeverity, setAlertSeverity] = useState<AlertColor>('info')
const [title, setTitle] = useState('')
const [alertText, setAlertText] = useState('')
const [numberOfPeers, setNumberOfPeers] = useState(1)
const showAlert = useCallback<
(message: string, options?: AlertOptions) => void
>((message, options) => {
setAlertText(message)
setAlertSeverity(options?.severity ?? 'info')
setIsAlertShowing(true)
}, [])
const shellContextValue = useMemo(
() => ({ numberOfPeers, setNumberOfPeers, setTitle, showAlert }),
[numberOfPeers, setNumberOfPeers, setTitle, showAlert]
)
const handleAlertClose = (
_event?: SyntheticEvent | Event,
reason?: string
) => {
if (reason === 'clickaway') {
return
}
setIsAlertShowing(false)
}
useEffect(() => {
document.title = title
}, [title])
return (
<ShellContext.Provider value={shellContextValue}>
<Box
className="Chitchatter"
sx={{
height: '100vh',
display: 'flex',
flexDirection: 'column',
paddingTop: 8,
}}
>
<Snackbar
open={isAlertShowing}
autoHideDuration={6000}
onClose={handleAlertClose}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
>
<Alert
onClose={handleAlertClose}
severity={alertSeverity}
variant="standard"
>
{alertText}
</Alert>
</Snackbar>
<AppBar position="fixed">
<Toolbar
variant="regular"
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<Typography variant="h6">{title}</Typography>
<Tooltip title="Number of peers in the room">
<StepIcon icon={numberOfPeers} sx={{ marginLeft: 'auto' }} />
</Tooltip>
</Toolbar>
</AppBar>
{children}
</Box>
</ShellContext.Provider>
)
}

View File

@ -0,0 +1 @@
export * from './Shell'