import { PropsWithChildren, SyntheticEvent, useCallback, useContext, useEffect, useMemo, useState, } from 'react' import CssBaseline from '@mui/material/CssBaseline' import { ThemeProvider, createTheme } from '@mui/material/styles' import Box from '@mui/material/Box' import { AlertColor } from '@mui/material/Alert' import { ShellContext } from 'contexts/ShellContext' import { SettingsContext } from 'contexts/SettingsContext' import { AlertOptions } from 'models/shell' import { AudioState, VideoState, Peer } from 'models/chat' import { ErrorBoundary } from 'components/ErrorBoundary' import { Drawer } from './Drawer' import { UpgradeDialog } from './UpgradeDialog' import { ShellAppBar } from './ShellAppBar' import { NotificationArea } from './NotificationArea' import { RouteContent } from './RouteContent' import { PeerList } from './PeerList' import { QRCodeDialog } from './QRCodeDialog' export interface ShellProps extends PropsWithChildren { userPeerId: string appNeedsUpdate: boolean } export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => { const settingsContext = useContext(SettingsContext) const [isAlertShowing, setIsAlertShowing] = useState(false) const [isDrawerOpen, setIsDrawerOpen] = useState(false) const [isQRCodeDialogOpen, setIsQRCodeDialogOpen] = useState(false) const [doShowPeers, setDoShowPeers] = useState(false) const [alertSeverity, setAlertSeverity] = useState('info') const [title, setTitle] = useState('') const [alertText, setAlertText] = useState('') const [numberOfPeers, setNumberOfPeers] = useState(1) const [isPeerListOpen, setIsPeerListOpen] = useState(false) const [peerList, setPeerList] = useState([]) // except you const [tabHasFocus, setTabHasFocus] = useState(true) const [audioState, setAudioState] = useState(AudioState.STOPPED) const [videoState, setVideoState] = useState(VideoState.STOPPED) const showAlert = useCallback< (message: string, options?: AlertOptions) => void >((message, options) => { setAlertText(message) setAlertSeverity(options?.severity ?? 'info') setIsAlertShowing(true) }, []) const shellContextValue = useMemo( () => ({ numberOfPeers, tabHasFocus, setDoShowPeers, setNumberOfPeers, setTitle, showAlert, isPeerListOpen, setIsQRCodeDialogOpen, setIsPeerListOpen, peerList, setPeerList, audioState, setAudioState, videoState, setVideoState, }), [ isPeerListOpen, setIsQRCodeDialogOpen, numberOfPeers, peerList, tabHasFocus, setDoShowPeers, setNumberOfPeers, setTitle, showAlert, audioState, setAudioState, videoState, setVideoState, ] ) const colorMode = settingsContext.getUserSettings().colorMode const theme = useMemo( () => createTheme({ palette: { mode: colorMode, }, }), [colorMode] ) const handleAlertClose = ( _event?: SyntheticEvent | Event, reason?: string ) => { if (reason === 'clickaway') { return } setIsAlertShowing(false) } useEffect(() => { document.title = title }, [title]) useEffect(() => { const handleFocus = () => { setTabHasFocus(true) } const handleBlur = () => { setTabHasFocus(false) } window.addEventListener('focus', handleFocus) window.addEventListener('blur', handleBlur) return () => { window.removeEventListener('focus', handleFocus) window.removeEventListener('blur', handleBlur) } }, []) const handleDrawerOpen = () => { setIsDrawerOpen(true) } const handlePeerListClick = () => { setIsPeerListOpen(!isPeerListOpen) } const handleLinkButtonClick = async () => { await navigator.clipboard.writeText(window.location.href) shellContextValue.showAlert('Current URL copied to clipboard', { severity: 'success', }) } const handleDrawerClose = () => { setIsDrawerOpen(false) } const handleHomeLinkClick = () => { setIsDrawerOpen(false) } const handleAboutLinkClick = () => { setIsDrawerOpen(false) } const handleDisclaimerLinkClick = () => { setIsDrawerOpen(false) } const handleSettingsLinkClick = () => { setIsDrawerOpen(false) } const handleQRCodeDialogClose = () => { setIsQRCodeDialogOpen(false) } return ( {children} ) }