1-
21import {
3- Body1 ,
4- Body1Strong ,
5- Button ,
6- Caption1 ,
7- Card ,
8- Text ,
9- Title2 ,
10- Toast ,
11- ToastBody ,
12- ToastTitle ,
2+ Body1 ,
3+ Body1Strong ,
4+ Button ,
5+ Caption1 ,
6+ Card ,
7+ Title2 ,
138} from "@fluentui/react-components" ;
14- import {
15- Send20Regular ,
16- } from "@fluentui/react-icons" ;
9+ import { FoodToast20Regular , Send20Regular } from "@fluentui/react-icons" ;
1710import React , { useRef , useEffect , useState } from "react" ;
18- import { useNavigate } from ' react-router-dom' ;
11+ import { useNavigate } from " react-router-dom" ;
1912import "./../../styles/HomeInput.css" ;
2013import "./../../styles/Chat.css" ;
21- import "../../styles/prism-material-oceanic.css"
14+ import "../../styles/prism-material-oceanic.css" ;
2215import { HomeInputProps , quickTasks , QuickTask } from "../../models/homeInput" ;
2316import { TaskService } from "../../services/TaskService" ;
2417import { NewTaskService } from "../../services/NewTaskService" ;
2518import ChatInput from "@/coral/modules/ChatInput" ;
26-
19+ import InlineToaster , { useInlineToaster } from "../toast/InlineToaster" ;
2720
2821const HomeInput : React . FC < HomeInputProps > = ( {
29- onInputSubmit,
30- onQuickTaskSelect,
22+ onInputSubmit,
23+ onQuickTaskSelect,
3124} ) => {
32- const [ input , setInput ] = useState ( "" ) ;
33- const [ submitting , setSubmitting ] = useState ( false ) ;
34- const [ showToast , setShowToast ] = useState ( false ) ;
35- const [ error , setError ] = useState < string | null > ( null ) ;
36- const textareaRef = useRef < HTMLTextAreaElement > ( null ) ;
37- const navigate = useNavigate ( ) ;
25+ const [ input , setInput ] = useState ( "" ) ;
26+ const textareaRef = useRef < HTMLTextAreaElement > ( null ) ;
27+ const navigate = useNavigate ( ) ;
28+ const { showToast } = useInlineToaster ( ) ;
29+
30+ const resetTextarea = ( ) => {
31+ setInput ( "" ) ;
32+ if ( textareaRef . current ) {
33+ textareaRef . current . style . height = "auto" ;
34+ textareaRef . current . focus ( ) ;
35+ }
36+ } ;
37+
38+ useEffect ( ( ) => {
39+ const cleanup = NewTaskService . addResetListener ( resetTextarea ) ;
40+ return cleanup ;
41+ } , [ ] ) ;
42+
43+ const handleSubmit = async ( ) => {
44+ if ( input . trim ( ) ) {
45+ try {
46+ const response = await TaskService . submitInputTask ( input . trim ( ) ) ;
3847
39- /**
40- * Reset textarea to empty state
41- */
42- const resetTextarea = ( ) => {
4348 setInput ( "" ) ;
4449 if ( textareaRef . current ) {
45- textareaRef . current . style . height = "auto" ;
46- textareaRef . current . focus ( ) ;
47- }
48- } ;
49-
50- // Listen for new task reset events
51- useEffect ( ( ) => {
52- const cleanup = NewTaskService . addResetListener ( resetTextarea ) ;
53- return cleanup ;
54- } , [ ] ) ;
55-
56- const handleSubmit = async ( ) => {
57- if ( input . trim ( ) ) {
58- setSubmitting ( true ) ;
59- setShowToast ( true ) ;
60- setError ( null ) ;
61- try {
62- // Submit the input task using TaskService
63- const response = await TaskService . submitInputTask ( input . trim ( ) ) ;
64-
65- // Clear the input field
66- //setInput("");
67- if ( textareaRef . current ) {
68- textareaRef . current . style . height = "auto" ;
69- }
70-
71- console . log ( 'Task response' , response ) ;
72- if ( response . plan_id != null ) {
73- // plan_id is valid (not null or undefined)
74- navigate ( `/plan/${ response . plan_id } ` ) ;
75- } else {
76- // plan_id is not valid, handle accordingly
77- console . log ( 'Invalid plan:' , response . status ) ;
78- setShowToast ( false ) ;
79- setError ( "Failed to create task. Please try again." ) ;
80- }
81-
82- } catch ( error : any ) {
83- console . log ( 'Failed to create task:' , error ) ;
84- setError ( error . message || "Failed to create task." ) ;
85- } finally {
86- setSubmitting ( false ) ;
87- }
88- }
89- } ;
90- const handleQuickTaskClick = ( task : QuickTask ) => {
91- // Copy task description to textarea
92- setInput ( task . description ) ;
93-
94- // Focus on textarea
95- if ( textareaRef . current ) {
96- textareaRef . current . focus ( ) ;
97- }
98-
99- // Call the onQuickTaskSelect with the task description
100- onQuickTaskSelect ( task . description ) ;
101- } ;
102-
103-
104- // Auto-resize textarea
105- useEffect ( ( ) => {
106- if ( textareaRef . current ) {
107- textareaRef . current . style . height = "auto" ;
108- textareaRef . current . style . height = `${ textareaRef . current . scrollHeight } px` ;
50+ textareaRef . current . style . height = "auto" ;
10951 }
110- } , [ input ] ) ;
11152
112- return (
113- < div className = "home-input-container" >
114- < div className = "home-input-content" >
115- < div className = "home-input-center-content" >
116- < div className = "home-input-title-wrapper" >
117- < Title2 > How can I help?</ Title2 >
53+ showToast ( "Task created!" , "success" ) ;
54+ navigate ( `/plan/${ response . plan_id } ` ) ;
55+ } catch ( error ) {
56+ console . error ( "Failed to create task:" , error ) ;
57+ showToast ( "Something went wrong" , "error" ) ;
58+ }
59+ }
60+ } ;
61+
62+ const handleQuickTaskClick = ( task : QuickTask ) => {
63+ setInput ( task . description ) ;
64+ if ( textareaRef . current ) {
65+ textareaRef . current . focus ( ) ;
66+ }
67+ onQuickTaskSelect ( task . description ) ;
68+ } ;
69+
70+ useEffect ( ( ) => {
71+ if ( textareaRef . current ) {
72+ textareaRef . current . style . height = "auto" ;
73+ textareaRef . current . style . height = `${ textareaRef . current . scrollHeight } px` ;
74+ }
75+ } , [ input ] ) ;
76+
77+ const handleClick = ( ) => {
78+ showToast ( "Creating a task plan..." , "error" , { dismissible : true } ) ;
79+ } ;
80+
81+ return (
82+ < div className = "home-input-container" >
83+ < div className = "home-input-content" >
84+ < div className = "home-input-center-content" >
85+ < div className = "home-input-title-wrapper" >
86+ < Title2 > How can I help?</ Title2 >
87+ </ div >
88+
89+ < ChatInput
90+ value = { input }
91+ placeholder = "Describe what you'd like to do or use / to reference files, people, and more"
92+ onChange = { setInput }
93+ >
94+ < Button
95+ appearance = "subtle"
96+ className = "home-input-send-button"
97+ onClick = { handleSubmit }
98+ disabled = { ! input . trim ( ) }
99+ icon = { < Send20Regular /> }
100+ />
101+ < Button
102+ appearance = "subtle"
103+ icon = { < FoodToast20Regular /> }
104+ onClick = { handleClick }
105+ > </ Button >
106+ </ ChatInput >
107+
108+ { /* Inline Toaster lives right under chat input */ }
109+ < InlineToaster />
110+
111+ < div className = "home-input-quick-tasks-section" >
112+ < div className = "home-input-quick-tasks-header" >
113+ < Body1Strong > Quick tasks</ Body1Strong >
114+ </ div >
115+ < div className = "home-input-quick-tasks" >
116+ { quickTasks . map ( ( task ) => (
117+ < Card
118+ key = { task . id }
119+ style = { {
120+ flex : "1 " ,
121+ display : "flex" ,
122+ flexDirection : "column" ,
123+ padding : "16px" ,
124+ backgroundColor : "var(--colorNeutralBackground3)" ,
125+ border : "1px solid var(--colorNeutralStroke2)" ,
126+ borderRadius : "8px" ,
127+ cursor : "pointer" ,
128+ boxShadow : "none" ,
129+ } }
130+ onMouseOver = { ( e ) =>
131+ ( e . currentTarget . style . backgroundColor =
132+ "var(--colorNeutralBackground4Hover)" )
133+ }
134+ onMouseOut = { ( e ) =>
135+ ( e . currentTarget . style . backgroundColor =
136+ "var(--colorNeutralBackground3)" )
137+ }
138+ onClick = { ( ) => handleQuickTaskClick ( task ) }
139+ >
140+ < div className = "home-input-quick-task-content" >
141+ < div className = "home-input-quick-task-icon" >
142+ { task . icon }
118143 </ div >
119-
120- < ChatInput
121- value = { input }
122- placeholder = "Describe what you'd like to do or use / to reference files, people, and more" onChange = { setInput }
123- disabledChat = { submitting }
124- >
125- < Button
126- appearance = "subtle"
127- className = "home-input-send-button"
128- onClick = { handleSubmit }
129- disabled = { submitting }
130- icon = { < Send20Regular /> }
131- />
132- </ ChatInput >
133-
134- < div className = "home-input-quick-tasks-section" >
135- < div className = "home-input-quick-tasks-header" >
136- < Body1Strong > Quick tasks</ Body1Strong >
137- </ div >
138- < div className = "home-input-quick-tasks" >
139- { quickTasks . map ( ( task ) => (
140- < Card
141- key = { task . id }
142- className = "home-input-quick-task-card"
143- onClick = { ( ) => handleQuickTaskClick ( task ) }
144- >
145- < div className = "home-input-quick-task-content" >
146- < div className = "home-input-quick-task-icon" >
147- { task . icon }
148- </ div >
149- < div className = "home-input-quick-task-text-content" >
150- < Body1Strong > { task . title } </ Body1Strong >
151- < Body1 className = "home-input-quick-task-description" >
152- { task . description }
153- </ Body1 >
154- </ div >
155- </ div >
156- </ Card >
157- ) ) }
158- </ div >
144+ < div className = "home-input-quick-task-text-content" >
145+ < Body1Strong > { task . title } </ Body1Strong >
146+ < Body1 className = "home-input-quick-task-description" >
147+ { task . description }
148+ </ Body1 >
159149 </ div >
160- { /* Toast appears after quick tasks */ }
161- { showToast && (
162- < div style = { { marginTop : 16 } } >
163- < Toast >
164- < ToastTitle > Task submitted!</ ToastTitle >
165- < ToastBody > Your task is processing.</ ToastBody >
166- </ Toast >
167- </ div >
168- ) }
169- { error && (
170- < div style = { { marginTop : 16 } } >
171- < Toast >
172- < ToastTitle > Task failed!</ ToastTitle >
173- < ToastBody > { error } </ ToastBody >
174- </ Toast >
175- </ div >
176- ) }
177- </ div >
150+ </ div >
151+ </ Card >
152+ ) ) }
178153 </ div >
154+ </ div >
179155 </ div >
180- ) ;
181- }
156+ </ div >
157+ </ div >
158+ ) ;
159+ } ;
182160
183- export default HomeInput ;
161+ export default HomeInput ;
0 commit comments