import React, { useState, useEffect, useRef } from 'react'; import { Prompt } from '../../../hooks/usePrompts'; import FileAttachmentPopup from './FileAttachmentPopup'; import { WorkflowManagerState, WorkflowManagerActions } from './useWorkflowManager'; import { useLanguage } from '../../../contexts/LanguageContext'; import styles from './DashboardChatAreaStyles/DashboardChatAreaInput.module.css'; import sharedStyles from './DashboardChatAreaStyles/DashboardChat.module.css'; interface InputAreaProps { selectedPrompt?: Prompt | null; onPromptUsed?: () => void; workflowState: WorkflowManagerState; workflowActions: WorkflowManagerActions; onAttachedFilesChange?: (files: AttachedFile[]) => void; attachedFiles?: AttachedFile[]; } interface AttachedFile { id: number; name: string; size: number; type: string; fileData?: File; objectUrl?: string; } const InputArea: React.FC = ({ selectedPrompt, onPromptUsed, workflowState, workflowActions, onAttachedFilesChange, attachedFiles: externalAttachedFiles = [] }) => { const { t } = useLanguage(); const [inputValue, setInputValue] = useState(''); const [showFilePopup, setShowFilePopup] = useState(false); const [isSending, setIsSending] = useState(false); const [sendError, setSendError] = useState(null); const [isFocused, setIsFocused] = useState(false); const textareaRef = useRef(null); // Always use external attached files from parent component const currentAttachedFiles = externalAttachedFiles; // Auto-resize textarea function const adjustTextareaHeight = () => { const textarea = textareaRef.current; if (!textarea) return; // Reset height to auto to get the actual scroll height textarea.style.height = 'auto'; // Calculate the height based on content const scrollHeight = textarea.scrollHeight; const lineHeight = 1.5 * 14; // 1.5em * 14px font size const padding = 32; // 16px top + 16px bottom padding const minHeight = lineHeight * 4 + padding; // 4 rows const maxHeight = lineHeight * 8 + padding; // 8 rows // Set height within constraints const newHeight = Math.min(Math.max(scrollHeight, minHeight), maxHeight); textarea.style.height = `${newHeight}px`; }; // Auto-fill input when prompt is selected useEffect(() => { if (selectedPrompt) { setInputValue(selectedPrompt.content); } }, [selectedPrompt]); // Adjust height when input value changes useEffect(() => { adjustTextareaHeight(); }, [inputValue]); // Initial resize on mount useEffect(() => { adjustTextareaHeight(); }, []); const handleSend = async () => { if (!inputValue.trim() || isSending) return; setIsSending(true); setSendError(null); try { const fileIds = currentAttachedFiles.map(f => f.id); let success = false; if (workflowState.currentWorkflowId) { // Continue existing workflow console.log(`➡️ Continuing workflow ${workflowState.currentWorkflowId}`); success = await workflowActions.continueWorkflow(inputValue, fileIds); } else { // Start new workflow console.log('🚀 Starting new workflow'); const newWorkflowId = await workflowActions.startNewWorkflow(inputValue, fileIds); success = !!newWorkflowId; } if (success) { setInputValue(''); if (onAttachedFilesChange) { onAttachedFilesChange([]); } if (onPromptUsed) onPromptUsed(); } else { setSendError('Failed to send message. Please try again.'); } } catch (error: any) { console.error('Failed to send message:', error); setSendError(error.message || 'Failed to send message. Please try again.'); } finally { setIsSending(false); } }; const handleKeyPress = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSend(); } }; const handleFilesAttached = (files: AttachedFile[]) => { setShowFilePopup(false); if (onAttachedFilesChange) { onAttachedFilesChange(files); } }; const isWorkflowActive = workflowState.workflow && ['running', 'processing', 'started'].includes(workflowState.workflow.status); // Determine if label should be in focused/moved state const shouldLabelBeFocused = isFocused || inputValue.trim().length > 0; // Get placeholder text const placeholderText = workflowState.currentWorkflowId ? t('chat.input.continue_workflow') : t('chat.input.enter_message'); return (
{/* Error messages */} {(sendError || workflowState.error) && (
{t('chat.input.error_prefix')} {sendError || workflowState.error}
)} {/* Show attached files count */} {currentAttachedFiles.length > 0 && (
{currentAttachedFiles.length} {currentAttachedFiles.length !== 1 ? t('chat.input.files_attached_plural') : t('chat.input.files_attached')} {t('chat.input.files_attached_label')}
)}