11import { Logo4 } from '@shared/assets/logo' ;
22import { ChatInput } from '@shared/ui/ChatInput' ;
3- import { useEffect , useRef , useState } from 'react' ;
3+ import { LoadingFallback } from '@shared/ui/LoadingFallback' ;
4+ import { useEffect , useRef } from 'react' ;
45import { ChatMessageList } from './ChatMessageList' ;
5- import type { ChatMessage } from '../model/types' ;
6-
7- const INITIAL_BOT_MESSAGE = `루핏이 예상 수리비를 빠르게 계산해드릴게요. 아래 3가지만 알려주세요.
8- (견적은 추정치이며 실제 비용은 수리점/부품/상태에 따라 달라질 수 있어요.)
9-
10- 기종: 예) 아이폰 15, 갤럭시 S23
11-
12- 어디가 고장났는지: 예) 액정/배터리/카메라/후면/충전/침수
13-
14- 보험/케어 가입 여부: 예) 애플케어 O/X, 통신사 보험 O/X
15-
16- 가능하면 원하는 방향도 한 줄로 적어주세요: "정품 우선" / "최대한 저렴하게" / "빨리"
17-
18- 예시) “아이폰 15, 액정 깨짐, 애플케어 X, 최대한 저렴하게”
19-
20- ` ;
6+ import { useChatMessages } from '../model/useChatMessages' ;
217
228const ChatbotPage = ( ) => {
23- const [ message , setMessage ] = useState ( '' ) ;
24- const [ messages , setMessages ] = useState < ChatMessage [ ] > ( ( ) => [
25- {
26- id : 'bot-initial' ,
27- role : 'bot' as const ,
28- content : INITIAL_BOT_MESSAGE ,
29- status : 'done' ,
30- } ,
31- ] ) ;
32- const replyTimeoutRef = useRef < number | null > ( null ) ;
9+ const { displayMessages, isHistoryLoading, errorMessage, handleSend } = useChatMessages ( ) ;
3310 const endOfMessagesRef = useRef < HTMLDivElement | null > ( null ) ;
3411
35- useEffect ( ( ) => {
36- return ( ) => {
37- if ( replyTimeoutRef . current ) {
38- window . clearTimeout ( replyTimeoutRef . current ) ;
39- }
40- } ;
41- } , [ ] ) ;
42-
4312 useEffect ( ( ) => {
4413 endOfMessagesRef . current ?. scrollIntoView ( { behavior : 'smooth' , block : 'end' } ) ;
45- } , [ messages ] ) ;
46-
47- const handleSend = ( value : string ) => {
48- const trimmed = value . trim ( ) ;
49- if ( ! trimmed ) {
50- return ;
51- }
52-
53- const userId = `user-${ Date . now ( ) } ` ;
54- const botId = `bot-${ Date . now ( ) } ` ;
55- setMessages ( ( prev ) => [
56- ...prev ,
57- { id : userId , role : 'user' , content : trimmed , status : 'done' } ,
58- { id : botId , role : 'bot' , content : '답변을 준비 중이에요...' , status : 'loading' } ,
59- ] ) ;
60- setMessage ( '' ) ;
14+ } , [ displayMessages . length ] ) ;
6115
62- if ( replyTimeoutRef . current ) {
63- window . clearTimeout ( replyTimeoutRef . current ) ;
64- }
65- replyTimeoutRef . current = window . setTimeout ( ( ) => {
66- setMessages ( ( prev ) =>
67- prev . map ( ( item ) =>
68- item . id === botId
69- ? {
70- ...item ,
71- status : 'done' ,
72- content : '입력하신 내용으로 예상 수리비를 준비할게요.\n필요하면 기종/증상 상세를 더 알려주세요!' ,
73- }
74- : item
75- )
76- ) ;
77- } , 800 ) ;
78- } ;
16+ if ( isHistoryLoading ) {
17+ return < LoadingFallback message = "대화를 불러오는 중" /> ;
18+ }
7919
8020 return (
8121 < div className = "w-full bg-white" >
@@ -88,17 +28,13 @@ const ChatbotPage = () => {
8828 </ div >
8929 < h1 className = "typo-title-2 text-black" > 루핏봇</ h1 >
9030 </ div >
91- < ChatMessageList messages = { messages } />
31+ < ChatMessageList messages = { displayMessages } />
32+ { errorMessage && < div className = "w-full text-center text-red-500" > { errorMessage } </ div > }
9233 < div ref = { endOfMessagesRef } className = "scroll-mb-[96px]" />
9334 </ section >
9435 < 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]" >
9536 < div className = "mx-auto w-full max-w-full xl:max-w-[1200px]" >
96- < ChatInput
97- placeholder = "무슨 견적을 원하시나요?"
98- value = { message }
99- onChange = { setMessage }
100- onSend = { handleSend }
101- />
37+ < ChatInput placeholder = "무슨 견적을 원하시나요?" onSend = { handleSend } />
10238 </ div >
10339 </ div >
10440 </ main >
0 commit comments