import React, { MutableRefObject, useEffect, useRef } from 'react'; import { Layout, Logo, Screens, Theme, Typography } from '@100mslive/types-prebuilt'; import { match } from 'ts-pattern'; import { HMSActions, HMSReactiveStore, HMSRoomProvider, HMSStatsStoreWrapper, HMSStoreWrapper, IHMSNotifications, selectIsConnectedToRoom, useHMSActions, useHMSStore, } from '@100mslive/react-sdk'; import { AppData } from './components/AppData/AppData'; // @ts-ignore: No implicit Any import AuthToken from './components/AuthToken'; import { ConferenceScreen } from './components/ConferenceScreen'; // @ts-ignore: No implicit Any import { ErrorBoundary } from './components/ErrorBoundary'; // @ts-ignore: No implicit Any import { Init } from './components/init/Init'; // @ts-ignore: No implicit Any import { KeyboardHandler } from './components/Input/KeyboardInputManager'; import { LeaveScreen } from './components/LeaveScreen'; import { MwebLandscapePrompt } from './components/MwebLandscapePrompt'; import { Notifications } from './components/Notifications'; import { PIPProvider } from './components/PIP/PIPProvider'; import { PreviewScreen } from './components/Preview/PreviewScreen'; // @ts-ignore: No implicit Any import { ToastContainer } from './components/Toast/ToastContainer'; import { Sheet } from './layouts/Sheet'; import { RoomLayoutContext, RoomLayoutProvider, useRoomLayout } from './provider/roomLayoutProvider'; import { DialogContainerProvider } from '../context/DialogContext'; import { Box } from '../Layout'; import { globalStyles, HMSThemeProvider } from '../Theme'; import { HMSPrebuiltContext } from './AppContext'; import { AppStateContext, PrebuiltStates, useAppStateManager } from './AppStateContext'; // @ts-ignore: No implicit Any import { FlyingEmoji } from './plugins/FlyingEmoji'; // @ts-ignore: No implicit Any import { RemoteStopScreenshare } from './plugins/RemoteStopScreenshare'; // @ts-ignore: No implicit Any import { useIsNotificationDisabled } from './components/AppData/useUISettings'; import { useAutoStartStreaming } from './components/hooks/useAutoStartStreaming'; import { useRoomLayoutLeaveScreen, useRoomLayoutPreviewScreen, } from './provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; // @ts-ignore: No implicit Any import { FeatureFlags } from './services/FeatureFlags'; // @ts-ignore: No implicit Any import { DEFAULT_PORTAL_CONTAINER } from './common/constants'; export type HMSPrebuiltOptions = { userName?: string; userId?: string; endpoints?: object; effectsSDKKey?: string; }; export type HMSPrebuiltProps = { roomCode?: string; logo?: Logo; typography?: Typography; themes?: Theme[]; options?: HMSPrebuiltOptions; screens?: Screens; authToken?: string; leaveOnUnload?: boolean; onLeave?: () => void; onJoin?: () => void; /** * @remarks * Specify css selectors for the HTML element to be used as container for dialogs. Affects the positioning and focus of dialogs. */ containerSelector?: string; }; export type HMSPrebuiltRefType = { hmsActions: HMSActions; hmsStore: HMSStoreWrapper; hmsStats: HMSStatsStoreWrapper; hmsNotifications: IHMSNotifications; }; export const HMSPrebuilt = React.forwardRef( ( { roomCode = '', authToken = '', containerSelector = DEFAULT_PORTAL_CONTAINER, logo, typography, themes, options: { userName = '', userId = '', endpoints } = {}, screens, leaveOnUnload = true, onLeave, onJoin, }, ref, ) => { const reactiveStore = useRef(); const [hydrated, setHydrated] = React.useState(false); useEffect(() => { setHydrated(true); const hms = new HMSReactiveStore(); const hmsStore = hms.getStore(); const hmsActions = hms.getActions(); const hmsNotifications = hms.getNotifications(); const hmsStats = hms.getStats(); hms.triggerOnSubscribe(); reactiveStore.current = { hmsActions, hmsStats, hmsStore, hmsNotifications, }; }, []); useEffect(() => { if (!ref || !reactiveStore.current) { return; } (ref as MutableRefObject).current = { ...reactiveStore.current }; }, [ref]); useEffect(() => { // leave room when component unmounts return () => { reactiveStore?.current?.hmsActions.leave(); }; }, []); const endpointsObj = endpoints as | { init: string; tokenByRoomCode: string; roomLayout: string; event: string; } | undefined; const tokenByRoomCodeEndpoint = endpointsObj?.tokenByRoomCode; const initEndpoint = endpointsObj?.init; const eventEndpoint = endpointsObj?.event; const roomLayoutEndpoint = endpointsObj?.roomLayout; const overrideLayout: Partial = { logo, themes, typography, screens, }; if (!roomCode && !authToken) { console.error(` HMSPrebuilt can be initialised by providing: either "roomCode" or "authToken". Please check if you are providing the above values for initialising prebuilt. `); throw Error('Incorrect initializing params for HMSPrebuilt component'); } if (!hydrated) { return null; } globalStyles(); return ( {data => { const layout = data?.layout; const theme: Theme = layout?.themes?.[0] || ({} as Theme); const { typography } = layout || {}; let fontFamily = ['sans-serif']; if (typography?.font_family) { fontFamily = [`${typography?.font_family}`, ...fontFamily]; } return ( ); }} ); }, ); HMSPrebuilt.displayName = 'HMSPrebuilt'; const AppStates = ({ activeState }: { activeState: PrebuiltStates }) => { const { isPreviewScreenEnabled } = useRoomLayoutPreviewScreen(); const { isLeaveScreenEnabled } = useRoomLayoutLeaveScreen(); useAutoStartStreaming(); return match({ activeState, isPreviewScreenEnabled, isLeaveScreenEnabled }) .with({ activeState: PrebuiltStates.PREVIEW, isPreviewScreenEnabled: true }, () => ) .with({ activeState: PrebuiltStates.LEAVE, isLeaveScreenEnabled: true }, () => ) .otherwise(() => ); }; const BackSwipe = () => { const isConnectedToRoom = useHMSStore(selectIsConnectedToRoom); const hmsActions = useHMSActions(); useEffect(() => { const onRouteLeave = async () => { if (isConnectedToRoom) { await hmsActions.leave(); } }; window.addEventListener('popstate', onRouteLeave); return () => { window.removeEventListener('popstate', onRouteLeave); }; }, [hmsActions, isConnectedToRoom]); return null; }; function AppRoutes({ authTokenByRoomCodeEndpoint, defaultAuthToken, }: { authTokenByRoomCodeEndpoint?: string; defaultAuthToken?: string; }) { const roomLayout = useRoomLayout(); const isNotificationsDisabled = useIsNotificationDisabled(); const { activeState, rejoin } = useAppStateManager(); return ( <> {activeState !== PrebuiltStates.LEAVE && } {!isNotificationsDisabled && } {roomLayout && activeState && } ); }