Update messaggio in area input
This commit is contained in:
+108
-24
@@ -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 (
|
||||
<div className="chat-input-container p-2 border-top d-flex align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
className="form-control me-2"
|
||||
placeholder="Scrivi un messaggio..."
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
disabled={loading}
|
||||
onKeyDown={(e) => e.key === "Enter" && handleSend()}
|
||||
/>
|
||||
{loading ? (
|
||||
<div className="flex-grow-1 me-2 p-2 bg-light rounded small text-muted">
|
||||
💬 Il modello sta processando… (tempo trascorso: {elapsedTime}s)
|
||||
</div>
|
||||
) : isTextarea ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
className="form-control me-2"
|
||||
placeholder="Scrivi un messaggio..."
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
rows={3}
|
||||
style={{ resize: "none", overflow: "hidden" }}
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
className="form-control me-2"
|
||||
placeholder="Scrivi un messaggio..."
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
)}
|
||||
|
||||
{loading ? (
|
||||
<div className="d-flex align-items-center">
|
||||
<button className="btn btn-warning btn-sm me-2" onClick={onStop}>
|
||||
<button className="btn btn-danger btn-sm me-2" onClick={onStop}>
|
||||
⏹ Stop
|
||||
</button>
|
||||
<button className="btn btn-secondary btn-sm me-2" onClick={handleAddMinute}>
|
||||
+1 min
|
||||
</button>
|
||||
{timeLeft !== null && (
|
||||
<span className="text-muted small">
|
||||
<span
|
||||
className={`small fw-bold ${timeLeft <= 10 ? "text-danger" : "text-muted"}`}
|
||||
>
|
||||
{timeLeft}s
|
||||
</span>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user