1- import { useEffect , useMemo , useState } from "react" ;
1+ import { useCallback , useEffect , useMemo , useState } from "react" ;
22import type {
33 RequestUserInputRequest ,
44 RequestUserInputResponse ,
@@ -12,6 +12,7 @@ type RequestUserInputMessageProps = {
1212 request : RequestUserInputRequest ,
1313 response : RequestUserInputResponse ,
1414 ) => void ;
15+ onDismiss : ( request : RequestUserInputRequest ) => void ;
1516} ;
1617
1718type SelectionState = Record < string , number | null > ;
@@ -22,6 +23,7 @@ export function RequestUserInputMessage({
2223 activeThreadId,
2324 activeWorkspaceId,
2425 onSubmit,
26+ onDismiss,
2527} : RequestUserInputMessageProps ) {
2628 const activeRequests = useMemo (
2729 ( ) =>
@@ -39,7 +41,10 @@ export function RequestUserInputMessage({
3941 } ) ,
4042 [ requests , activeThreadId , activeWorkspaceId ] ,
4143 ) ;
42- const activeRequest = activeRequests [ 0 ] ;
44+ const activeRequest = activeRequests [ 0 ] ?? null ;
45+ const questions = activeRequest ?. params . questions ?? [ ] ;
46+ const totalRequests = activeRequests . length ;
47+
4348 const [ selections , setSelections ] = useState < SelectionState > ( { } ) ;
4449 const [ notes , setNotes ] = useState < NotesState > ( { } ) ;
4550
@@ -60,14 +65,7 @@ export function RequestUserInputMessage({
6065 setNotes ( nextNotes ) ;
6166 } , [ activeRequest ] ) ;
6267
63- if ( ! activeRequest ) {
64- return null ;
65- }
66-
67- const { questions } = activeRequest . params ;
68- const totalRequests = activeRequests . length ;
69-
70- const buildAnswers = ( ) => {
68+ const buildAnswers = useCallback ( ( ) => {
7169 const answers : RequestUserInputResponse [ "answers" ] = { } ;
7270 questions . forEach ( ( question , index ) => {
7371 if ( ! question . id ) {
@@ -97,19 +95,53 @@ export function RequestUserInputMessage({
9795 answers [ question . id ] = { answers : answerList } ;
9896 } ) ;
9997 return answers ;
100- } ;
98+ } , [ questions , selections , notes ] ) ;
10199
102- const handleSelect = ( questionId : string , optionIndex : number ) => {
100+ const handleSelect = useCallback ( ( questionId : string , optionIndex : number ) => {
103101 setSelections ( ( current ) => ( { ...current , [ questionId ] : optionIndex } ) ) ;
104- } ;
102+ } , [ ] ) ;
105103
106- const handleNotesChange = ( questionId : string , value : string ) => {
104+ const handleNotesChange = useCallback ( ( questionId : string , value : string ) => {
107105 setNotes ( ( current ) => ( { ...current , [ questionId ] : value } ) ) ;
108- } ;
106+ } , [ ] ) ;
109107
110- const handleSubmit = ( ) => {
108+ const handleSubmit = useCallback ( ( ) => {
109+ if ( ! activeRequest ) return ;
111110 onSubmit ( activeRequest , { answers : buildAnswers ( ) } ) ;
112- } ;
111+ } , [ activeRequest , onSubmit , buildAnswers ] ) ;
112+
113+ const handleDismiss = useCallback ( ( ) => {
114+ if ( ! activeRequest ) return ;
115+ onDismiss ( activeRequest ) ;
116+ } , [ activeRequest , onDismiss ] ) ;
117+
118+ useEffect ( ( ) => {
119+ if ( ! activeRequest ) return ;
120+
121+ const handleKeyDown = ( event : KeyboardEvent ) => {
122+ if ( event . target instanceof HTMLTextAreaElement ) {
123+ if ( event . key === "Enter" && ( event . metaKey || event . ctrlKey ) ) {
124+ event . preventDefault ( ) ;
125+ handleSubmit ( ) ;
126+ }
127+ return ;
128+ }
129+ if ( event . key === "Enter" ) {
130+ event . preventDefault ( ) ;
131+ handleSubmit ( ) ;
132+ } else if ( event . key === "Escape" ) {
133+ event . preventDefault ( ) ;
134+ handleDismiss ( ) ;
135+ }
136+ } ;
137+
138+ window . addEventListener ( "keydown" , handleKeyDown ) ;
139+ return ( ) => window . removeEventListener ( "keydown" , handleKeyDown ) ;
140+ } , [ activeRequest , handleSubmit , handleDismiss ] ) ;
141+
142+ if ( ! activeRequest ) {
143+ return null ;
144+ }
113145
114146 return (
115147 < div className = "message request-user-input-message" >
@@ -192,6 +224,13 @@ export function RequestUserInputMessage({
192224 < button className = "primary" onClick = { handleSubmit } >
193225 Submit
194226 </ button >
227+ < button className = "secondary" onClick = { handleDismiss } >
228+ Dismiss
229+ </ button >
230+ < div className = "request-user-input-shortcuts" >
231+ < span > < kbd > Enter</ kbd > Submit</ span >
232+ < span > < kbd > Esc</ kbd > Dismiss</ span >
233+ </ div >
195234 </ div >
196235 </ div >
197236 </ div >
0 commit comments