Chat.tsx
2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
import SocketContext from '../../contexts/SocketContext';
import { MessageType, RawMessage } from '../common/types';
import { ChatLine } from './ChatLine';
import { ChatData } from './types';
interface ChatProps {
w: string;
h: string;
}
export const Chat: React.FC<ChatProps> = (props) => {
const socket = useContext(SocketContext);
const [ input, setInput ] = useState('');
const [ chatLines, setChatLines ] = useState<ChatData[]>([]);
const messageEndRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const handleChatData = (message: RawMessage) => {
if (message.type === MessageType.ROOM_CHAT) {
setChatLines(oldChatLines => [...oldChatLines, message.message as ChatData]);
}
}
socket.on('msg', handleChatData);
socket.on('msg', handleAcceptMessage);
socket.on('msg', handleFinishMessage);
return () => {
socket.off('msg', handleChatData);
socket.off('msg', handleAcceptMessage);
socket.on('msg', handleFinishMessage);
}
}, []);
const handleAutoScroll = useCallback(() => {
messageEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, []);
useEffect(handleAutoScroll, [chatLines])
const handleEnter = useCallback((e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
const rawMessage: RawMessage = {
type: MessageType.ROOM_CHAT,
message: { message: input }
}
socket.emit('msg', rawMessage, () => {});
setInput('');
}
}, [input]);
const handleAcceptMessage = useCallback((rawMessage: RawMessage) => {
if (rawMessage.type === MessageType.GAME_ACCEPT) {
const message: ChatData = {
sender: 'SYSTEM',
message: 'That\'s correct!'
};
setChatLines(oldChatLines => [...oldChatLines, message]);
}
}, []);
const handleFinishMessage = useCallback((rawMessage: RawMessage) => {
if (rawMessage.type === MessageType.GAME_FINISH_ROUND) {
const message: ChatData = {
sender: 'SYSTEM',
message: 'The round is over!'
};
setChatLines(oldChatLines => [...oldChatLines, message]);
}
}, []);
return (
<div className={props.w}>
<div className={`${props.h} w-full py-2 rounded shadow flex flex-col overflow-y-scroll`}>
{chatLines.map((line, i) => (<ChatLine key={16383+i} chatData={line}/>))}
<div ref={messageEndRef} />
</div>
<input className='w-full px-3 py-2 bg-white
placeholder-gray-400 text-gray-700 text-sm
rounded shadow outline-none focus:outline-none'
placeholder='Enter the answer'
onChange={e => setInput(e.target.value)}
value={input}
onKeyPress={handleEnter}></input>
</div>
);
}