feat: chat send via WebSocket instead of REST
All checks were successful
Deploy Web Client / deploy (push) Successful in 36s

This commit is contained in:
Markov 2026-02-15 23:50:40 +01:00
parent eff6724455
commit cb5b2afe16

View File

@ -6,7 +6,6 @@ import {
ChatMessage, ChatMessage,
getProjectChat, getProjectChat,
getChatMessages, getChatMessages,
sendChatMessage,
} from "@/lib/api"; } from "@/lib/api";
import { wsClient } from "@/lib/ws"; import { wsClient } from "@/lib/ws";
@ -20,7 +19,6 @@ export default function ChatPanel({ projectId }: ChatPanelProps) {
const [input, setInput] = useState(""); const [input, setInput] = useState("");
const [expanded, setExpanded] = useState(false); const [expanded, setExpanded] = useState(false);
const [collapsed, setCollapsed] = useState(false); const [collapsed, setCollapsed] = useState(false);
const [sending, setSending] = useState(false);
const messagesEndRef = useRef<HTMLDivElement>(null); const messagesEndRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
@ -72,27 +70,20 @@ export default function ChatPanel({ projectId }: ChatPanelProps) {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]); }, [messages]);
const handleSend = async () => { const handleSend = () => {
if (!chat || !input.trim() || sending) return; if (!chat || !input.trim()) return;
const text = input.trim(); const text = input.trim();
setInput(""); setInput("");
setSending(true);
try { // Send via WebSocket — message will come back via chat.message event
// Send via REST (gets saved + we get it back via WS broadcast) wsClient.send("chat.send", {
const msg = await sendChatMessage(chat.id, text); chat_id: chat.id,
// Add immediately (WS might duplicate — deduplicate by id) content: text,
setMessages((prev) => { sender_type: "human",
if (prev.find((m) => m.id === msg.id)) return prev; sender_name: "admin",
return [...prev, msg];
}); });
} catch (e) {
console.error("Failed to send message:", e);
setInput(text); // restore on failure
} finally {
setSending(false);
inputRef.current?.focus(); inputRef.current?.focus();
}
}; };
const handleKeyDown = (e: React.KeyboardEvent) => { const handleKeyDown = (e: React.KeyboardEvent) => {
@ -180,11 +171,11 @@ export default function ChatPanel({ projectId }: ChatPanelProps) {
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder="Написать сообщение..." placeholder="Написать сообщение..."
className="flex-1 bg-[var(--bg)] border border-[var(--border)] rounded px-3 py-1.5 text-sm outline-none focus:border-[var(--accent)]" className="flex-1 bg-[var(--bg)] border border-[var(--border)] rounded px-3 py-1.5 text-sm outline-none focus:border-[var(--accent)]"
disabled={!chat || sending} disabled={!chat}
/> />
<button <button
onClick={handleSend} onClick={handleSend}
disabled={!chat || !input.trim() || sending} disabled={!chat || !input.trim()}
className="bg-[var(--accent)] text-white px-4 py-1.5 rounded text-sm hover:opacity-90 disabled:opacity-50" className="bg-[var(--accent)] text-white px-4 py-1.5 rounded text-sm hover:opacity-90 disabled:opacity-50"
> >