From 9def0b589ae5aca8f882b88a345939c7634b6dfc Mon Sep 17 00:00:00 2001 From: HanJul_01 <129282275+Hanjuri@users.noreply.github.com> Date: Tue, 10 Sep 2024 15:47:33 +0900 Subject: [PATCH] =?UTF-8?q?feat:=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=B5=9C=EC=A2=85=20=EB=B0=8F=20=EC=B1=84=ED=8C=85?= =?UTF-8?q?=EB=B0=A9=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eslint.config.js | 16 +- src/api/ChatListCall.js | 9 +- src/api/ChatMessageCall.js | 2 +- src/pages/chat/ChatMain.jsx | 14 +- src/pages/chat/ChatRoom.jsx | 175 ++++++++++---------- src/pages/chat/styled/ChatMessage.styled.js | 3 +- src/pages/chat/styled/ChatRoom.styled.js | 18 +- src/pages/join/JoinPage.jsx | 6 +- src/pages/join/KakaoLogin.jsx | 3 +- src/pages/join/KakoRedirect.jsx | 8 +- src/pages/join/styled/JoinPage.styled.js | 19 ++- 11 files changed, 145 insertions(+), 128 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 32d1f47..bcabad0 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,10 +1,8 @@ import reactRefresh from "eslint-plugin-react-refresh"; -import prettier from "eslint-config-prettier"; import prettierPlugin from "eslint-plugin-prettier"; import globals from "globals"; -import react from "@vitejs/plugin-react"; -import reactHooks from "@eslint/js"; -import js from "@eslint/js"; +import reactPlugin from "eslint-plugin-react"; +import reactHooksPlugin from "eslint-plugin-react-hooks"; export default [ { @@ -21,8 +19,8 @@ export default [ }, settings: { react: { version: "18.3" } }, plugins: { - react, - "react-hooks": reactHooks, + react: reactPlugin, + "react-hooks": reactHooksPlugin, "react-refresh": reactRefresh, prettier: prettierPlugin, }, @@ -32,10 +30,6 @@ export default [ "plugin:prettier/recommended", ], rules: { - ...js.configs.recommended.rules, - ...react.configs.recommended.rules, - ...react.configs["jsx-runtime"].rules, - ...reactHooks.configs.recommended.rules, "react/jsx-no-target-blank": "off", "react-refresh/only-export-components": [ "warn", @@ -44,4 +38,4 @@ export default [ "prettier/prettier": "error", }, }, -]; +]; \ No newline at end of file diff --git a/src/api/ChatListCall.js b/src/api/ChatListCall.js index 6ad2d52..088cd80 100644 --- a/src/api/ChatListCall.js +++ b/src/api/ChatListCall.js @@ -1,12 +1,13 @@ import axios from "axios"; import { instance } from "./instance.js"; -export const getChatList = async (username = "pjh1") => { +export const getChatList = async (username) => { try { - const response = await instance.get("/chat/rooms"); - console.log(response); + const response = await instance.get(`/chat/rooms?username=${username}`); + console.log('apicall',username, response); + return response; } catch (error) { console.error("Error fetching chat list!:", error.message); throw error; } -}; +}; \ No newline at end of file diff --git a/src/api/ChatMessageCall.js b/src/api/ChatMessageCall.js index e9ae5c2..a471674 100644 --- a/src/api/ChatMessageCall.js +++ b/src/api/ChatMessageCall.js @@ -13,7 +13,7 @@ export const getChatMessages = async (roomUUID, page = 0, size = 10) => { size // 페이지 당 메시지 수 } }); - return response.data; + return response; } catch (error) { console.error("채팅방 메세지 불러오기 실패:", error.message); throw error; diff --git a/src/pages/chat/ChatMain.jsx b/src/pages/chat/ChatMain.jsx index a580a95..891185b 100644 --- a/src/pages/chat/ChatMain.jsx +++ b/src/pages/chat/ChatMain.jsx @@ -10,16 +10,16 @@ import dummyChatList from "./dummyChatData/dummyChatList"; function ChatMain() { const [chatList, setChatList] = useState([]) const [selectedChatRoom, setSelectedChatRoom] = useState(null); - const nowUser = 'pjh2'; + const nowUser = 'user1'; useEffect(() => { const fetchChatList = async () => { try { - const response = await getChatList(nowUser); // 사용자 이름을 동적으로 설정 가능 - setChatList(response); - console.log('채팅방리스트 불러오기 성공', response); + const response = await getChatList(nowUser); + setChatList(response.data.data); + console.log('채팅방리스트 불러오기 성공', response.data.data); } catch (error) { console.error("채팅방리스트 불러오기 실패", error); } @@ -40,7 +40,7 @@ function ChatMain() { - {Array.isArray(dummyChatList)&&dummyChatList.map((eachChat, id) => ( + {Array.isArray(chatList)&&chatList.map((eachChat, id) => ( { @@ -49,8 +49,8 @@ function ChatMain() { diff --git a/src/pages/chat/ChatRoom.jsx b/src/pages/chat/ChatRoom.jsx index 144de93..221f880 100644 --- a/src/pages/chat/ChatRoom.jsx +++ b/src/pages/chat/ChatRoom.jsx @@ -1,79 +1,81 @@ import React, { useEffect, useState } from "react"; -import * as Stomp from 'stompjs'; import SockJS from "sockjs-client"; +import * as Stomp from "stompjs"; import * as styles from "./styled/ChatRoom.styled"; import Text from "../../components/Common/Text"; import ChatMessage from "./ChatMessage.jsx"; import { getChatMessages } from "../../api/ChatMessageCall.js"; -import dummyChatMessages from "./dummyChatData/dummyChatMessages1"; const ChatRoom = (props) => { const { uuid, name } = props; const [messages, setMessages] = useState([]); const [message, setMessage] = useState(""); - const [stompClient, setStompClient] = useState(null); - - const currentUsername = '홍창기'; // 현재 사용자를 pjh2로 가정 - - const roomId = props.uuid; - - // 채팅방 메세지 데이터 가져오기 - useEffect(() => { - const fetchMessages = async () => { - try { - const response = await getChatMessages(uuid, 0, 10); - // 메시지 데이터에 isCurrentUser 추가 - const modifiedMessages = Array.isArray(response.data) - ? response.data.map((msg) => ({ - ...msg, - isCurrentUser: msg.username === currentUsername, - })) - : []; - setMessages(modifiedMessages); - console.log("채팅방 메세지 데이터:", modifiedMessages, response); - } catch (error) { - console.error("Failed to fetch chat messages", error); - } - }; - fetchMessages(); - }, [roomId]); - - // 실시간 웹소켓 연결 및 메세지 보내기 - useEffect(() => { - const newSocket = io(import.meta.env.VITE_BASE_URL, { - path: "/chat/ws", // 서버에서 설정한 경로로 수정 - query: { roomId: uuid }, - }); - - setSocket(newSocket); - - newSocket.on("connect", () => { - console.log("WebSocket에 연결되었습니다!"); - }); - - newSocket.on("message", (chatMessage) => { - console.log("WebSocket 메세지 수신", chatMessage); - setMessages((prevMessages) => [ - ...prevMessages, - { - id: chatMessage.id, - user: chatMessage.username, - message: chatMessage.message, - time: new Date().toLocaleTimeString(), - isCurrentUser: chatMessage.username === currentUsername, - }, - ]); - }); + const currentUsername = '홍창기'; // 현재 사용자 설정 + const roomId = uuid; + const [stompClient, setStompClient] = useState(null); // STOMP 클라이언트 객체 저장 + + // 채팅방 메시지 데이터 가져오기 + useEffect(() => { + const fetchMessages = async () => { + try { + const response = await getChatMessages(uuid, 0, 10); + const dataList = response.data.data; + const modifiedMessages = Array.isArray(dataList) + ? dataList.map((msg) => ({ + ...msg, + isCurrentUser: msg.username === currentUsername, + })) + : []; + modifiedMessages.sort((a, b) => new Date(a.sendAt) - new Date(b.sendAt)); + setMessages(modifiedMessages); + console.log("채팅방 메시지 데이터:", modifiedMessages); + } catch (error) { + console.error("Failed to fetch chat messages", error); + } + }; + fetchMessages(); + }, [uuid]); + + // WebSocket 연결 및 메시지 구독 + useEffect(() => { + const socket = new SockJS(`${import.meta.env.VITE_BASE_URL}chat/ws`); + const stompClient = Stomp.over(socket); + + stompClient.connect({}, () => { + console.log("STOMP WebSocket에 연결되었습니다!"); + // 구독 설정 (서버에서 채팅방 메시지를 수신) + stompClient.subscribe(`/sub/chat/room/${uuid}`, (message) => { + const chatMessage = JSON.parse(message.body); + console.log("WebSocket 메시지 수신", chatMessage); + + // 수신된 메시지를 메시지 리스트에 추가 + setMessages((prevMessages) => [ + ...prevMessages, + { + id: chatMessage.id, + username: chatMessage.username, + message: chatMessage.message, + time: new Date().toLocaleTimeString(), + isCurrentUser: chatMessage.username === currentUsername, + }, + ]); + }); + }); + + // STOMP 클라이언트 객체를 저장 + setStompClient(stompClient); + + // 연결 해제 시 클린업 return () => { - if (client) { - client.disconnect(() => { - console.log("WebSocket 연결 해제 되었습니다!"); - }); + if (stompClient) { + stompClient.disconnect(); + console.log("STOMP WebSocket 연결 해제 되었습니다!"); } }; - }, [uuid]); // uuid 변경될 때마다 재연결 + }, [uuid]); + // 메시지 전송 const sendMessage = () => { if (message.trim() === "" || !stompClient || !uuid) { return; @@ -86,32 +88,24 @@ const ChatRoom = (props) => { message: message, }; + // 서버로 메시지 발행 (전송) stompClient.send("/pub/messages", {}, JSON.stringify(chatMessage)); - setMessages(prevMessages => { - if (Array.isArray(prevMessages)) { - return [ - ...prevMessages, - { - id: Date.now(), // 임시로 고유 ID를 부여 - user: chatMessage.username, - text: chatMessage.message, - time: new Date().toLocaleTimeString(), - isCurrentUser: true, // 현재 사용자가 보낸 메시지이므로 true - } - ]; - } else { - return [{ - id: Date.now(), - user: chatMessage.username, - text: chatMessage.message, - time: new Date().toLocaleTimeString(), - isCurrentUser: true, - }]; - } - }); - - setMessage(""); + // 클라이언트에서 즉시 메시지 추가 + setMessages((prevMessages) => [ + ...prevMessages, + { + id: Date.now(), + username: chatMessage.username, + message: chatMessage.message, + time: new Date().toLocaleTimeString(), + isCurrentUser: true, + }, + ]); + + console.log("전송된 메시지:", chatMessage); + + setMessage(""); // 입력창 초기화 }; return ( @@ -122,14 +116,17 @@ const ChatRoom = (props) => { fontFamily="KakaoBold" fontSize={45} color="#000" - >{name} + > + {name} + - {Array.isArray(dummyChatMessages) && dummyChatMessages.map((each, id) => ( + {Array.isArray(messages) && messages.map((each, id) => ( ))} @@ -142,7 +139,7 @@ const ChatRoom = (props) => { value={message} onChange={(e) => setMessage(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && sendMessage()} - > + /> {'>'} @@ -150,4 +147,4 @@ const ChatRoom = (props) => { ); }; -export default ChatRoom; +export default ChatRoom; \ No newline at end of file diff --git a/src/pages/chat/styled/ChatMessage.styled.js b/src/pages/chat/styled/ChatMessage.styled.js index 5efed2a..6496b46 100644 --- a/src/pages/chat/styled/ChatMessage.styled.js +++ b/src/pages/chat/styled/ChatMessage.styled.js @@ -8,13 +8,14 @@ export const lineTotalWrapper = styled.div` flex-direction: row; margin-top: 6px; margin-left: 15px; + background-color: yellow; `; export const lineTotalWrapper2 = styled.div` height: auto; display: flex; flex-direction: row; justify-content: flex-end; - margin-top: 6px; + margin-top: 10px; margin-right: 15px; `; export const profileWrapper = styled.div` diff --git a/src/pages/chat/styled/ChatRoom.styled.js b/src/pages/chat/styled/ChatRoom.styled.js index 7a616ca..2b38cdf 100644 --- a/src/pages/chat/styled/ChatRoom.styled.js +++ b/src/pages/chat/styled/ChatRoom.styled.js @@ -9,6 +9,7 @@ export const TotalWrapper = styled.div` height: 100%; align-items: center; justify-content: flex-start; + `; export const NameWrapper = styled.div` @@ -18,12 +19,15 @@ export const NameWrapper = styled.div` background-color: #f8f7e1; align-items: center; justify-content: center; + border-radius: 20px; `; export const ChatRoomWrapper = styled.div` width: 100%; height: 80%; - background-color: white;`; + background: rgba(255, 255, 255, 0.5); + overflow-y:scroll; +`; export const BottomWrapper = styled.div` display: flex; @@ -31,7 +35,8 @@ export const BottomWrapper = styled.div` justify-content: center; width: 100%; height: 10%; - background-color:#f8f7e1 `; + border-radius: 20px; + background-color:#f8f7e1;`; export const InputWrapper = styled.div` display: flex; @@ -40,7 +45,7 @@ export const InputWrapper = styled.div` width: 85%; height: 90%; border-radius: 40px; - background-color: white; + background-color: rgba(255, 255, 255, 0.8); `; export const Input = styled.input` @@ -53,12 +58,13 @@ export const Input = styled.input` `; export const SendButton = styled.button` - width: 65px; - height: 65px; - background-color: yellow; + width: 55px; + height: 55px; + background-color: #f9e000; border-radius: 30px; border: none; margin: 5px; + font-size: 20px; &:active{ background-color: navajowhite; diff --git a/src/pages/join/JoinPage.jsx b/src/pages/join/JoinPage.jsx index ec8199a..6651fa6 100644 --- a/src/pages/join/JoinPage.jsx +++ b/src/pages/join/JoinPage.jsx @@ -32,6 +32,8 @@ function JoinPage(){ course, }; console.log(data); + localStorage.setItem("koreaName", koreaName); + try { const result = await postMemberData(data); // API 유틸리티 파일의 함수 호출 @@ -115,7 +117,7 @@ function JoinPage(){ > - + setCourse("FULLSTACK")}> - + diff --git a/src/pages/join/KakaoLogin.jsx b/src/pages/join/KakaoLogin.jsx index 3f0823f..a88f08a 100644 --- a/src/pages/join/KakaoLogin.jsx +++ b/src/pages/join/KakaoLogin.jsx @@ -12,10 +12,9 @@ function KakaoLogin() { useEffect(() => { const accessToken = localStorage.getItem("kakao_access_token"); - console.log(CLIENT_ID, REDIRECT_URL); + console.log(CLIENT_ID, REDIRECT_URL, accessToken); if (accessToken) { alert("이미 로그인 되어있습니다!"); - navigate("/join"); } if (!window.Kakao) { const script = document.createElement("script"); diff --git a/src/pages/join/KakoRedirect.jsx b/src/pages/join/KakoRedirect.jsx index 4d724c7..4525283 100644 --- a/src/pages/join/KakoRedirect.jsx +++ b/src/pages/join/KakoRedirect.jsx @@ -38,7 +38,13 @@ const KakaoRedirect = () => { } ); console.log("Access Token:", response.data.access_token); - // 받은 토큰을 localStorage 또는 백엔드로 전달 + // 쿠키에 Access Token 저장 + document.cookie = `kakao_access_token=${response.data.access_token}`; + + await axios.post('/api.kaboo.site:8081', { + access_token: response.data.access_token + }); + localStorage.setItem("kakao_access_token", response.data.access_token); navigate("/join") diff --git a/src/pages/join/styled/JoinPage.styled.js b/src/pages/join/styled/JoinPage.styled.js index 2f4af48..46629e9 100644 --- a/src/pages/join/styled/JoinPage.styled.js +++ b/src/pages/join/styled/JoinPage.styled.js @@ -71,20 +71,31 @@ export const InputWrapper = styled.div` justify-content:center; width: 70%; height: 50%; + border-radius: 20px; + border: 1.5px solid black; + +`; +export const InputWrapper2 = styled.div` + display: flex; + align-items: center; + justify-content:center; + width: 70%; + height: 50%; + `; export const Input = styled.input` width: 80%; - height: 95%; - border: 1.5px solid black; + height: 90%; outline: none; - border-radius: 20px; + border: none; font-size: 20px; + background-color: transparent; `; export const TeamButton = styled.button` -width: 25%; +width: 100px; height: 100%; border-radius: 15px; background-color:#FFF7AE;