feat: chat send via WebSocket instead of REST
All checks were successful
Deploy Web Client / deploy (push) Successful in 36s
All checks were successful
Deploy Web Client / deploy (push) Successful in 36s
This commit is contained in:
parent
eff6724455
commit
cb5b2afe16
@ -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"
|
||||||
>
|
>
|
||||||
→
|
→
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user