From 97e71742acff8c467d7e9d9b2ddd48c4430be4ed Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 27 Oct 2026 02:18:52 +0000 Subject: [PATCH] Show a joined channel's web tab whichever reply comes first (closes #193) After a join request returned, joinChannel made tab number tabsRef.current.length active. When the user's own JOIN event had already added the tab, or the tab was already open, that index was one past the last tab. The view then fell back to the Server tab and typed lines were dropped. joinChannel now records the joined channel's name. An effect makes that channel's tab active once the tab list holds it, finding the tab by name. Model: opus-5-5 --- web/src/app.jsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/web/src/app.jsx b/web/src/app.jsx index 11607d8..22f57a4 100644 --- a/web/src/app.jsx +++ b/web/src/app.jsx @@ -280,6 +280,8 @@ function App() { const [connected, setConnected] = useState(true); const [inputHistory, setInputHistory] = useState([]); const [historyIndex, setHistoryIndex] = useState(-1); + // A channel this client has just joined, whose tab is to be shown. + const [joinedChannel, setJoinedChannel] = useState(null); const lastIdRef = useRef(0); const seenIdsRef = useRef(new Set()); @@ -315,6 +317,18 @@ function App() { if (tab) setUnread((prev) => ({ ...prev, [tab.name]: 0 })); }, [activeTab, tabs]); + // Show the tab of a channel this client has just joined. The tab is + // found by name in the updated tab list, because the user's own JOIN + // event may have added it before the join request returned. + useEffect(() => { + if (!joinedChannel) return; + const idx = tabs.findIndex( + (t) => t.type === "channel" && t.name === joinedChannel, + ); + if (idx >= 0) setActiveTab(idx); + setJoinedChannel(null); + }, [tabs, joinedChannel]); + const addMessage = useCallback((tabName, msg) => { if (msg.id && seenIdsRef.current.has(msg.id)) return; if (msg.id) seenIdsRef.current.add(msg.id); @@ -864,8 +878,7 @@ function App() { return [...prev, { type: "channel", name }]; }); - const newIdx = tabsRef.current.length; - setActiveTab(newIdx); + setJoinedChannel(name); try { const hist = await api( `/history?target=${encodeURIComponent(name)}&limit=50`,