1- import React , { useState } from 'react' ;
1+ import React , { useState , useCallback , memo } from 'react' ;
22import styled from 'styled-components' ;
33import { useSelector } from 'react-redux' ;
44import { RootState } from '../store' ;
5+
56// Debug logging utility
6- const DEBUG = true ;
7- const log = ( message : string , data ?: any ) => {
7+ const DEBUG = process . env . NODE_ENV === 'development' ;
8+ const log = ( message : string , data ?: unknown ) => {
89 if ( DEBUG ) {
910 if ( data ) {
1011 console . log ( `[InputArea] ${ message } ` , data ) ;
@@ -20,8 +21,17 @@ const InputContainer = styled.div`
2021 border-top: 1px solid ${ ( props ) => props . theme . colors . border } ;
2122 display: ${ ( { theme} ) => theme . config ?. singleInput ? 'none' : 'block' } ;
2223 max-height: 10vh;
24+ position: sticky;
25+ bottom: 0;
26+ z-index: 10;
27+ ` ;
28+ const StyledForm = styled . form `
29+ display: flex;
30+ gap: 1rem;
31+ align-items: flex-start;
2332` ;
2433
34+
2535const TextArea = styled . textarea `
2636 width: 100%;
2737 padding: 0.5rem;
@@ -31,44 +41,77 @@ const TextArea = styled.textarea`
3141 resize: vertical;
3242 min-height: 40px;
3343 max-height: ${ ( { theme} ) => theme . sizing . console . maxHeight } ;
44+ &:focus {
45+ outline: 2px solid ${ ( props ) => props . theme . colors . primary } ;
46+ border-color: ${ ( props ) => props . theme . colors . primary } ;
47+ }
48+ &:disabled {
49+ background-color: ${ ( props ) => props . theme . colors . disabled } ;
50+ }
51+ ` ;
52+ const SendButton = styled . button `
53+ padding: 0.5rem 1rem;
54+ background-color: ${ ( props ) => props . theme . colors . primary } ;
55+ color: white;
56+ border: none;
57+ border-radius: ${ ( props ) => props . theme . sizing . borderRadius . md } ;
58+ cursor: pointer;
59+ transition: opacity 0.2s;
60+ &:disabled {
61+ opacity: 0.5;
62+ cursor: not-allowed;
63+ }
64+ &:hover:not(:disabled) {
65+ opacity: 0.9;
66+ }
3467` ;
3568
3669interface InputAreaProps {
3770 onSendMessage : ( message : string ) => void ;
3871}
3972
40- const InputArea : React . FC < InputAreaProps > = ( { onSendMessage} ) => {
73+ const InputArea = memo ( function InputArea ( { onSendMessage} : InputAreaProps ) {
4174 log ( 'Initializing component' ) ;
4275 const [ message , setMessage ] = useState ( '' ) ;
4376 const config = useSelector ( ( state : RootState ) => state . config ) ;
4477 const [ isSubmitting , setIsSubmitting ] = useState ( false ) ;
4578
46- const handleSubmit = ( e : React . FormEvent ) => {
79+ const handleSubmit = useCallback ( ( e : React . FormEvent ) => {
4780 e . preventDefault ( ) ;
81+ if ( isSubmitting ) return ;
82+
4883 log ( 'Submit attempt' ) ;
4984 if ( message . trim ( ) ) {
5085 setIsSubmitting ( true ) ;
5186 log ( 'Sending message' , {
5287 messageLength : message . length ,
5388 message : message . substring ( 0 , 100 ) + ( message . length > 100 ? '...' : '' )
5489 } ) ;
55- onSendMessage ( message ) ;
56- setMessage ( '' ) ;
57- setIsSubmitting ( false ) ;
58- log ( 'Message sent and form reset' ) ;
90+ Promise . resolve ( onSendMessage ( message ) ) . finally ( ( ) => {
91+ setMessage ( '' ) ;
92+ setIsSubmitting ( false ) ;
93+ log ( 'Message sent and form reset' ) ;
94+ } ) ;
5995 } else {
6096 log ( 'Empty message, not sending' ) ;
6197 }
62- } ;
98+ } , [ message , onSendMessage ] ) ;
6399
64- const handleMessageChange = ( e : React . ChangeEvent < HTMLTextAreaElement > ) => {
100+ const handleMessageChange = useCallback ( ( e : React . ChangeEvent < HTMLTextAreaElement > ) => {
65101 const newMessage = e . target . value ;
66102 log ( 'Message changed' , {
67103 length : newMessage . length ,
68104 isEmpty : newMessage . trim ( ) . length === 0
69105 } ) ;
70106 setMessage ( newMessage ) ;
71- } ;
107+ } , [ ] ) ;
108+
109+ const handleKeyPress = useCallback ( ( e : React . KeyboardEvent < HTMLTextAreaElement > ) => {
110+ if ( e . key === 'Enter' && ! e . shiftKey ) {
111+ e . preventDefault ( ) ;
112+ handleSubmit ( e ) ;
113+ }
114+ } , [ handleSubmit ] ) ;
72115
73116 React . useEffect ( ( ) => {
74117 log ( 'Component mounted' , { configState : config } ) ;
@@ -80,20 +123,27 @@ const InputArea: React.FC<InputAreaProps> = ({onSendMessage}) => {
80123
81124 return (
82125 < InputContainer >
83- < form onSubmit = { handleSubmit } >
126+ < StyledForm onSubmit = { handleSubmit } >
84127 < TextArea
85128 value = { message }
86129 onChange = { handleMessageChange }
130+ onKeyPress = { handleKeyPress }
87131 placeholder = "Type a message..."
88132 rows = { 3 }
133+ aria-label = "Message input"
134+ disabled = { isSubmitting }
89135 />
90- < button type = "submit" > Send</ button >
91- </ form >
136+ < SendButton
137+ type = "submit"
138+ disabled = { isSubmitting || ! message . trim ( ) }
139+ aria-label = "Send message"
140+ >
141+ Send
142+ </ SendButton >
143+ </ StyledForm >
92144 </ InputContainer >
93145 ) ;
94- } ;
95- // Log when module is imported
96- log ( 'Module loaded' ) ;
146+ } ) ;
97147
98148
99149export default InputArea ;
0 commit comments