Jeremy Kahn e597a667a1
feat(chat): [closes #13] Active typing indicators (#133)
* feat(typing-indicator): wire up handleMessageChange
* feat(typing-indicator): send typing: true status
* feat(typing-indicator): expire typing state
* feat(typing-indicator): update typing state received from peers
* refactor(shell): add updatePeer utility
* feat(typing-indicator): display peer typing status
* feat(typing-indicator): reset typing status when a message is sent
* feat(typing-indicator): move indicator below message form
* feat(typing-indicator): keep status text to one line
2023-07-27 21:06:35 -05:00

171 lines
4.7 KiB
TypeScript

import { useContext } from 'react'
import { useWindowSize } from '@react-hook/window-size'
import Collapse from '@mui/material/Collapse'
import Zoom from '@mui/material/Zoom'
import Box from '@mui/material/Box'
import Divider from '@mui/material/Divider'
import { v4 as uuid } from 'uuid'
import { rtcConfig } from 'config/rtcConfig'
import { trackerUrls } from 'config/trackerUrls'
import { RoomContext } from 'contexts/RoomContext'
import { ShellContext } from 'contexts/ShellContext'
import { MessageForm } from 'components/MessageForm'
import { ChatTranscript } from 'components/ChatTranscript'
import { useRoom } from './useRoom'
import { RoomAudioControls } from './RoomAudioControls'
import { RoomVideoControls } from './RoomVideoControls'
import { RoomScreenShareControls } from './RoomScreenShareControls'
import { RoomFileUploadControls } from './RoomFileUploadControls'
import { RoomVideoDisplay } from './RoomVideoDisplay'
import { RoomShowMessagesControls } from './RoomShowMessagesControls'
import { RoomHideRoomControls } from './RoomHideRoomControls'
import { TypingStatusBar } from './TypingStatusBar'
export interface RoomProps {
appId?: string
getUuid?: typeof uuid
password?: string
roomId: string
userId: string
}
export function Room({
appId = `${encodeURI(window.location.origin)}_${process.env.REACT_APP_NAME}`,
getUuid = uuid,
roomId,
password,
userId,
}: RoomProps) {
const {
isMessageSending,
handleInlineMediaUpload,
handleMessageChange,
messageLog,
peerRoom,
roomContextValue,
sendMessage,
showVideoDisplay,
} = useRoom(
{
appId,
trackerUrls,
rtcConfig,
password,
trackerRedundancy: 3,
},
{
roomId,
userId,
getUuid,
}
)
const handleMessageSubmit = async (message: string) => {
await sendMessage(message)
}
const showMessages = roomContextValue.isShowingMessages
const { showRoomControls } = useContext(ShellContext)
const [windowWidth, windowHeight] = useWindowSize()
const landscape = windowWidth > windowHeight
return (
<RoomContext.Provider value={roomContextValue}>
<Box
className="Room"
sx={{
height: '100%',
display: 'flex',
flexGrow: '1',
overflow: 'auto',
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
flexGrow: '1',
overflow: 'auto',
}}
>
<Collapse in={showRoomControls}>
<Box
sx={{
alignItems: 'flex-start',
display: 'flex',
justifyContent: 'center',
padding: 1,
overflowX: 'auto',
}}
>
<RoomAudioControls peerRoom={peerRoom} />
<RoomVideoControls peerRoom={peerRoom} />
<RoomScreenShareControls peerRoom={peerRoom} />
<RoomFileUploadControls
peerRoom={peerRoom}
onInlineMediaUpload={handleInlineMediaUpload}
/>
<Zoom in={showVideoDisplay} mountOnEnter unmountOnExit>
<span>
<RoomShowMessagesControls />
</span>
</Zoom>
<RoomHideRoomControls />
</Box>
</Collapse>
<Box
sx={{
display: 'flex',
flexDirection: landscape ? 'row' : 'column',
height: '100%',
width: '100%',
overflow: 'auto',
}}
>
{showVideoDisplay && (
<RoomVideoDisplay
userId={userId}
width="100%"
height={landscape || !showMessages ? '100%' : '60%'}
/>
)}
{showMessages && (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
flexGrow: '1',
width: showVideoDisplay && landscape ? '400px' : '100%',
height: landscape ? '100%' : '40%',
}}
>
<ChatTranscript
messageLog={messageLog}
userId={userId}
className="grow overflow-auto px-4"
/>
<Divider />
<Box>
<MessageForm
onMessageSubmit={handleMessageSubmit}
isMessageSending={isMessageSending}
onMessageChange={handleMessageChange}
/>
<TypingStatusBar />
</Box>
</Box>
)}
</Box>
</Box>
</Box>
</RoomContext.Provider>
)
}