/* eslint-disable react/no-invalid-html-attribute */ /* eslint-disable react/no-danger */ /* eslint-disable react/no-unescaped-entities */ import { useRecoilValue } from 'recoil'; import Head from 'next/head'; import { FC, useEffect, useRef, useState } from 'react'; import { Layout } from 'antd'; import dynamic from 'next/dynamic'; import Script from 'next/script'; import { ErrorBoundary } from 'react-error-boundary'; import { Footer } from '../../ui/Footer/Footer'; import { ClientConfigStore, isChatAvailableSelector, clientConfigStateAtom, fatalErrorStateAtom, appStateAtom, serverStatusState, isMobileAtom, isChatVisibleSelector, } from '../../stores/ClientConfigStore'; import { Content } from '../../ui/Content/Content'; import { Header } from '../../ui/Header/Header'; import { ClientConfig } from '../../../interfaces/client-config.model'; import { DisplayableError } from '../../../types/displayable-error'; import setupNoLinkReferrer from '../../../utils/no-link-referrer'; import { TitleNotifier } from '../../TitleNotifier/TitleNotifier'; import { ServerRenderedHydration } from '../../ServerRendered/ServerRenderedHydration'; import { Theme } from '../../theme/Theme'; import styles from './Main.module.scss'; import { PushNotificationServiceWorker } from '../../workers/PushNotificationServiceWorker/PushNotificationServiceWorker'; import { AppStateOptions } from '../../stores/application-state'; import { Noscript } from '../../ui/Noscript/Noscript'; import { ServerStatus } from '../../../interfaces/server-status.model'; // Lazy loaded components const FatalErrorStateModal = dynamic( () => import('../../modals/FatalErrorStateModal/FatalErrorStateModal').then( mod => mod.FatalErrorStateModal, ), { ssr: false, }, ); export const Main: FC = () => { const [displayFooter, setDisplayFooter] = useState(false); const clientConfig = useRecoilValue(clientConfigStateAtom); const clientStatus = useRecoilValue(serverStatusState); const { name } = clientConfig; const isChatAvailable = useRecoilValue(isChatAvailableSelector); const fatalError = useRecoilValue(fatalErrorStateAtom); const appState = useRecoilValue(appStateAtom); const isMobile = useRecoilValue(isMobileAtom); const isChatVisible = useRecoilValue(isChatVisibleSelector); const layoutRef = useRef(null); const { chatDisabled } = clientConfig; const { videoAvailable } = appState; const { online, streamTitle, versionNumber: version } = clientStatus; // accounts for sidebar width when online in desktop const showChat = online && !chatDisabled && isChatVisible; const dynamicPadding = showChat && !isMobile ? '340px' : '0px'; useEffect(() => { setupNoLinkReferrer(layoutRef.current); }, []); const handleScroll = () => { const documentHeight = document.body.scrollHeight; const currentScroll = window.scrollY + window.innerHeight; // When the user is [modifier]px from the bottom, fire the event. const modifier = 10; if (currentScroll + modifier > documentHeight) { if (!displayFooter) { setDisplayFooter(true); } } else { // eslint-disable-next-line no-lonely-if if (displayFooter) { setDisplayFooter(false); } } }; useEffect(() => { window.addEventListener('scroll', handleScroll); return () => { window.removeEventListener('scroll', handleScroll); }; }, [displayFooter]); const isProduction = process.env.NODE_ENV === 'production'; const headerText = online ? streamTitle || name : name; return ( <> {isProduction && } {isProduction ? ( {name ? {name} : {'{{.Name}}'}} ) : ( {name} )} ( )} >