From a68d8c37cd8211684ae2a1e630cced90aa7f3972 Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 27 Oct 2026 05:32:31 +0000 Subject: [PATCH] Show the direct-message web tab even when other tabs change first (closes #202) openDM took the direct-message tab's position from the tab list of the render its caller came from. /msg calls it only after the PRIVMSG request returns. By then the server's copy of the message, or a join or part from another client of the session, may have changed the tabs. The active tab then became another tab or none, and the next typed line went to the wrong place or was dropped. openDM now finds the tab by name inside its setTabs update and makes it active there, as joinChannel does. Model: opus-5-5 --- web/src/app.jsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/web/src/app.jsx b/web/src/app.jsx index 6c1d112..8d97eaf 100644 --- a/web/src/app.jsx +++ b/web/src/app.jsx @@ -948,16 +948,23 @@ function App() { const openDM = (targetNick) => { if (targetNick === nickRef.current) return; + // Show the direct-message tab. Preact runs this update at once on + // the newest tab list, so the tab is found there by name: the + // server's copy of the user's message may already have added it, + // and other tabs may have opened or closed. setTabs((prev) => { - if (prev.find((t) => t.type === "dm" && t.name === targetNick)) + const idx = prev.findIndex( + (t) => t.type === "dm" && t.name === targetNick, + ); + if (idx >= 0) { + setActiveTab(idx); + return prev; + } + setActiveTab(prev.length); return [...prev, { type: "dm", name: targetNick }]; }); - const idx = tabs.findIndex( - (t) => t.type === "dm" && t.name === targetNick, - ); - setActiveTab(idx >= 0 ? idx : tabs.length); }; const handleCommand = async (text) => {