Skip to content

Commit

Permalink
Merge pull request #83 from Plick-pop-in/feat/#2
Browse files Browse the repository at this point in the history
[feat/#2] 실시간 채팅 기본 구현(로컬)
  • Loading branch information
yeriinnn authored Jun 3, 2024
2 parents 3ed53bf + 0d8eca9 commit bfa0dd1
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 7 deletions.
25 changes: 22 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^2.2.3",
"@stomp/stompjs": "^7.0.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
Expand All @@ -22,6 +23,7 @@
"router-dom": "^2.2.11",
"sass": "^1.76.0",
"swiper": "^8.4.7",
"uuid": "^9.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
Binary file added src/assets/images/ic_chat_send.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 10 additions & 4 deletions src/component/live/Chat.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import "./css/Chat.css";
import ChatBox from "./ChatBox";
import ChatScreen from "./ChatScreen";

const Chat = () => {
return (
Expand All @@ -15,12 +16,17 @@ const Chat = () => {
</div>
</div>
<div className="chat-white-background">
<div className="user-chat-list">
<div className="user-chat-container">
<ChatBox
/>
<div style={{ display: "flex", flexDirection: "row" }}>
<div className="user-chat-list">
<div className="user-chat-container">
<ChatBox />
</div>
</div>
<div style={{ marginLeft: "40px", marginTop: "33px" }}>
<ChatScreen />
</div>
</div>
<div className="footer-margin" style={{ marginBottom: "20px" }} /> {/* 여기에 마진을 추가 */}
</div>
</div>
);
Expand Down
14 changes: 14 additions & 0 deletions src/component/live/ChatMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import "./css/ChatMessage.css";

const ChatMessage = ({ nickname, message, time }) => {
return (
<div className="chat-message">
<span className="user-nickname">{nickname}</span>
<div className="message-bubble">{message}</div>
<span className="message-time">{time}</span>
</div>
);
};

export default ChatMessage;
120 changes: 120 additions & 0 deletions src/component/live/ChatScreen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React, { useState, useEffect } from "react";
import ChatMessage from "./ChatMessage";
import { Client } from '@stomp/stompjs';
import "./css/ChatScreen.css";

const ChatScreen = () => {
const [messages, setMessages] = useState([]);
const [client, setClient] = useState(null);
const [inputMessage, setInputMessage] = useState("");

const handleMessage = (message) => {
console.log("받은 메시지: ", message.body); // 메시지 확인용 로그
const body = JSON.parse(message.body);

// ID를 사용하여 중복 확인
const existingMessage = messages.find(msg => msg.id === body.id);
if (!existingMessage) {
setMessages(prevMessages => {
const updatedMessages = [...prevMessages, body];
console.log("업데이트된 messages 상태: ", updatedMessages); // 상태 업데이트 확인용 로그
return updatedMessages;
});
}
};

useEffect(() => {
if (!client) {
const newClient = new Client({
brokerURL: "ws://localhost:8080/ws",
debug: function (str) {
console.log(str);
},
reconnectDelay: 5000,
heartbeatIncoming: 4000,
heartbeatOutgoing: 4000,
});

newClient.onConnect = () => {
console.log("웹소켓 연결 성공");
setClient(newClient);

newClient.subscribe('/sub/public', (message) => {
handleMessage(message);
});
};

newClient.onStompError = (error) => {
console.error("웹소켓 연결 에러:", error);
};

newClient.activate();
}

return () => {
if (client && client.connected) {
client.deactivate();
}
};
}, [client]);

useEffect(() => {
console.log("렌더링된 messages 상태: ", messages); // 상태 변화 확인용 로그
}, [messages]);

const sendMessage = () => {
if (client && client.connected) {
const chatMessage = {
type: "MESSAGE",
content: inputMessage,
sender: "사용자 닉네임",
time: new Date().toISOString()
};

console.log("보내는 메시지: ", chatMessage); // 메시지 전송 확인용 로그
client.publish({
destination: '/pub/chat.sendMessage',
body: JSON.stringify(chatMessage),
});
setInputMessage("");
} else {
console.error("STOMP 연결 실패");
}
};

return (
<div className="chat-screen">
<div className="chat-messages">
{messages.map((message, index) => {
console.log("렌더링할 메시지: ", message); // 렌더링 확인용 로그
return (
<ChatMessage
key={index}
nickname={message.sender}
message={message.content}
time={new Date(message.time).toLocaleString()} // ISO 8601 형식을 파싱하여 표시
/>
);
})}
</div>
<div className="chat-input">
<input
className="chat-input-box"
type="text"
placeholder="메시지를 입력하세요."
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
/>
<button
className="chat-input-button"
aria-label="전송"
onClick={sendMessage}
>

</button>
</div>
</div>
);
};

export default ChatScreen;
40 changes: 40 additions & 0 deletions src/component/live/css/ChatMessage.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.chat-message {
width: 345px;
height: auto;
flex-shrink: 0;
}

.user-nickname {
width: 345px;
height: 15.14px;
flex-shrink: 0;
font-family: "Pretendard-Regular";
font-size: 12px;
font-weight: 400;
line-height: 1.3333; /* 16px */
}

.message-bubble {
width: 372px;
height: auto;
flex-shrink: 0;
border-radius: 12px 12px 12px 0px;
background: #F7F7F7;
color: #626264;
text-align: left;
font-family: "Pretendard-Regular";
font-size: 12px;
font-weight: 400;
line-height: 16px;
padding: 8px;
margin-top: 5px;
}

.message-time {
font-family: "Pretendard-Regular";
font-size: 12px;
font-weight: 400;
line-height: 16px;
text-align: right;
display: block;
}
71 changes: 71 additions & 0 deletions src/component/live/css/ChatScreen.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
.chat-screen {
width: 915px;
height: 700px;
flex-shrink: 0;
background-color: white;
border: 1px solid #ccc;
border-radius: 10px;
overflow-y: auto;
padding: 10px;
margin-left: 20px;
position: relative;
}

.chat-message {
width: auto;
height: auto;
}

.chat-messages {
width: 100%;
height: 100%;
overflow-y: auto;
margin-bottom: 10px;
}


.chat-input {
width: 785px;
height: 48px;
flex-shrink: 0;
border-radius: 8px;
background: #F7F7F7;
position: absolute;
bottom: 63px;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}


.chat-input input {
flex: 1;
border: none;
outline: none;
background: none;
height: 100%;
padding: 0 10px;
font-size: 16px;
border-radius: 8px 0 0 8px;
}

.chat-input button {
width: 48px;
height: 48px;
flex-shrink: 0;
border-radius: 10px;
background: #47ABD9 url("/src/assets/images/ic_chat_send.png") no-repeat center;
background-size: 24px;
border: none;
cursor: pointer;
margin-left: 15px;
}

.chat-input button:hover {
background-color: #0056b3;
}

0 comments on commit bfa0dd1

Please sign in to comment.