Chat.tsx 1.87 KB
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';

export const Chat: React.FC = () => {
  const socket = useContext(SocketContext);
  const [ input, setInput ] = useState('');
  const [ chatLines, setChatLines ] = useState<ChatData[]>([]);
  const messageEndRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    socket.on(MessageType.ROOM_CHAT, (data: ChatData) => {
      setChatLines([...chatLines, data]);
    });

    return () => {
      socket.off(MessageType.ROOM_CHAT);
    }
  }, []);

  const handleAutoScroll = useCallback(() => {
    messageEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, []);
  
  useEffect(handleAutoScroll, [chatLines])

  const handleEnter = useCallback((e: React.KeyboardEvent) => {
    if (e.key === 'Enter') {
      setChatLines([...chatLines, { sender: 'me', message: input }]);
      
      const rawMessage: RawMessage = {
        type: MessageType.ROOM_CHAT,
        message: { message: input }
      }
      socket.emit('msg', rawMessage, () => {});

      setInput('');
    }
  }, [input]);

  return (
    <div className='w-5/12'>
      <div className='w-full h-80 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>
  );
}