diff --git a/client/src/api/axios.ts b/client/src/api/axios.ts index b4ae54ec..fa596df3 100644 --- a/client/src/api/axios.ts +++ b/client/src/api/axios.ts @@ -1,15 +1,12 @@ import axios, { AxiosResponse } from 'axios'; -import LocalStorage from './localStorage'; - import checkForToken from '@/utils/checkForToken'; +import LocalStorage from '@/utils/localStorage'; const { authVerify, storageData } = checkForToken(); -const accessToken = - typeof window !== 'undefined' ? storageData.state.accessToken : null; -const refreshToken = - typeof window !== 'undefined' ? storageData.state.refreshToken : null; +const accessToken = storageData?.state.accessToken; +const refreshToken = storageData?.state.refreshToken; export const instance = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_URL, diff --git a/client/src/components/inquiry/Chat.tsx b/client/src/components/inquiry/Chat.tsx index c68799ac..eb60d0a8 100644 --- a/client/src/components/inquiry/Chat.tsx +++ b/client/src/components/inquiry/Chat.tsx @@ -1,31 +1,42 @@ 'use client'; import { useRouter } from 'next/navigation'; -import { useEffect } from 'react'; +import { useEffect, useRef, useState } from 'react'; import InfiniteScroll from 'react-infinite-scroller'; +import { CompatClient, Stomp, StompSubscription } from '@stomp/stompjs'; +import SockJS from 'sockjs-client'; + import useUserStore from '@/stores/userStore'; import useChatStore from '@/stores/chatStore'; +import useScrollToBottom from '@/hooks/useScrollToBottom'; + import useChatMessageQuery from '@/hooks/query/useChatMessageQuery'; -import useNewChatAndExistChatConnect from '@/hooks/useNewChatAndExistChatConnect'; import { ChatInput, ChatBox } from '.'; import checkForToken from '@/utils/checkForToken'; +import { ChatInfo } from '@/types/data'; + interface ChatProps { role: 'user' | 'admin'; } export default function Chat({ role }: ChatProps) { + const client = useRef(); + + const [connected, setConnected] = useState(false); + const [chat, setChat] = useState([]); + const router = useRouter(); - const { roomId, message, isNewChatConnect, setMessage } = useChatStore(); - const { userId, displayName, setClear } = useUserStore(); + const { roomId, message, setMessage } = useChatStore(); + const { accessToken, refreshToken, userId, displayName, setClear } = + useUserStore(); - const { setConnected, setChat, client, scrollRef, chat, connected } = - useNewChatAndExistChatConnect(isNewChatConnect); + const scrollRef = useScrollToBottom(chat); const { data: messageList, @@ -35,6 +46,10 @@ export default function Chat({ role }: ChatProps) { const { authVerify } = checkForToken(); + const url = process.env.NEXT_PUBLIC_API_URL; + + let subscription: StompSubscription | undefined; + const newMessge = { senderId: +userId, chatRoomId: roomId, @@ -49,7 +64,9 @@ export default function Chat({ role }: ChatProps) { authVerify() === 'Refresh Token Expired' ) { return ( - alert('토큰이 만료되었습니다. 다시 로그인 해주시길 바랍니다.'), + alert( + '토큰이 만료되었습니다. 로그아웃 후 다시 로그인 해주시길 바랍니다.', + ), setConnected(false), setClear(), setMessage(''), @@ -58,7 +75,6 @@ export default function Chat({ role }: ChatProps) { } client?.current?.send(`/pub/chatRoom/send`, {}, JSON.stringify(newMessge)); - setMessage(''); }; @@ -68,6 +84,36 @@ export default function Chat({ role }: ChatProps) { } }, [messageList]); + useEffect(() => { + client.current = Stomp.over(() => new SockJS(`${url}/wss`)); + client.current.debug = () => {}; + client.current.connect( + { + Authorization: accessToken, + refresh: refreshToken, + }, + () => { + subscription = client?.current?.subscribe( + `/sub/chatRoom/${roomId}`, + (payload) => { + const receivedMessage: ChatInfo = JSON.parse(payload.body); + + setChat((previousChat) => [...previousChat, receivedMessage]); + }, + ); + + setConnected(true); + }, + ); + + return () => { + client.current?.disconnect(() => { + subscription?.unsubscribe(); + setConnected(false); + }); + }; + }, []); + return (
(); + + const [connected, setConnected] = useState(false); + const [chat, setChat] = useState([]); + const router = useRouter(); - const { message, roomId, isNewChatConnect, setMessage } = useChatStore(); - const { displayName, userId, setClear } = useUserStore(); + const { message, setMessage, roomId } = useChatStore(); + const { accessToken, refreshToken, displayName, userId, setClear } = + useUserStore(); - const { setConnected, client, scrollRef, chat, connected } = - useNewChatAndExistChatConnect(isNewChatConnect); + const scrollRef = useScrollToBottom(chat); const { authVerify } = checkForToken(); + const url = process.env.NEXT_PUBLIC_API_URL; + + let subscription: StompSubscription | undefined; + + const entryMessage = () => { + const adminId = 101; + + client?.current?.send( + `/pub/chatRoom/enter`, + {}, + JSON.stringify({ senderId: +userId, chatRoomId: +roomId, adminId }), + ); + }; + const newMessge = { senderId: +userId, chatRoomId: roomId, @@ -40,7 +64,9 @@ export default function NewChat({ role }: NewChatProps) { authVerify() === 'Refresh Token Expired' ) { return ( - alert('토큰이 만료되었습니다. 다시 로그인 해주시길 바랍니다.'), + alert( + '토큰이 만료되었습니다. 로그아웃 후 다시 로그인 해주시길 바랍니다.', + ), setConnected(false), setClear(), setMessage(''), @@ -49,10 +75,42 @@ export default function NewChat({ role }: NewChatProps) { } client?.current?.send(`/pub/chatRoom/send`, {}, JSON.stringify(newMessge)); - setMessage(''); }; + useEffect(() => { + if (roomId) { + client.current = Stomp.over(() => new SockJS(`${url}/wss`)); + client.current.debug = () => {}; + client.current.connect( + { + Authorization: accessToken, + refresh: refreshToken, + }, + () => { + subscription = client?.current?.subscribe( + `/sub/chatRoom/${roomId}`, + (payload) => { + const receivedMessage: ChatInfo = JSON.parse(payload.body); + + setChat((previousChat) => [...previousChat, receivedMessage]); + }, + ); + + entryMessage(); + setConnected(true); + }, + ); + } + + return () => { + client.current?.disconnect(() => { + subscription?.unsubscribe(); + setConnected(false); + }); + }; + }, [roomId]); + return (
{ - const client = useRef(); - const scrollRef = useRef(null); - - const [connected, setConnected] = useState(false); - const [chat, setChat] = useState([]); - - const { roomId, setIsNewChatConnect } = useChatStore(); - const { accessToken, refreshToken, userId } = useUserStore(); - - const url = process.env.NEXT_PUBLIC_API_URL; - - let subscription: StompSubscription | undefined; - - const entryMessage = () => { - const adminId = process.env.NEXT_PUBLIC_ADMIN_ID; - - client?.current?.send( - `/pub/chatRoom/enter`, - {}, - JSON.stringify({ senderId: +userId, chatRoomId: +roomId, adminId }), - ); - }; - - useEffect(() => { - if (!roomId) return; - - client.current = Stomp.over(() => new SockJS(`${url}/wss`)); - client.current.debug = () => {}; - client.current.connect( - { - Authorization: accessToken, - refresh: refreshToken, - }, - () => { - subscription = client?.current?.subscribe( - `/sub/chatRoom/${roomId}`, - (payload) => { - const receivedMessage: ChatInfo = JSON.parse(payload.body); - - setChat((previousChat) => [...previousChat, receivedMessage]); - }, - ); - - if (isNewChatConnect) { - entryMessage(); - } - - setConnected(true); - }, - ); - - return () => { - client.current?.disconnect(() => { - subscription?.unsubscribe(); - setConnected(false); - setIsNewChatConnect(false); - }); - }; - }, [roomId]); - - useEffect(() => { - if (!scrollRef.current) return; - - scrollRef.current.scrollTop = scrollRef.current.scrollHeight; - }, [chat]); - - return { setConnected, setChat, client, scrollRef, chat, connected }; -}; - -export default useNewChatAndExistChatConnect; diff --git a/client/src/hooks/useScrollToBottom.ts b/client/src/hooks/useScrollToBottom.ts new file mode 100644 index 00000000..49ae2150 --- /dev/null +++ b/client/src/hooks/useScrollToBottom.ts @@ -0,0 +1,17 @@ +import { useEffect, useRef } from 'react'; + +import { ChatInfo } from '@/types/data'; + +const useScrollToBottom = (chat: ChatInfo[]) => { + const scrollRef = useRef(null); + + useEffect(() => { + if (!scrollRef.current) return; + + scrollRef.current.scrollTop = scrollRef.current.scrollHeight; + }, [chat]); + + return scrollRef; +}; + +export default useScrollToBottom; diff --git a/client/src/stores/chatStore.ts b/client/src/stores/chatStore.ts index 23894330..ec8e9947 100644 --- a/client/src/stores/chatStore.ts +++ b/client/src/stores/chatStore.ts @@ -4,24 +4,20 @@ import { ChatList } from '@/types/data'; interface ChatState { chatList: ChatList[]; - selected: string; message: string; title: string; roomId: string; questionerId: string; isOpen: boolean; - isNewChatConnect: boolean; setChatList: (chatList: ChatList[]) => void; - setSelected: (selected: string) => void; setMessage: (message: string) => void; setTitle: (title: string) => void; setRoomId: (roomId: string) => void; setQuestionerId: (questionerId: string) => void; setIsOpen: (isOpen: boolean) => void; - setIsNewChatConnect: (isNewChat: boolean) => void; } const useChatStore = create((set) => ({ @@ -34,7 +30,6 @@ const useChatStore = create((set) => ({ questionerId: '', isOpen: false, - isNewChatConnect: false, setChatList: (chatList) => { set(() => ({ chatList })); @@ -63,10 +58,6 @@ const useChatStore = create((set) => ({ setIsOpen(isOpen) { set({ isOpen, selected: 'home' }); }, - - setIsNewChatConnect(isNewChatConnect) { - set({ isNewChatConnect }); - }, })); export default useChatStore; diff --git a/client/src/utils/checkForToken.ts b/client/src/utils/checkForToken.ts index b31c1223..854c15ea 100644 --- a/client/src/utils/checkForToken.ts +++ b/client/src/utils/checkForToken.ts @@ -1,12 +1,10 @@ -import LocalStorage from '@/api/localStorage'; +import LocalStorage from './localStorage'; const checkForToken = () => { const storageData = LocalStorage.getItem('user-key'); - const accessToken = - typeof window !== 'undefined' ? storageData.state.accessToken : null; - const refreshToken = - typeof window !== 'undefined' ? storageData.state.refreshToken : null; + const accessToken = storageData?.state.accessToken; + const refreshToken = storageData?.state.refreshToken; const parseJWT = (token: string | null) => { if (token) return JSON.parse(atob(token.split('.')[1])); diff --git a/client/src/api/localStorage.ts b/client/src/utils/localStorage.ts similarity index 100% rename from client/src/api/localStorage.ts rename to client/src/utils/localStorage.ts