From 6aa3df0334d4ac03be2f04bab63992aae0d50558 Mon Sep 17 00:00:00 2001 From: Andrew Charneski Date: Fri, 29 Nov 2024 16:47:47 -0500 Subject: [PATCH] wip --- webapp/chat-app/src/components/InputArea.tsx | 86 +++++++++++++++---- webapp/chat-app/src/components/Menu/Menu.tsx | 19 ++-- .../chat-app/src/store/slices/configSlice.ts | 17 ++++ webapp/chat-app/src/styled.d.ts | 1 + webapp/chat-app/src/themes/themes.ts | 6 ++ webapp/chat-app/src/types/styled.d.ts | 1 + 6 files changed, 105 insertions(+), 25 deletions(-) diff --git a/webapp/chat-app/src/components/InputArea.tsx b/webapp/chat-app/src/components/InputArea.tsx index 6eb2a994..2de86d14 100644 --- a/webapp/chat-app/src/components/InputArea.tsx +++ b/webapp/chat-app/src/components/InputArea.tsx @@ -1,10 +1,11 @@ -import React, {useState} from 'react'; +import React, {useState, useCallback, memo} from 'react'; import styled from 'styled-components'; import {useSelector} from 'react-redux'; import {RootState} from '../store'; + // Debug logging utility -const DEBUG = true; -const log = (message: string, data?: any) => { +const DEBUG = process.env.NODE_ENV === 'development'; +const log = (message: string, data?: unknown) => { if (DEBUG) { if (data) { console.log(`[InputArea] ${message}`, data); @@ -20,8 +21,17 @@ const InputContainer = styled.div` border-top: 1px solid ${(props) => props.theme.colors.border}; display: ${({theme}) => theme.config?.singleInput ? 'none' : 'block'}; max-height: 10vh; + position: sticky; + bottom: 0; + z-index: 10; +`; +const StyledForm = styled.form` + display: flex; + gap: 1rem; + align-items: flex-start; `; + const TextArea = styled.textarea` width: 100%; padding: 0.5rem; @@ -31,20 +41,45 @@ const TextArea = styled.textarea` resize: vertical; min-height: 40px; max-height: ${({theme}) => theme.sizing.console.maxHeight}; + &:focus { + outline: 2px solid ${(props) => props.theme.colors.primary}; + border-color: ${(props) => props.theme.colors.primary}; + } + &:disabled { + background-color: ${(props) => props.theme.colors.disabled}; + } +`; +const SendButton = styled.button` + padding: 0.5rem 1rem; + background-color: ${(props) => props.theme.colors.primary}; + color: white; + border: none; + border-radius: ${(props) => props.theme.sizing.borderRadius.md}; + cursor: pointer; + transition: opacity 0.2s; + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + &:hover:not(:disabled) { + opacity: 0.9; + } `; interface InputAreaProps { onSendMessage: (message: string) => void; } -const InputArea: React.FC = ({onSendMessage}) => { +const InputArea = memo(function InputArea({onSendMessage}: InputAreaProps) { log('Initializing component'); const [message, setMessage] = useState(''); const config = useSelector((state: RootState) => state.config); const [isSubmitting, setIsSubmitting] = useState(false); - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = useCallback((e: React.FormEvent) => { e.preventDefault(); + if (isSubmitting) return; + log('Submit attempt'); if (message.trim()) { setIsSubmitting(true); @@ -52,23 +87,31 @@ const InputArea: React.FC = ({onSendMessage}) => { messageLength: message.length, message: message.substring(0, 100) + (message.length > 100 ? '...' : '') }); - onSendMessage(message); - setMessage(''); - setIsSubmitting(false); - log('Message sent and form reset'); + Promise.resolve(onSendMessage(message)).finally(() => { + setMessage(''); + setIsSubmitting(false); + log('Message sent and form reset'); + }); } else { log('Empty message, not sending'); } - }; + }, [message, onSendMessage]); - const handleMessageChange = (e: React.ChangeEvent) => { + const handleMessageChange = useCallback((e: React.ChangeEvent) => { const newMessage = e.target.value; log('Message changed', { length: newMessage.length, isEmpty: newMessage.trim().length === 0 }); setMessage(newMessage); - }; + }, []); + + const handleKeyPress = useCallback((e: React.KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleSubmit(e); + } + }, [handleSubmit]); React.useEffect(() => { log('Component mounted', {configState: config}); @@ -80,20 +123,27 @@ const InputArea: React.FC = ({onSendMessage}) => { return ( -
+