1- import { useChatHistoryQuery , useSendMessageMutation } from '@shared/apis/chatbot' ;
21import { Logo4 } from '@shared/assets/logo' ;
32import { ChatInput } from '@shared/ui/ChatInput' ;
43import { LoadingFallback } from '@shared/ui/LoadingFallback' ;
5- import { useEffect , useMemo , useRef } from 'react' ;
4+ import { useEffect , useRef } from 'react' ;
65import { ChatMessageList } from './ChatMessageList' ;
7- import type { ChatMessage } from '../model/types' ;
8-
9- const INITIAL_BOT_MESSAGE = `루핏이 예상 수리비를 빠르게 계산해드릴게요. 아래 3가지만 알려주세요.
10- (견적은 추정치이며 실제 비용은 수리점/부품/상태에 따라 달라질 수 있어요.)
11-
12- 기종: 예) 아이폰 15, 갤럭시 S23
13-
14- 어디가 고장났는지: 예) 액정/배터리/카메라/후면/충전/침수
15-
16- 보험/케어 가입 여부: 예) 애플케어 O/X, 통신사 보험 O/X
17-
18- 가능하면 원하는 방향도 한 줄로 적어주세요: "정품 우선" / "최대한 저렴하게" / "빨리"
19-
20- 예시) "아이폰 15, 액정 깨짐, 애플케어 X, 최대한 저렴하게"
21-
22- ` ;
6+ import { useChatMessages } from '../model/useChatMessages' ;
237
248const ChatbotPage = ( ) => {
25- const { data : history , isLoading : isHistoryLoading } = useChatHistoryQuery ( ) ;
26- const sendMutation = useSendMessageMutation ( ) ;
9+ const { displayMessages, isHistoryLoading, errorMessage, handleSend } = useChatMessages ( ) ;
2710 const endOfMessagesRef = useRef < HTMLDivElement | null > ( null ) ;
2811
29- const messages : ChatMessage [ ] = useMemo ( ( ) => {
30- if ( ! history || history . length === 0 ) {
31- return [
32- {
33- id : 'bot-initial' ,
34- role : 'bot' as const ,
35- content : INITIAL_BOT_MESSAGE ,
36- status : 'done' ,
37- } ,
38- ] ;
39- }
40-
41- return history . map ( ( item , index ) => ( {
42- id : `history-${ index } ` ,
43- role : item . role === 'User' ? ( 'user' as const ) : ( 'bot' as const ) ,
44- content : item . message ,
45- status : 'done' as const ,
46- } ) ) ;
47- } , [ history ] ) ;
48-
49- const displayMessages : ChatMessage [ ] = useMemo ( ( ) => {
50- if ( ! sendMutation . isPending ) {
51- return messages ;
52- }
53-
54- const pendingUserMessage : ChatMessage = {
55- id : 'pending-user' ,
56- role : 'user' ,
57- content : sendMutation . variables ?? '' ,
58- status : 'done' ,
59- } ;
60-
61- const loadingBotMessage : ChatMessage = {
62- id : 'pending-bot' ,
63- role : 'bot' ,
64- content : '' ,
65- status : 'loading' ,
66- } ;
67-
68- return [ ...messages , pendingUserMessage , loadingBotMessage ] ;
69- } , [ messages , sendMutation . isPending , sendMutation . variables ] ) ;
70-
7112 useEffect ( ( ) => {
7213 endOfMessagesRef . current ?. scrollIntoView ( { behavior : 'smooth' , block : 'end' } ) ;
73- } , [ displayMessages ] ) ;
74-
75- const handleSend = ( value : string ) => {
76- const trimmed = value . trim ( ) ;
77- if ( ! trimmed || sendMutation . isPending ) {
78- return ;
79- }
80-
81- sendMutation . mutate ( trimmed ) ;
82- } ;
14+ } , [ displayMessages . length ] ) ;
8315
8416 if ( isHistoryLoading ) {
8517 return < LoadingFallback message = "대화를 불러오는 중" /> ;
@@ -97,9 +29,7 @@ const ChatbotPage = () => {
9729 < h1 className = "typo-title-2 text-black" > 루핏봇</ h1 >
9830 </ div >
9931 < ChatMessageList messages = { displayMessages } />
100- { sendMutation . isError && (
101- < div className = "w-full text-center text-red-500" > 메시지 전송에 실패했습니다. 다시 시도해주세요.</ div >
102- ) }
32+ { errorMessage && < div className = "w-full text-center text-red-500" > { errorMessage } </ div > }
10333 < div ref = { endOfMessagesRef } className = "scroll-mb-[96px]" />
10434 </ section >
10535 < div className = "md:px-xxxl fixed inset-x-0 bottom-0 z-50 bg-white px-(--margin-l) pt-4 pb-(--margin-s) xl:px-[120px]" >
0 commit comments