Overnap

Merge branch 'feature/chat' into feature/room

1 +import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
2 +import SocketContext from '../../contexts/SocketContext';
3 +import { MessageType, RawMessage } from '../common/types';
4 +import { ChatLine } from './ChatLine';
5 +import { ChatData } from './types';
6 +
7 +export const Chat: React.FC = () => {
8 + const socket = useContext(SocketContext);
9 + const [ input, setInput ] = useState('');
10 + const [ chatLines, setChatLines ] = useState<ChatData[]>([]);
11 + const messageEndRef = useRef<HTMLDivElement | null>(null);
12 +
13 + useEffect(() => {
14 + const handleChatData = (message: RawMessage) => {
15 + if (message.type === MessageType.ROOM_CHAT) {
16 + setChatLines(oldChatLines => [...oldChatLines, message.message as ChatData]);
17 + }
18 + }
19 +
20 + socket.on('msg', handleChatData);
21 +
22 + return () => {
23 + socket.off('msg', handleChatData);
24 + }
25 + }, []);
26 +
27 + const handleAutoScroll = useCallback(() => {
28 + messageEndRef.current?.scrollIntoView({ behavior: 'smooth' });
29 + }, []);
30 +
31 + useEffect(handleAutoScroll, [chatLines])
32 +
33 + const handleEnter = useCallback((e: React.KeyboardEvent) => {
34 + if (e.key === 'Enter') {
35 + // setChatLines([...chatLines, { sender: 'me', message: input }]);
36 +
37 + const rawMessage: RawMessage = {
38 + type: MessageType.ROOM_CHAT,
39 + message: { message: input }
40 + }
41 + socket.emit('msg', rawMessage, () => {});
42 +
43 + setInput('');
44 + }
45 + }, [input]);
46 +
47 + return (
48 + <div className='w-4/12'>
49 + <div className='w-full h-80 rounded shadow flex flex-col overflow-y-scroll'>
50 + {chatLines.map((line, i) => (<ChatLine key={16383+i} chatData={line}/>))}
51 + <div ref={messageEndRef} />
52 + </div>
53 + <input className='w-full px-3 py-2 bg-white
54 + placeholder-gray-400 text-gray-700 text-sm
55 + rounded shadow outline-none focus:outline-none'
56 + placeholder='Enter the answer'
57 + onChange={e => setInput(e.target.value)}
58 + value={input}
59 + onKeyPress={handleEnter}></input>
60 + </div>
61 + );
62 +}
...\ No newline at end of file ...\ No newline at end of file
1 +import React from 'react';
2 +import { ChatData } from './types';
3 +
4 +interface ChatLineProps {
5 + chatData: ChatData;
6 +}
7 +
8 +export const ChatLine: React.FC<ChatLineProps> = ({ chatData }) => {
9 + return (
10 + <div className='w-full px-3 py-1.5 bg-white
11 + text-gray-700 text-sm'>{chatData.sender} : {chatData.message}</div>
12 + );
13 +}
...@@ -19,3 +19,8 @@ export interface UpdateRoomUser { ...@@ -19,3 +19,8 @@ export interface UpdateRoomUser {
19 ready: boolean; 19 ready: boolean;
20 }; 20 };
21 } 21 }
22 +
23 +export interface ChatData {
24 + sender: string;
25 + message: string;
26 +}
...\ No newline at end of file ...\ No newline at end of file
......
1 import React, { useContext } from 'react'; 1 import React, { useContext } from 'react';
2 import { useLocation } from 'react-router'; 2 import { useLocation } from 'react-router';
3 import { Main } from '../components/common/Main'; 3 import { Main } from '../components/common/Main';
4 +import { Chat } from '../components/room/Chat';
4 import { RoomInfo } from '../components/room/RoomInfo'; 5 import { RoomInfo } from '../components/room/RoomInfo';
5 import SocketContext from '../contexts/SocketContext'; 6 import SocketContext from '../contexts/SocketContext';
6 7
...@@ -8,6 +9,9 @@ export const Room: React.FC = () => { ...@@ -8,6 +9,9 @@ export const Room: React.FC = () => {
8 return ( 9 return (
9 <Main> 10 <Main>
10 <RoomInfo /> 11 <RoomInfo />
12 + <div className='w-full'>
13 + <Chat />
14 + </div>
11 </Main> 15 </Main>
12 ); 16 );
13 } 17 }
...\ No newline at end of file ...\ No newline at end of file
......