diff --git a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/ActiveRoom.tsx b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/ActiveRoom.tsx index fceae45d2cc..00d17c8ada5 100644 --- a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/ActiveRoom.tsx +++ b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/ActiveRoom.tsx @@ -11,6 +11,7 @@ import { useLivekitState } from '../store/useLivekitState'; import { useServerUrl } from '../utils/useServerUrl'; import { useToken } from '../utils/useToken'; import { VideoConference } from './lib/VideoConference'; +import { MeetingContextProvider } from '../context/MeetingContext'; const UpdateRoom: React.FC = React.memo(() => { const room = useRoomContext(); @@ -71,7 +72,9 @@ export const ActiveRoom: React.FC = React.memo((props) => { audio={userChoices.audioEnabled} onDisconnected={onLeave} > - + + + diff --git a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/ControlBar.tsx b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/ControlBar.tsx index cb1f8722bc1..2b5fa1c09f6 100644 --- a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/ControlBar.tsx +++ b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/ControlBar.tsx @@ -15,6 +15,7 @@ import { Translate } from '../../translate'; import { useMediaQuery } from '../../utils/useMediaQuery'; import { ChatIcon } from './icons/ChatIcon'; import { LeaveIcon } from './icons/LeaveIcon'; +import { useMeetingContextState } from '../../context/MeetingContext'; /** @public */ export type ControlBarControls = { @@ -55,6 +56,7 @@ export function ControlBar({ variation, controls, ...props }: ControlBarProps) { setIsChatOpen(layoutContext?.widget.state?.showChat); } }, [layoutContext?.widget.state?.showChat]); + const setRightPanel = useMeetingContextState((state) => state.setRightPanel); const isTooLittleSpace = useMediaQuery( `(max-width: ${isChatOpen ? 1000 : 760}px)` ); @@ -134,10 +136,10 @@ export function ControlBar({ variation, controls, ...props }: ControlBarProps) { )} {visibleControls.chat && ( - + )} {visibleControls.leave && ( diff --git a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/VideoConference.tsx b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/VideoConference.tsx index 692c345512c..9c603efcc31 100644 --- a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/VideoConference.tsx +++ b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/VideoConference.tsx @@ -28,6 +28,7 @@ import { CarouselLayout } from './CarouselLayout'; import { ControlBar } from './ControlBar'; import { Chat } from './Chat'; import { FocusLayout } from './FocusLayout'; +import { useMeetingContextState } from '../../context/MeetingContext'; /** * @public @@ -60,6 +61,7 @@ export const VideoConference: React.FC = React.memo( }); const lastAutoFocusedScreenShareTrack = React.useRef(null); + const rightPanel = useMeetingContextState((state) => state.rightPanel); const tracks = useTracks( [ @@ -146,10 +148,9 @@ export const VideoConference: React.FC = React.memo( - + {rightPanel === 'chat' && ( + + )} )} diff --git a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/context/MeetingContext.tsx b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/context/MeetingContext.tsx new file mode 100644 index 00000000000..60235df8e17 --- /dev/null +++ b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/context/MeetingContext.tsx @@ -0,0 +1,28 @@ +import React, { PropsWithChildren, useContext, useMemo } from 'react'; +import { + MeetingState, + MeetingStateStoreType, + createMeetingStateStore, +} from '../store/meeting'; +import { useStore } from 'zustand'; + +const MeetingContext = React.createContext(null); + +export const MeetingContextProvider: React.FC = React.memo( + (props) => { + const store = useMemo(() => createMeetingStateStore(), []); + + return ( + + {props.children} + + ); + } +); +MeetingContextProvider.displayName = 'MeetingContextProvider'; + +export function useMeetingContextState(selector: (s: MeetingState) => T) { + const context = useContext(MeetingContext); + + return useStore(context, selector); +} diff --git a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/store/meeting.ts b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/store/meeting.ts new file mode 100644 index 00000000000..bffcb89e1cd --- /dev/null +++ b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/store/meeting.ts @@ -0,0 +1,25 @@ +import { createStore } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +export interface MeetingState { + rightPanel: 'chat' | 'member' | null; + setRightPanel: (panel: 'chat' | 'member' | null) => void; +} + +export function createMeetingStateStore() { + return createStore()( + immer((set, get) => ({ + rightPanel: null, + setRightPanel: (rightPanel) => { + if (get().rightPanel === rightPanel) { + // toggle + set({ rightPanel: null }); + } else { + set({ rightPanel }); + } + }, + })) + ); +} + +export type MeetingStateStoreType = ReturnType;