diff --git a/src/renderer/src/components/workspace/ai-chat-panel/ai-chat-panel.tsx b/src/renderer/src/components/workspace/ai-chat-panel/ai-chat-panel.tsx index ea83dfb..b916cb3 100644 --- a/src/renderer/src/components/workspace/ai-chat-panel/ai-chat-panel.tsx +++ b/src/renderer/src/components/workspace/ai-chat-panel/ai-chat-panel.tsx @@ -2,8 +2,9 @@ import { useState, useRef } from 'react' import ChatHeader from './chat-header' import ChatInput from './chat-input' import ChatMessage from './chat-message' -import { useChat } from '@ai-sdk/react' +import { useChat, Message } from '@ai-sdk/react' import { Sparkles } from 'lucide-react' +import TypingLoadingAnimation from './typing-loading-animation' const initialSuggestions = [ '가장 많이 팔린 상품 5개 보여줘', @@ -18,7 +19,7 @@ const initialSuggestions = [ */ export default function AiChatPanel(): React.JSX.Element { const [searchTerm, setSearchTerm] = useState('') - const { messages, input, handleInputChange, handleSubmit, setInput, isLoading } = useChat({ + const { messages, input, handleInputChange, setInput, isLoading, append } = useChat({ api: '/api/chat', streamProtocol: 'text', // TODO: AI 팀에서 받아올 때는 data로 변경해야함 initialMessages: [ @@ -32,18 +33,46 @@ export default function AiChatPanel(): React.JSX.Element { }) const textareaRef = useRef(null) + const [tempMessages, setTempMessages] = useState([]) + const [showTyping, setShowTyping] = useState(false) + const handleSuggestionClick = (suggestion: string): void => { setInput(suggestion) textareaRef.current?.focus() } + const handleSubmitCustom = async (e: React.FormEvent): Promise => { + e.preventDefault() + if (!input.trim()) return + + const userMessage: Message = { + id: `${Date.now()}`, + role: 'user', + content: input.trim() + } + + setTempMessages((prev) => [...prev, userMessage]) + setInput('') + setShowTyping(true) + + // TODO: 추후 AI 응답의 실제 완료 시점을 기반으로 로딩 애니메이션을 종료하도록 수정 필요 + setTimeout(() => { + append({ + role: 'user', + content: userMessage.content + }) + setTempMessages([]) + setShowTyping(false) + }, 5000) + } + console.log(messages) return (
- {messages.map((m, index) => ( + {[...messages, ...tempMessages].map((m, index) => (
{m.role === 'system' && index === 0 && ( @@ -64,13 +93,15 @@ export default function AiChatPanel(): React.JSX.Element { )}
))} + {showTyping && }
-
+
diff --git a/src/renderer/src/components/workspace/ai-chat-panel/chat-input.tsx b/src/renderer/src/components/workspace/ai-chat-panel/chat-input.tsx index c9b0ed6..2cddefb 100644 --- a/src/renderer/src/components/workspace/ai-chat-panel/chat-input.tsx +++ b/src/renderer/src/components/workspace/ai-chat-panel/chat-input.tsx @@ -5,6 +5,7 @@ interface ChatInputProps { value: string onChange: (e: React.ChangeEvent) => void isLoading: boolean + disabled: boolean } /** @@ -13,7 +14,7 @@ interface ChatInputProps { * @returns JSX.Element */ const ChatInput = forwardRef(function ChatInput( - { value, onChange, isLoading }, + { value, onChange, disabled }, ref ) { useEffect(() => { @@ -25,7 +26,7 @@ const ChatInput = forwardRef(function ChatI }, [value, ref]) const handleKeyDown = (e: React.KeyboardEvent): void => { - if (e.key === 'Enter' && !e.shiftKey && !isLoading) { + if (e.key === 'Enter' && !e.shiftKey && !disabled) { e.preventDefault() // The form submission is handled by the parent form's onSubmit e.currentTarget.form?.requestSubmit() @@ -40,10 +41,10 @@ const ChatInput = forwardRef(function ChatI value={value} onChange={onChange} onKeyDown={handleKeyDown} - placeholder={isLoading ? 'AI가 답변을 생성중입니다...' : '무엇이든 물어보세요!'} + placeholder={disabled ? 'AI가 답변을 생성중입니다...' : '무엇이든 물어보세요!'} className="self-stretch bg-transparent text-neutral-200 text-xs font-medium font-['Pretendard'] leading-[14px] placeholder:text-zinc-500 focus:outline-none resize-none max-h-[44px]" rows={1} - disabled={isLoading} + disabled={disabled} />
@@ -55,7 +56,7 @@ const ChatInput = forwardRef(function ChatI