diff --git a/frontend/src/ChatInput.jsx b/frontend/src/ChatInput.jsx index 1cb9e3f..e461357 100644 --- a/frontend/src/ChatInput.jsx +++ b/frontend/src/ChatInput.jsx @@ -1,47 +1,79 @@ // src/ChatInput.jsx import React, { useState, useEffect, useRef } from "react"; -const MAX_EXECUTION_TIME_MS = 2 * 60 * 1000; // 2 minuti +const MAX_EXECUTION_TIME_MS_DEFAULT = 2 * 60 * 1000; // 2 minuti +const EXTRA_TIME_MS = 60 * 1000; +const CHAR_LIMIT_FOR_TEXTAREA = 80; +const LINE_LIMIT_FOR_TEXTAREA = 1; export default function ChatInput({ onSend, onStop, loading }) { const [inputValue, setInputValue] = useState(""); const [timeLeft, setTimeLeft] = useState(null); + const [elapsedTime, setElapsedTime] = useState(0); + const [maxExecutionTime, setMaxExecutionTime] = useState(MAX_EXECUTION_TIME_MS_DEFAULT); + const stopTimerRef = useRef(null); const countdownIntervalRef = useRef(null); + const elapsedIntervalRef = useRef(null); + const inputRef = useRef(null); - // Gestione auto-stop e countdown + const isTextarea = + inputValue.length > CHAR_LIMIT_FOR_TEXTAREA || + inputValue.split("\n").length > LINE_LIMIT_FOR_TEXTAREA; + + // Focus automatico + useEffect(() => { + if (!loading && inputRef.current) { + inputRef.current.focus(); + const val = inputRef.current.value; + inputRef.current.setSelectionRange(val.length, val.length); + } + }, [isTextarea, loading]); + + // Auto‑resize + useEffect(() => { + if (isTextarea && inputRef.current) { + inputRef.current.style.height = "auto"; + inputRef.current.style.height = inputRef.current.scrollHeight + "px"; + } + }, [inputValue, isTextarea]); + + // Gestione timer e countdown useEffect(() => { if (loading) { - setTimeLeft(Math.floor(MAX_EXECUTION_TIME_MS / 1000)); + setTimeLeft(Math.floor(maxExecutionTime / 1000)); + setElapsedTime(0); stopTimerRef.current = setTimeout(() => { console.warn("⏱ Tempo massimo raggiunto, stop automatico"); onStop(); - }, MAX_EXECUTION_TIME_MS); + }, maxExecutionTime); countdownIntervalRef.current = setInterval(() => { - setTimeLeft(prev => { - if (prev === null) return null; - if (prev <= 1) { - clearInterval(countdownIntervalRef.current); - return 0; - } - return prev - 1; - }); + setTimeLeft(prev => (prev > 0 ? prev - 1 : 0)); + }, 1000); + + elapsedIntervalRef.current = setInterval(() => { + setElapsedTime(prev => prev + 1); }, 1000); } else { clearTimeout(stopTimerRef.current); clearInterval(countdownIntervalRef.current); + clearInterval(elapsedIntervalRef.current); stopTimerRef.current = null; countdownIntervalRef.current = null; + elapsedIntervalRef.current = null; setTimeLeft(null); + setElapsedTime(0); + setMaxExecutionTime(MAX_EXECUTION_TIME_MS_DEFAULT); } return () => { clearTimeout(stopTimerRef.current); clearInterval(countdownIntervalRef.current); + clearInterval(elapsedIntervalRef.current); }; - }, [loading, onStop]); + }, [loading, maxExecutionTime, onStop]); const handleSend = () => { if (inputValue.trim()) { @@ -50,25 +82,77 @@ export default function ChatInput({ onSend, onStop, loading }) { } }; + const handleAddMinute = () => { + setMaxExecutionTime(prev => prev + EXTRA_TIME_MS); + setTimeLeft(prev => (prev !== null ? prev + 60 : prev)); + clearTimeout(stopTimerRef.current); + stopTimerRef.current = setTimeout(() => { + console.warn("⏱ Tempo massimo raggiunto, stop automatico"); + onStop(); + }, maxExecutionTime + EXTRA_TIME_MS); + }; + + const handleKeyDown = (e) => { + if (e.key === "Enter") { + if (e.shiftKey) { + e.preventDefault(); + const { selectionStart, selectionEnd } = e.target; + const newValue = + inputValue.substring(0, selectionStart) + + "\n" + + inputValue.substring(selectionEnd); + setInputValue(newValue); + requestAnimationFrame(() => { + inputRef.current.selectionStart = inputRef.current.selectionEnd = selectionStart + 1; + }); + } else { + e.preventDefault(); + handleSend(); + } + } + }; + return (