From f90ff236c46e730a6a0073362dc28d8607efe6d9 Mon Sep 17 00:00:00 2001 From: Dormarble Date: Thu, 29 Apr 2021 21:26:45 +0900 Subject: [PATCH] =?UTF-8?q?[#54]=20=EC=B1=84=ED=8C=85=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/utils/api.js | 2 + src/views/chat/chatMessage.jsx | 6 +- src/views/chat/index.jsx | 136 +++++++++++++++++++++++++++------ 4 files changed, 118 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 3a5bc38..ed1170a 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "sass-loader": "^11.0.1", "socket.io-client": "2.3.1", "style-loader": "^2.0.0", + "uuid": "3.4.0", "web-vitals": "^1.1.0", "webpack": "^5.24.2", "webpack-cli": "^4.5.0", diff --git a/src/utils/api.js b/src/utils/api.js index b928e0c..ac2ff94 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -60,8 +60,10 @@ export const API_GET_ALL_NOTICES = makeAPI(GET, '/notice/all'); export const API_CREATE_NOTICE = makeAPI(POST, '/notice'); export const API_UPDATE_NOTICE = makeAPI(PATCH, '/notice'); export const API_DELETE_NOTICE = makeAPI(DELETE, '/notice'); +export const API_FIND_CHATROOM = makeAPI(GET, '/chatRoom'); export const API_FIND_CHATROOMS = makeAPI(GET, '/chatRoom'); export const API_GET_MESSAGES = makeAPI(GET, '/chatRoom/messages'); +export const API_GET_POINTS = makeAPI(GET, '/chatRoom/points'); export const API_GET_ALL_LECTURES = makeAPI(GET, '/lecture'); export const API_UPDATE_LECTURES = makeAPI(PATCH, '/lecture'); export const API_GET_HISTORIES = makeAPI(GET, '/history'); diff --git a/src/views/chat/chatMessage.jsx b/src/views/chat/chatMessage.jsx index 89c610b..aaa1f51 100644 --- a/src/views/chat/chatMessage.jsx +++ b/src/views/chat/chatMessage.jsx @@ -1,12 +1,14 @@ import { Container } from '@material-ui/core'; +import dayjs from 'dayjs'; import React from 'react'; -export default function ChatMessage({from, message, readCnt}) { +export default function ChatMessage({idx, from, message, readCnt}) { + const time = dayjs(message.date).format('HH:mm') return ( {from} {message.content} - {message.date} + {time} {readCnt > 0 ? readCnt : null } ); diff --git a/src/views/chat/index.jsx b/src/views/chat/index.jsx index 375f5a5..9bb5e42 100644 --- a/src/views/chat/index.jsx +++ b/src/views/chat/index.jsx @@ -1,63 +1,139 @@ import React, { useEffect, useRef, useState } from 'react'; import { Button, Container, Typography } from '@material-ui/core'; import queryString from 'query-string'; -import { useRecoilState } from 'recoil'; -import { chatroomState } from '../../states/Chatroom'; +import { v4 as uuidv4 } from 'uuid'; import { Redirect } from 'react-router'; -import { API_GET_MESSAGES, requestAPI } from '../../utils/api'; +import { API_FIND_CHATROOM, API_GET_MESSAGES, API_GET_POINTS, requestAPI } from '../../utils/api'; import { StatusCodes } from 'http-status-codes'; import ChatMessage from './chatMessage'; import { getSocket } from '../../utils/socket'; export default function Chatroom({location}) { - const [chatroomList, setChatroomList] = useRecoilState(chatroomState); + const [chatRoom, setChatRoom] = useState({}); const [input, setInput] = useState(''); const [messages, setMessages] = useState([]); const [readPoints, setReadPoints] = useState([]); const [emptyMsg, setEmptyMsg] = useState(''); - const query = queryString.parse(location.search) - const chatRoom = chatroomList.find(chatroom => chatroom._id === query.id); + const chatRoomId = queryString.parse(location.search).id; - if(!chatRoom) { - return + if(chatRoom === null) { + return ; } - const length = useRef(chatRoom.length); const range = useRef({start: 0, end: 0}); const messageRef = useRef([]); + const readPointRef = useRef([]); + const chatRoomRef = useRef({}); const userId = window.localStorage.getItem('userID'); const socket = getSocket(); const onMessageEvent = (message) => { - length.current++; + const newChatRoom = { + ...chatRoomRef.current, + length: length+1 + }; + setChatRoom(newChatRoom); + chatRoomRef.current = newChatRoom; range.current.end++; - setMessages(messageRef.current.concat(message)); - messageRef.current = messageRef.current.concat(message); - } + let newMessages; + if(message.from === userId) { + newMessages = messageRef.current.map(m => { + if(m.id === message.id) { + return message; + } + return m; + }) + } else { + newMessages = messageRef.current.concat(message); + } + console.log(newMessages) + setMessages(newMessages); + messageRef.current = newMessages; + + socket.emit('read', { + chatRoomId: chatRoomId, + userId: userId, + messageIdx: range.current.end + }); + }; + + const onReadEvent = (read) => { + const updatedReadPoints = readPointRef.current.map(point => { + if(point.id === read.userId) { + return { + ...point, + read: read.messageIdx + }; + } + return point; + }); + + setReadPoints(updatedReadPoints); + readPointRef.current = updatedReadPoints; + }; useEffect(() => { socket.on('message', onMessageEvent); + socket.on('read', onReadEvent); + + const getChatRoom = async (chatRoomId) => { + const response = await requestAPI(API_FIND_CHATROOM().setPathParam(chatRoomId)); + + if(response.status !== StatusCodes.OK) { + setEmptyMsg('데이터를 불러오는데 실패했습니다.'); + setChatRoom(null); + chatRoomRef.current = null; + return; + } + + setChatRoom(response.data); + chatRoomRef.current = response.data; + + return response.data; + } const getMessages = async (chatRoomId, start, end) => { + if(end < 0) return; + const response = await requestAPI(API_GET_MESSAGES().setQuery({chatRoomId, start, end})); if(response.status !== StatusCodes.OK) { - setEmptyMsg('메시지를 불러오는데 실패했습니다.'); + setEmptyMsg('채팅을 불러오는데 실패했습니다.'); return; } setMessages(response.data); - messageRef.current = response.data + messageRef.current = response.data; }; - const start = length.current > 50 ? length.current-50 : 0; - const end = length.current > 0 ? length.current-1 : 0; + const getReadPoints = async (chatRoomId) => { + const response = await requestAPI(API_GET_POINTS().setQuery({chatRoomId})); - range.current = {start, end}; - length.current = end - start + 1; - getMessages(chatRoom._id, start, end); + if(response.status !== StatusCodes.OK) { + setEmptyMsg('데이터를 불러오는데 실패했습니다.'); + return; + } + setReadPoints(response.data); + readPointRef.current = response.data; + } + + getChatRoom(chatRoomId).then((room) => { + const start = room.length > 50 ? room.length-50 : 0; + const end = room.length > 0 ? room.length-1 : 0; + + range.current = {start, end}; + + getMessages(chatRoomId, start, end); + getReadPoints(chatRoomId); + + socket.emit('read', { + chatRoomId: chatRoomId, + userId: userId, + messageIdx: range.current.end + }); + }); }, []); @@ -73,7 +149,10 @@ export default function Chatroom({location}) { const send = () => { if(input.length > 0) { + const id = uuidv4(); + const messageEvent = { + id, chatRoomId: chatRoom._id, from: window.localStorage.getItem('userID'), type: 'normal', @@ -81,16 +160,23 @@ export default function Chatroom({location}) { } socket.emit('message', messageEvent); + + const newMessages = messageRef.current.concat(messageEvent); + setMessages(newMessages); + messageRef.current = newMessages; + + setInput(''); } + } const messageList = messages.map((m, idx) => { - const index = range.current.start + idx + const index = range.current.start + idx; const from = chatRoom.participants.find(p => p._id == m.from).name; - const readCnt = readPoints.filter(point => point.id !== userId) - .filter(point => point.idx < index) + const readCnt = readPoints.filter(point => point.id != m.from) + .filter(point => point.read < index) .length; - return ; + return ; }); return ( @@ -100,7 +186,7 @@ export default function Chatroom({location}) { { messageList } - +