@@ -5,119 +5,126 @@ import remarkGfm from "remark-gfm";
55import rehypePrism from "rehype-prism" ;
66import { PlanChatProps } from "@/models" ;
77import {
8- Body1 ,
9- Button ,
10- Tag ,
11- ToolbarDivider
8+ Body1 ,
9+ Button ,
10+ Spinner ,
11+ Tag ,
12+ ToolbarDivider
1213} from "@fluentui/react-components" ;
1314import {
14- HeartRegular ,
15+ HeartRegular ,
1516} from "@fluentui/react-icons" ;
1617import { useRef , useState } from "react" ;
1718import ReactMarkdown from "react-markdown" ;
1819import "../../styles/PlanChat.css" ;
1920import "../../styles/Chat.css" ;
2021import "../../styles/prism-material-oceanic.css" ;
22+ import { TaskService } from "@/services/TaskService" ;
2123
2224const PlanChat : React . FC < PlanChatProps > = ( {
23- planData,
24- OnChatSubmit
25+ planData,
26+ input,
27+ loading,
28+ OnChatSubmit
29+
2530} ) => {
26- const messages = planData ?. messages || [ ] ;
27- const [ input , setInput ] = useState ( "" ) ;
28- const [ isTyping , setIsTyping ] = useState ( false ) ;
29- const [ showScrollButton , setShowScrollButton ] = useState ( false ) ;
30- const [ inputHeight , setInputHeight ] = useState ( 0 ) ;
31- const [ currentConversationId , setCurrentConversationId ] = useState < string | undefined > ( undefined ) ;
31+ const messages = planData ?. messages || [ ] ;
32+ const [ inputValue , setInput ] = useState ( input ) ;
33+ const [ isTyping , setIsTyping ] = useState ( false ) ;
34+ const [ showScrollButton , setShowScrollButton ] = useState ( false ) ;
35+ const [ inputHeight , setInputHeight ] = useState ( 0 ) ;
36+ const [ currentConversationId , setCurrentConversationId ] = useState < string | undefined > ( undefined ) ;
3237
33- const messagesContainerRef = useRef < HTMLDivElement > ( null ) ;
34- const inputContainerRef = useRef < HTMLDivElement > ( null ) ;
38+ const messagesContainerRef = useRef < HTMLDivElement > ( null ) ;
39+ const inputContainerRef = useRef < HTMLDivElement > ( null ) ;
3540
36- const sendMessage = async ( ) => { } ;
41+ const sendMessage = async ( ) => { } ;
3742
38- const scrollToBottom = ( ) => { } ;
43+ const scrollToBottom = ( ) => { } ;
44+ if ( ! planData ) return < Spinner size = "large" /> ;
45+ return (
46+ < div className = "chat-container" >
47+ < div className = "messages" ref = { messagesContainerRef } >
48+ < div className = "message-wrapper" >
49+ { messages . map ( ( msg , index ) => {
50+ const isHuman = msg . source . includes ( "human" ) ;
3951
40- return (
41- < div className = "chat-container" >
42- < div className = "messages" ref = { messagesContainerRef } >
43- < div className = "message-wrapper" >
44- { messages . map ( ( msg , index ) => {
45- const isHuman = msg . role === "user" || msg . role === "human" ;
52+ return (
53+ < div key = { index } className = { `message ${ isHuman ? "user" : "assistant" } ` } >
54+ { ! isHuman && (
55+ < div className = "plan-chat-header" >
56+ < div className = "plan-chat-speaker" >
57+ < span className = "speaker-name" > { TaskService . cleanTextToSpaces ( msg . source ) } </ span >
58+ < Tag size = "extra-small" shape = "rounded" appearance = "filled" className = "bot-tag" > BOT</ Tag >
59+ </ div >
60+ </ div >
61+ ) }
4662
47- return (
48- < div key = { index } className = { `message ${ msg . role } ` } >
49- { ! isHuman && (
50- < div className = "plan-chat-header" >
51- < div className = "plan-chat-speaker" >
52- < span className = "speaker-name" > HR Agent</ span >
53- < Tag size = "extra-small" shape = "rounded" appearance = "filled" className = "bot-tag" > BOT</ Tag >
54- </ div >
55- </ div >
56- ) }
63+ < Body1 >
64+ < div className = "plan-chat-message-content" >
65+ < ReactMarkdown remarkPlugins = { [ remarkGfm ] } rehypePlugins = { [ rehypePrism ] } >
66+ { msg . content || "" }
67+ </ ReactMarkdown >
5768
58- < Body1 >
59- < div className = "plan-chat-message-content" >
60- < ReactMarkdown remarkPlugins = { [ remarkGfm ] } rehypePlugins = { [ rehypePrism ] } >
61- { msg . content || "" }
62- </ ReactMarkdown >
69+ { ! isHuman && (
70+ < div className = "assistant-footer" >
71+ < div className = "assistant-actions" >
72+ < Button
73+ onClick = { ( ) => msg . content && navigator . clipboard . writeText ( msg . content ) }
74+ title = "Copy Response"
75+ appearance = "subtle"
76+ style = { { height : 28 , width : 28 } }
77+ icon = { < Copy /> }
78+ />
79+ < Tag size = "extra-small" > Sample data for demonstration purposes only.</ Tag >
80+ </ div >
81+ </ div >
82+ ) }
83+ </ div >
84+ </ Body1 >
85+ </ div >
86+ ) ;
87+ } ) }
88+ </ div >
6389
64- { ! isHuman && (
65- < div className = "assistant-footer" >
66- < div className = "assistant-actions" >
67- < Button
68- onClick = { ( ) => msg . content && navigator . clipboard . writeText ( msg . content ) }
69- title = "Copy Response"
70- appearance = "subtle"
71- style = { { height : 28 , width : 28 } }
72- icon = { < Copy /> }
73- />
74- < Tag size = "extra-small" > Sample data for demonstration purposes only.</ Tag >
75- </ div >
76- </ div >
77- ) }
78- </ div >
79- </ Body1 >
80- </ div >
81- ) ;
82- } ) }
83- </ div >
84-
85- { isTyping && (
86- < div className = "typing-indicator" >
87- < span > Thinking...</ span >
88- </ div >
89- ) }
90- </ div >
90+ { isTyping && (
91+ < div className = "typing-indicator" >
92+ < span > Thinking...</ span >
93+ </ div >
94+ ) }
95+ </ div >
9196
92- { showScrollButton && (
93- < Tag
94- onClick = { scrollToBottom }
95- className = "scroll-to-bottom plan-chat-scroll-button"
96- shape = "circular"
97- style = { { bottom : inputHeight } }
98- >
99- Back to bottom
100- </ Tag >
101- ) }
97+ { showScrollButton && (
98+ < Tag
99+ onClick = { scrollToBottom }
100+ className = "scroll-to-bottom plan-chat-scroll-button"
101+ shape = "circular"
102+ style = { { bottom : inputHeight } }
103+ >
104+ Back to bottom
105+ </ Tag >
106+ ) }
102107
103- < div ref = { inputContainerRef } className = "plan-chat-input-container" >
104- < div className = "plan-chat-input-wrapper" >
105- < ChatInput
106- value = { input }
107- onChange = { setInput }
108- onEnter = { sendMessage }
109- >
110- < Button
111- appearance = "transparent"
112- onClick = { sendMessage }
113- icon = { < Send /> }
114- disabled = { ! planData ?. hasHumanClarificationRequest || isTyping || ! input . trim ( ) }
115- />
116- </ ChatInput >
108+ < div ref = { inputContainerRef } className = "plan-chat-input-container" >
109+ < div className = "plan-chat-input-wrapper" >
110+ < ChatInput
111+ value = { inputValue }
112+ onChange = { setInput }
113+ onEnter = { ( ) => OnChatSubmit ( inputValue ) }
114+ disabledChat = { ! planData . enableChat }
115+ placeholder = "Add more info to this task..."
116+ >
117+ < Button
118+ appearance = "transparent"
119+ onClick = { sendMessage }
120+ icon = { < Send /> }
121+ disabled = { ! planData ?. enableChat || isTyping || ! input . trim ( ) }
122+ />
123+ </ ChatInput >
124+ </ div >
125+ </ div >
117126 </ div >
118- </ div >
119- </ div >
120- ) ;
127+ ) ;
121128} ;
122129
123130export default PlanChat ;
0 commit comments