11import { useEffect , useRef , useState , ChangeEvent , KeyboardEvent } from "react" ;
2+ import { useLocation } from "react-router-dom" ;
23import IntroGuide from "@/components/IntroGuide" ;
34import Header from "@/components/header/Header" ;
45import ChatMessage from "@/components/ChatMessage" ;
56import ChatActionBar from "@/components/ChatActionBar" ;
6- import pickMbtiImage from "@/utils/pickMbtiImage" ;
7- import instance from "@/api/axios" ;
8- import { useLocation } from "react-router-dom" ;
97import TipsMenuContainer from "@/components/tips/TipsMenuContainer" ;
8+ import pickMbtiImage from "@/utils/pickMbtiImage" ;
9+ import { authInstance } from "@/api/axios" ;
1010import { trackEvent } from "@/libs/analytics" ;
1111
1212interface Message {
@@ -18,81 +18,107 @@ interface ChatResponse {
1818 data : string ;
1919}
2020
21+ interface GetChatHistoryAPIResponse {
22+ data : ChatHistoryResponse [ ] ;
23+ }
24+
25+ interface ChatHistoryResponse {
26+ messageContent : string ;
27+ virtualFriendId : number | null ;
28+ }
29+
2130const Chat = ( ) => {
2231 const { state } = useLocation ( ) ;
2332 const { mbti, mode, id = Date . now ( ) . toString ( ) , name } = state ;
2433
2534 const [ messages , setMessages ] = useState < Message [ ] > ( [ ] ) ;
2635 const [ input , setInput ] = useState ( "" ) ;
2736 const [ isOpen , setIsOpen ] = useState ( false ) ;
28- const bottomRef = useRef < HTMLDivElement | null > ( null ) ;
37+ const bottomRef = useRef < HTMLDivElement > ( null ) ;
2938
3039 const chatTitle = mode === "fastFriend" ? `${ mbti } 와 대화` : `${ name } 과 대화` ;
31- const assistantInfo = mbti ;
32- const assistantImgUrl = pickMbtiImage ( assistantInfo ) ;
40+ const assistantImgUrl = pickMbtiImage ( mbti ) ;
3341 const storageKey = `chatMessages_${ id } ` ;
3442
3543 useEffect ( ( ) => {
36- bottomRef . current ?. scrollIntoView ( { behavior : "smooth" } ) ;
37- } , [ messages , isOpen ] ) ;
44+ const fetchMessages = async ( ) => {
45+ if ( mode === "virtualFriend" ) {
46+ try {
47+ const virtualFriendChatHistory =
48+ await authInstance . get < GetChatHistoryAPIResponse > (
49+ `/api/message/${ id } `
50+ ) ;
51+ const chatHistory = virtualFriendChatHistory . data . data ;
52+
53+ const fetchedMessages : Message [ ] = chatHistory . map ( ( msg ) => ( {
54+ role : msg . virtualFriendId ? "assistant" : "user" ,
55+ content : msg . messageContent
56+ } ) ) ;
57+
58+ setMessages ( fetchedMessages ) ;
59+ } catch ( error ) {
60+ console . error ( "채팅 불러오기 실패" , error ) ;
61+ }
62+ } else {
63+ const storedMessage = sessionStorage . getItem ( storageKey ) ;
64+ if ( storedMessage ) {
65+ setMessages ( JSON . parse ( storedMessage ) ) ;
66+ }
67+ }
68+ } ;
69+
70+ fetchMessages ( ) ;
71+ } , [ mode , id , storageKey ] ) ;
3872
3973 useEffect ( ( ) => {
40- const stored = sessionStorage . getItem ( storageKey ) ;
41- if ( stored ) setMessages ( JSON . parse ( stored ) ) ;
42- } , [ storageKey ] ) ;
74+ if ( mode !== "virtualFriend" ) {
75+ sessionStorage . setItem ( storageKey , JSON . stringify ( messages ) ) ;
76+ }
77+ } , [ messages , mode , storageKey ] ) ;
4378
4479 useEffect ( ( ) => {
45- sessionStorage . setItem ( storageKey , JSON . stringify ( messages ) ) ;
46- } , [ messages , storageKey ] ) ;
80+ bottomRef . current ?. scrollIntoView ( { behavior : "smooth" } ) ;
81+ } , [ messages , isOpen ] ) ;
4782
4883 const handleToggleTips = ( ) => {
49- const nextAction = ! isOpen ;
50-
84+ const nextState = ! isOpen ;
5185 trackEvent ( "Click" , {
5286 page : "채팅방" ,
53- element : nextAction ? "콘텐츠 열기" : "콘텐츠 닫기"
87+ element : nextState ? "콘텐츠 열기" : "콘텐츠 닫기"
5488 } ) ;
55-
56- setIsOpen ( nextAction ) ;
89+ setIsOpen ( nextState ) ;
5790 } ;
5891
5992 const handleSend = async ( messageToSend : string ) => {
6093 if ( ! messageToSend . trim ( ) ) return ;
6194
62- const newMessages : Message [ ] = [
95+ const updatedMessages : Message [ ] = [
6396 ...messages ,
6497 { role : "user" , content : messageToSend }
6598 ] ;
66- setMessages ( newMessages ) ;
99+ setMessages ( updatedMessages ) ;
67100 setInput ( "" ) ;
68101
69102 try {
70- let url = "" ;
71- let payload = { } ;
72-
73- if ( mode === "fastFriend" ) {
74- url = "/api/fast-friend/message" ;
75- payload = { fastFriendId : id , content : messageToSend } ;
76- } else {
77- url = "/api/message" ;
78- payload = {
79- conversationId : id ,
80- messageContent : messageToSend
81- } ;
82- }
103+ const url =
104+ mode === "fastFriend" ? "/api/fast-friend/message" : "/api/message" ;
105+ const payload =
106+ mode === "fastFriend"
107+ ? { fastFriendId : id , content : messageToSend }
108+ : { conversationId : id , messageContent : messageToSend } ;
83109
84- const response = await instance . post < ChatResponse > ( url , payload ) ;
110+ const { data } = await authInstance . post < ChatResponse > ( url , payload ) ;
85111
86112 setMessages ( [
87- ...newMessages ,
113+ ...updatedMessages ,
88114 {
89115 role : "assistant" ,
90- content : response . data . data || "응답이 없어요"
116+ content : data . data || "응답이 없어요"
91117 }
92118 ] ) ;
93- } catch ( e ) {
119+ } catch ( error ) {
94120 setMessages ( [
95- ...newMessages ,
121+ ...updatedMessages ,
96122 { role : "assistant" , content : "오류가 발생했어요. 다시 시도해 주세요." }
97123 ] ) ;
98124 }
@@ -104,7 +130,7 @@ const Chat = () => {
104130
105131 const handleKeyup = ( e : KeyboardEvent < HTMLInputElement > ) => {
106132 if ( e . key === "Enter" ) {
107- handleSend ( e . currentTarget . value ) ;
133+ handleSend ( input ) ;
108134 }
109135 } ;
110136
@@ -115,12 +141,10 @@ const Chat = () => {
115141 < div className = "flex-1 space-y-4 overflow-y-auto px-[20px] pt-6" >
116142 < IntroGuide />
117143 { /* 메시지 리스트 */ }
118- { messages . map ( ( msg , index ) => (
144+ { messages . map ( ( msg , idx ) => (
119145 < div
120- key = { index }
121- className = { `flex ${
122- msg . role === "user" ? "justify-end" : "justify-start"
123- } items-start`}
146+ key = { idx }
147+ className = { `flex ${ msg . role === "user" ? "justify-end" : "justify-start" } items-start` }
124148 >
125149 { /* 캐릭터 아이콘 */ }
126150 { msg . role === "assistant" && (
0 commit comments