11'use client' ;
22
3- import { useEffect , useRef , useState } from 'react' ;
3+ import { useState } from 'react' ;
44import MessageInput from './user/MessageInput' ;
5- import {
6- fetchChatHistory ,
7- fetchGreeting ,
8- fetchSendStepMessage ,
9- fetchSendTextMessage ,
10- } from '../api/chat' ;
5+ import { fetchSendStepMessage , fetchSendTextMessage } from '../api/chat' ;
116import { useAuthStore } from '@/domains/shared/store/auth' ;
12- import {
13- ChatMessage ,
14- stepPayload ,
15- StepRecommendation ,
16- RecommendationItem ,
17- } from '../types/recommend' ;
7+ import { ChatMessage , stepPayload } from '../types/recommend' ;
188import ChatList from './ChatList' ;
9+ import { useChatInit } from '../hook/useChatInit' ;
10+ import { useSelectedOptions } from '../hook/useSelectedOptions' ;
1911
2012function ChatSection ( ) {
2113 const [ messages , setMessages ] = useState < ChatMessage [ ] > ( [ ] ) ;
22-
2314 const [ userCurrentStep , setUserCurrentStep ] = useState ( 0 ) ;
24- const [ isBotTyping , setIsBotTyping ] = useState ( false ) ;
15+ const { selectedOptions , setOption , setStepOption } = useSelectedOptions ( ) ;
2516
26- const selectedOptions = useRef < {
27- selectedAlcoholStrength ?: string ;
28- selectedAlcoholBaseType ?: string ;
29- selectedCocktailType ?: string ;
30- } > ( { } ) ;
17+ const isInputDisabled =
18+ selectedOptions . current . selectedSearchType !== 'QA' && userCurrentStep < 3 ;
3119
3220 const handleSendMessage = async ( payload : stepPayload | { message : string ; userId : string } ) => {
33- const typingTimer = setTimeout ( ( ) => setIsBotTyping ( true ) , 300 ) ;
34-
35- try {
36- if ( ! ( 'currentStep' in payload ) ) {
37- const botMessage = await fetchSendTextMessage ( payload ) ;
38- clearTimeout ( typingTimer ) ;
39- setIsBotTyping ( false ) ;
21+ const tempTypingId = `typing-${ Date . now ( ) } ` ;
4022
41- if ( ! botMessage ) return ;
42- setTimeout ( ( ) => setMessages ( ( prev ) => [ ...prev , botMessage ] ) , 500 ) ;
43- return ;
44- }
23+ // Typing 메시지 임시 추가
24+ setMessages ( ( prev ) => [
25+ ...prev ,
26+ {
27+ id : tempTypingId ,
28+ sender : 'CHATBOT' ,
29+ type : 'TYPING' ,
30+ message : '' ,
31+ createdAt : new Date ( ) . toISOString ( ) ,
32+ } ,
33+ ] ) ;
4534
46- const botMessage = await fetchSendStepMessage ( payload ) ;
47- clearTimeout ( typingTimer ) ;
48- setIsBotTyping ( false ) ;
35+ try {
36+ const botMessage =
37+ 'currentStep' in payload
38+ ? await fetchSendStepMessage ( payload )
39+ : await fetchSendTextMessage ( payload ) ;
4940
5041 if ( ! botMessage ) return ;
51- setTimeout ( ( ) => setMessages ( ( prev ) => [ ...prev , botMessage ] ) , 500 ) ;
42+
43+ setMessages ( ( prev ) => prev . map ( ( msg ) => ( msg . id === tempTypingId ? botMessage : msg ) ) ) ;
5244 } catch ( err ) {
53- clearTimeout ( typingTimer ) ;
54- setIsBotTyping ( false ) ;
5545 console . error ( err ) ;
46+ setMessages ( ( prev ) => prev . filter ( ( msg ) => msg . id !== tempTypingId ) ) ;
5647 }
5748 } ;
5849
@@ -70,7 +61,14 @@ function ChatSection() {
7061 { id : tempId , userId, message, sender : 'USER' , type : 'text' , createdAt : tempCreatedAt } ,
7162 ] ) ;
7263
73- await handleSendMessage ( { message, userId } ) ;
64+ const nextStep = userCurrentStep === 3 ? userCurrentStep + 1 : userCurrentStep ;
65+
66+ const payload : stepPayload =
67+ nextStep === 0
68+ ? { message, userId, currentStep : nextStep }
69+ : { message, userId, currentStep : nextStep , ...selectedOptions . current } ;
70+
71+ await handleSendMessage ( payload ) ;
7472 } ;
7573
7674 // 옵션 클릭 시
@@ -103,49 +101,26 @@ function ChatSection() {
103101 } ,
104102 ] ) ;
105103
104+ // QA (질문형) 일 시 0 나머지는 +1
106105 const nextStep = value === 'QA' ? 0 : ( stepData ?. currentStep ?? 0 ) + 1 ;
107106 setUserCurrentStep ( nextStep ) ;
108107
109- switch ( stepData . currentStep + 1 ) {
110- case 2 :
111- selectedOptions . current . selectedAlcoholStrength = value ;
112- break ;
113- case 3 :
114- selectedOptions . current . selectedAlcoholBaseType = value ;
115- break ;
108+ // 0단계에서 QA 선택 시
109+ if ( stepData . currentStep === 0 && value === 'QA' ) {
110+ setOption ( 'selectedSearchType' , 'QA' ) ;
116111 }
117112
118- const payload : stepPayload = {
119- message : selectedLabel ,
120- userId ,
121- currentStep : nextStep ,
122- ... selectedOptions . current ,
123- } ;
113+ setStepOption ( stepData . currentStep + 1 , value ) ;
114+
115+ const payload : stepPayload =
116+ nextStep === 0
117+ ? { message : selectedLabel , userId , currentStep : nextStep }
118+ : { message : selectedLabel , userId , currentStep : nextStep , ... selectedOptions . current } ;
124119
125120 await handleSendMessage ( payload ) ;
126121 } ;
127122
128- // 채팅 기록 불러오기 없으면 greeting 호출
129- useEffect ( ( ) => {
130- const loadChatHistory = async ( ) => {
131- const history = await fetchChatHistory ( ) ;
132- if ( history && history . length > 0 ) {
133- setMessages ( history . sort ( ( a , b ) => Number ( a . id ) - Number ( b . id ) ) ) ;
134- } else {
135- const greeting = await fetchGreeting ( '' ) ;
136- if ( greeting ) setMessages ( [ greeting ] ) ;
137- }
138- } ;
139- loadChatHistory ( ) ;
140- } , [ ] ) ;
141-
142- const getRecommendations = (
143- type : string | undefined ,
144- stepData ?: StepRecommendation | null
145- ) : RecommendationItem [ ] => {
146- if ( type !== 'CARD_LIST' || ! stepData ?. recommendations ) return [ ] ;
147- return stepData . recommendations ;
148- } ;
123+ useChatInit ( setMessages ) ;
149124
150125 return (
151126 < section className = "relative flex-1 flex flex-col items-center w-full" >
@@ -154,10 +129,8 @@ function ChatSection() {
154129 messages = { messages }
155130 userCurrentStep = { userCurrentStep }
156131 onSelectedOption = { handleSelectedOption }
157- getRecommendations = { getRecommendations }
158- isBotTyping = { isBotTyping }
159132 />
160- < MessageInput onSubmit = { handleSubmitText } />
133+ < MessageInput onSubmit = { handleSubmitText } disabled = { isInputDisabled } />
161134 </ section >
162135 ) ;
163136}
0 commit comments