Close a channel's web tab when the user parts or is kicked (closes #185)
check / check (push) Waiting to run

A PART event from the user's own nick now closes the channel's tab,
whether this web client or another client of the session sent it. It
adds no message or unread count.

A KICK event now goes into the channel's tab as "nick was kicked from
channel by kicker (reason)", with the kicked nick taken from params.
Before, it fell through to the Server tab, which showed only the
reason. When the kicked nick is the user's own, the tab closes.

The tab removal that partChannel did moves into removeChannelTab,
which partChannel and both events share.

Model: opus-5-5
This commit was merged in pull request #192.
This commit is contained in:
2026-10-27 03:11:33 +01:00
parent 76ef8ffaaf
commit e1173eba9e
+31 -5
View File
@@ -355,6 +355,14 @@ function App() {
.catch(() => {});
}, []);
// removeChannelTab closes a channel's tab and shows the Server tab.
const removeChannelTab = useCallback((name) => {
setTabs((prev) =>
prev.filter((t) => !(t.type === "channel" && t.name === name)),
);
setActiveTab(0);
}, []);
const processMessage = useCallback(
(msg) => {
const body = Array.isArray(msg.body) ? msg.body.join("\n") : "";
@@ -424,6 +432,13 @@ function App() {
break;
}
case "PART": {
// The user's own PART, sent from this client or another,
// closes the tab and adds no message or unread count.
if (msg.from === nickRef.current) {
removeChannelTab(msg.to);
break;
}
const reason = body ? " (" + body + ")" : "";
const text = `${msg.from} has parted ${msg.to}${reason}`;
if (msg.to) addMessage(msg.to, { ...base, text, system: true });
@@ -431,6 +446,20 @@ function App() {
break;
}
case "KICK": {
// The kicked nick is in params; the body is the reason.
const kicked = Array.isArray(msg.params) ? msg.params[0] : "";
const reason = body ? " (" + body + ")" : "";
const text = `${kicked} was kicked from ${msg.to} by ${msg.from}${reason}`;
if (msg.to) addMessage(msg.to, { ...base, text, system: true });
if (kicked === nickRef.current) {
removeChannelTab(msg.to);
} else if (msg.to && msg.to.startsWith("#")) {
refreshMembers(msg.to);
}
break;
}
case "QUIT": {
const reason = body ? " (" + body + ")" : "";
const text = `${msg.from} has quit${reason}`;
@@ -656,7 +685,7 @@ function App() {
}
}
},
[addMessage, refreshMembers],
[addMessage, refreshMembers, removeChannelTab],
);
// Long-poll loop.
@@ -865,10 +894,7 @@ function App() {
} catch (e) {
// Ignore.
}
setTabs((prev) =>
prev.filter((t) => !(t.type === "channel" && t.name === name)),
);
setActiveTab(0);
removeChannelTab(name);
};
const closeTab = (idx) => {