diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a1dfc49b..432b8c8e 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,7 +5,7 @@ import styled, { ThemeProvider } from "styled-components"; import { theme } from "@/styles/theme"; import Header from "@/components/common/Header"; import StyledComponentsRegistry from "@/libs/registry"; -import { use, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { Provider } from "react-redux"; import { AppStore, store } from "@/redux/store"; import { usePathname } from "next/navigation"; diff --git a/src/components/chat/MessageHeader.tsx b/src/components/chat/MessageHeader.tsx index 10e644d9..a3665daa 100644 --- a/src/components/chat/MessageHeader.tsx +++ b/src/components/chat/MessageHeader.tsx @@ -80,19 +80,23 @@ const MessageHeader = (props: MessageHeaderProps) => { > {chatEnterData.gameName} - {onlineFriends.includes(chatEnterData.memberId) ? ( + {chatEnterData?.friend && <> - 온라인 - + {onlineFriends.includes(chatEnterData.memberId) ? ( + <> + 온라인 + + + ) : ( + 오프라인 + )} - ) : ( - 오프라인 - )} + } ` width: 100%; position: relative; min-height: ${({ $type }) => ($type === "posting" ? "837px" : "880px")}; - height: auto; + max-height: ${({ $type }) => ($type === "posting" ? "837px" : "880px")}; height: 100%; margin: 50px; padding: 0 20px; diff --git a/src/components/createBoard/GameStyle.tsx b/src/components/createBoard/GameStyle.tsx index c22f06cf..88173401 100644 --- a/src/components/createBoard/GameStyle.tsx +++ b/src/components/createBoard/GameStyle.tsx @@ -44,14 +44,15 @@ const GameStyle = (props: GameStyleProps) => { useEffect(() => { setSelectedStyleIds(selectedStyles); }, [selectedStyles, setSelectedStyleIds]); + const selectedGameStyles = GAME_STYLE.filter(style => selectedStyleIds.includes(style.gameStyleId)) + .map(style => style.gameStyleName); return ( <> - {selectedStyles.map((styleId) => { - const style = GAME_STYLE.find((item) => item.gameStyleId === styleId); - return {style?.gameStyleName}; - })} + {selectedGameStyles.map((styleName, index) => ( + {styleName} + ))}
diff --git a/src/components/readBoard/ReadBoard.tsx b/src/components/readBoard/ReadBoard.tsx index b5d9f491..70344eb4 100644 --- a/src/components/readBoard/ReadBoard.tsx +++ b/src/components/readBoard/ReadBoard.tsx @@ -358,6 +358,7 @@ const ReadBoard = (props: ReadBoardProps) => { await deletePost(postId); await dispatch(setPostStatus("delete")); await dispatch(setCloseReadingModal()); + await dispatch(setPostStatus("")); } catch (error) { console.error(error); } @@ -470,9 +471,10 @@ const ReadBoard = (props: ReadBoardProps) => { } else { try { dispatch(setCloseReadingModal()); - if (!isPost) return; - dispatch(setChatRoomUuid(isPost.boardId)); - dispatch(openChatRoom()); + if (isPost) { + dispatch(setChatRoomUuid(isPost.boardId)); + dispatch(openChatRoom()); + } } catch (error) { console.error(error); } diff --git a/src/components/socket/SocketConnection.tsx b/src/components/socket/SocketConnection.tsx index 65cf4bca..268d07b3 100644 --- a/src/components/socket/SocketConnection.tsx +++ b/src/components/socket/SocketConnection.tsx @@ -3,7 +3,9 @@ import { useDispatch } from "react-redux"; import { socket } from "@/socket"; import useChatMessage from "@/hooks/useChatMessage"; import useChatFriend from "@/hooks/useChatFriend"; - +import { reissueToken } from "@/api/auth"; +import { getAccessToken } from "@/utils/storage"; +import { isTokenExpired } from "@/utils/auth"; const SocketConnection: React.FC = () => { const dispatch = useDispatch(); @@ -12,14 +14,45 @@ const SocketConnection: React.FC = () => { useChatFriend(); useEffect(() => { - function onConnect() { + const onConnect = () => { const socketId = socket?.id || ""; sessionStorage.setItem("gamegooSocketId", socketId); - } + }; - function onDisconnect() { + const onDisconnect = () => { console.error("소켓 끊김"); - } + }; + + const handleJwtExpiredError = async (data: any) => { + const { eventName, eventData } = data; + try { + const currentToken = getAccessToken(); + // 토큰이 없을 경우 토큰 재발급 + if (!currentToken || isTokenExpired(currentToken)) { + const response = await reissueToken(); + const newToken = response.result.refreshToken; + console.log('newToken', newToken); + socket?.emit(eventName, { ...eventData, token: newToken }); + } + } catch (error) { + console.error("토큰 재발급 실패:", error); + } + }; + + const handleConnectionJwtError = async () => { + try { + const currentToken = getAccessToken(); + + // 토큰이 없을 경우 토큰 재발급 + if (!currentToken || isTokenExpired(currentToken)) { + const response = await reissueToken(); + const newToken = response.result.refreshToken; + socket?.emit("connection-update-token", { token: newToken }); + } + } catch (error) { + console.error("토큰 재발급 실패:", error); + } + }; if (socket?.connected) { onConnect(); @@ -27,10 +60,13 @@ const SocketConnection: React.FC = () => { socket?.on("connect", onConnect); socket?.on("disconnect", onDisconnect); - + socket?.on("connection-jwt-error", handleConnectionJwtError); + socket?.on("jwt-expired-error", handleJwtExpiredError); return () => { socket?.off("connect", onConnect); socket?.off("disconnect", onDisconnect); + socket?.off("connection-jwt-error", handleConnectionJwtError); + socket?.off("jwt-expired-error", handleJwtExpiredError); }; }, [dispatch]); diff --git a/src/hooks/useChatFriend.ts b/src/hooks/useChatFriend.ts index 26e337e0..56c36de6 100644 --- a/src/hooks/useChatFriend.ts +++ b/src/hooks/useChatFriend.ts @@ -9,7 +9,7 @@ const useChatFriend = () => { useEffect(() => { // 소켓 연결되어 있지 않으면 소켓 연결 if (!socket) { - return connectSocket(); + connectSocket(); } const handleMemberInfo = (res: any) => { diff --git a/src/hooks/useChatList.ts b/src/hooks/useChatList.ts index 5cc76011..58584d8c 100644 --- a/src/hooks/useChatList.ts +++ b/src/hooks/useChatList.ts @@ -8,7 +8,7 @@ const useChatList = (setChatrooms: (chatrooms: ChatroomList[]) => void) => { useEffect(() => { // 소켓 연결되어 있지 않으면 소켓 연결 if (!socket) { - return connectSocket(); + connectSocket(); } const handleJoinedNewChatroom = async () => { diff --git a/src/hooks/useChatMessage.ts b/src/hooks/useChatMessage.ts index ee411f41..c81064e4 100644 --- a/src/hooks/useChatMessage.ts +++ b/src/hooks/useChatMessage.ts @@ -18,7 +18,7 @@ const useChatMessage = () => { useEffect(() => { // 소켓 연결되어 있지 않으면 소켓 연결 if (!socket) { - return connectSocket(); + connectSocket(); } const handleChatMessage = (res: any) => { diff --git a/src/utils/auth.tsx b/src/utils/auth.tsx new file mode 100644 index 00000000..9c074770 --- /dev/null +++ b/src/utils/auth.tsx @@ -0,0 +1,9 @@ +export const isTokenExpired = (token: string): boolean => { + if (!token) return true; + + const payload = JSON.parse(atob(token.split('.')[1])); + const expiryTime = payload.exp * 1000; + const currentTime = Date.now(); + + return currentTime > expiryTime; +}; \ No newline at end of file diff --git a/src/utils/storage.ts b/src/utils/storage.ts index e9deeb3a..d4d35fc7 100644 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -79,12 +79,12 @@ export const clearTokens = () => { localStorage.removeItem('refreshToken'); localStorage.removeItem('name'); localStorage.removeItem('profileImg'); + localStorage.removeItem('userId'); sessionStorage.removeItem('accessToken'); sessionStorage.removeItem('refreshToken'); sessionStorage.removeItem('name'); sessionStorage.removeItem('profileImg'); sessionStorage.removeItem('userId'); - sessionStorage.removeItem('userId'); }; /* 매칭 완료 여부 */