diff --git a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/Chat.tsx b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/Chat.tsx index 948005a4b8d..b6e5df23e1d 100644 --- a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/Chat.tsx +++ b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/Chat.tsx @@ -2,21 +2,11 @@ import type { ChatMessage, ReceivedChatMessage, } from '@livekit/components-core'; -import { setupChat } from '@livekit/components-core'; -import { - ChatEntry, - MessageFormatter, - useRoomContext, -} from '@livekit/components-react'; +import { ChatEntry, MessageFormatter } from '@livekit/components-react'; import * as React from 'react'; import { Translate } from '../../translate'; import { cloneSingleChild } from '../../utils/common'; -import { useObservableState } from '../../utils/useObservableState'; -// import { useRoomContext } from '../context'; -// import { useObservableState } from '../hooks/internal/useObservableState'; -// import { cloneSingleChild } from '../utils'; -// import type { MessageFormatter } from '../components/ChatEntry'; -// import { ChatEntry } from '../components/ChatEntry'; +import { useChatContext } from './ChatContext'; export type { ChatMessage, ReceivedChatMessage }; @@ -25,22 +15,6 @@ export interface ChatProps extends React.HTMLAttributes { messageFormatter?: MessageFormatter; } -/** @public */ -export function useChat() { - const room = useRoomContext(); - const [setup, setSetup] = React.useState>(); - const isSending = useObservableState(setup?.isSendingObservable, false); - const chatMessages = useObservableState(setup?.messageObservable, []); - - React.useEffect(() => { - const setupChatReturn = setupChat(room); - setSetup(setupChatReturn); - return setupChatReturn.destroy; - }, [room]); - - return { send: setup?.send, chatMessages, isSending }; -} - /** * The Chat component adds a basis chat functionality to the LiveKit room. The messages are distributed to all participants * in the room. Only users who are in the room at the time of dispatch will receive the message. @@ -56,7 +30,7 @@ export function useChat() { export function Chat({ messageFormatter, ...props }: ChatProps) { const inputRef = React.useRef(null); const ulRef = React.useRef(null); - const { send, chatMessages, isSending } = useChat(); + const { send, chatMessages, isSending } = useChatContext(); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); diff --git a/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/ChatContext.tsx b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/ChatContext.tsx new file mode 100644 index 00000000000..965d4f8bca5 --- /dev/null +++ b/server/plugins/com.msgbyte.livekit/web/plugins/com.msgbyte.livekit/src/components/lib/ChatContext.tsx @@ -0,0 +1,47 @@ +import { useRoomContext } from '@livekit/components-react'; +import React, { useContext, useEffect, useState } from 'react'; +import { ReceivedChatMessage, setupChat } from '@livekit/components-core'; +import { useObservableState } from '../../utils/useObservableState'; + +const ChatContext = React.createContext({ + send: async (message: string) => {}, + chatMessages: [] as ReceivedChatMessage[], + isSending: false, +}); +ChatContext.displayName = 'ChatContext'; + +export const ChatProvider: React.FC = React.memo( + (props) => { + const chatContext = useSetupChat(); + + return ( + + {props.children} + + ); + } +); +ChatProvider.displayName = 'ChatProvider'; + +function useSetupChat() { + const room = useRoomContext(); + const [setup, setSetup] = useState>(); + const isSending = useObservableState(setup?.isSendingObservable, false); + const chatMessages = useObservableState( + setup?.messageObservable, + [] + ); + + useEffect(() => { + const setupChatReturn = setupChat(room); + setSetup(setupChatReturn); + + return setupChatReturn.destroy; + }, [room]); + + return { send: setup?.send, chatMessages, isSending }; +} + +export function useChatContext() { + return useContext(ChatContext); +} 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..ea2a52b2c98 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 { useChatContext } from './ChatContext'; /** @public */ export type ControlBarControls = { @@ -58,6 +59,7 @@ export function ControlBar({ variation, controls, ...props }: ControlBarProps) { const isTooLittleSpace = useMediaQuery( `(max-width: ${isChatOpen ? 1000 : 760}px)` ); + const { chatMessages } = useChatContext(); const defaultVariation = isTooLittleSpace ? 'minimal' : 'verbose'; variation ??= defaultVariation; @@ -137,6 +139,9 @@ export function ControlBar({ variation, controls, ...props }: ControlBarProps) { {showIcon && } {showText && Translate.chat} + {Array.isArray(chatMessages) && chatMessages.length > 0 && ( + ({chatMessages.length}) + )} )} 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..6f00a795a6d 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 { ChatProvider } from './ChatContext'; /** * @public @@ -124,32 +125,34 @@ export const VideoConference: React.FC = React.memo( // onPinChange={handleFocusStateChange} onWidgetChange={widgetUpdate} > -
- {!focusTrack ? ( -
- - - -
- ) : ( -
- - + +
+ {!focusTrack ? ( +
+ - + +
+ ) : ( +
+ + + + - {focusTrack && } - -
- )} + {focusTrack && } + +
+ )} - -
+ +
- + + )}