From 39174e5454aa92bc120bda98beb0012f2b2b653e Mon Sep 17 00:00:00 2001
From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com>
Date: Thu, 12 Mar 2026 02:55:52 +0100
Subject: [PATCH] fix: channel deletion navigates to space root instead of @me
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add stale-channel guard in AppLayout that redirects to the space root
when the URL's channelId no longer exists in the channel list. Remove
the hardcoded navigate('/channels/@me') from ChannelSettingsModal and
the redundant setCurrentChannel fallback from the WS channel_deleted
handler — AppLayout's guard now handles all cases uniformly.
---
packages/web/src/components/layout/AppLayout.tsx | 14 ++++++++++++++
.../src/components/modals/ChannelSettingsModal.tsx | 7 -------
packages/web/src/hooks/useWebSocket.ts | 12 ------------
3 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/packages/web/src/components/layout/AppLayout.tsx b/packages/web/src/components/layout/AppLayout.tsx
index 602ef643..075df99c 100644
--- a/packages/web/src/components/layout/AppLayout.tsx
+++ b/packages/web/src/components/layout/AppLayout.tsx
@@ -240,6 +240,20 @@ export function AppLayout() {
}
}, [spaceId, channelId, channels, navigate]);
+ // Guard: redirect when URL channelId no longer exists (deleted, permission revoked, etc.)
+ useEffect(() => {
+ if (!spaceId || spaceId === '@me' || !channelId) return;
+ if (channels.length === 0) return;
+
+ const { channelToSpaceMap } = useSpaceStore.getState();
+ const firstCh = channels[0];
+ if (!firstCh || channelToSpaceMap.get(firstCh.id) !== spaceId) return;
+
+ if (!channels.some(c => c.id === channelId)) {
+ navigate(`/channels/${spaceId}`, { replace: true });
+ }
+ }, [spaceId, channelId, channels, navigate]);
+
if (isLoading || !user) {
return (
diff --git a/packages/web/src/components/modals/ChannelSettingsModal.tsx b/packages/web/src/components/modals/ChannelSettingsModal.tsx
index 72cf828b..93ff5669 100644
--- a/packages/web/src/components/modals/ChannelSettingsModal.tsx
+++ b/packages/web/src/components/modals/ChannelSettingsModal.tsx
@@ -1,10 +1,8 @@
import React, { useState, useEffect } from 'react';
-import { useNavigate } from 'react-router-dom';
import { Modal } from '../ui/Modal';
import { ConfirmDialog } from '../ui/ConfirmDialog';
import { useUIStore } from '../../stores/uiStore';
import { useSpaceStore, getApiForOrigin } from '../../stores/spaceStore';
-import { useChatStore } from '../../stores/chatStore';
import { api } from '../../api/client';
import { PermissionBits, permissionsToString, stringToPermissions, hasPermissionBit } from '../../utils/permissions';
@@ -24,8 +22,6 @@ export function ChannelSettingsModal() {
const channels = useSpaceStore((s) => s.channels);
const spaces = useSpaceStore((s) => s.spaces);
const spacePermissions = useSpaceStore((s) => s.spacePermissions);
- const currentChannelId = useChatStore((s) => s.currentChannelId);
- const navigate = useNavigate();
const [isPrivate, setIsPrivate] = useState(false);
const [isLoading, setIsLoading] = useState(false);
@@ -116,9 +112,6 @@ export function ChannelSettingsModal() {
const channelApi = getApiForOrigin(space?._instanceOrigin ?? '');
await channelApi.channels.delete(channelId);
closeModal();
- if (currentChannelId === channelId) {
- navigate('/channels/@me');
- }
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to delete channel');
setIsDeleting(false);
diff --git a/packages/web/src/hooks/useWebSocket.ts b/packages/web/src/hooks/useWebSocket.ts
index 25aaa0b9..25d4f50c 100644
--- a/packages/web/src/hooks/useWebSocket.ts
+++ b/packages/web/src/hooks/useWebSocket.ts
@@ -633,18 +633,6 @@ function handleEvent(origin: string, event: ServerEvent): void {
useVoiceStore.setState({ voiceUsers: newVoiceUsers });
}
}
- {
- const { currentChannelId } = useChatStore.getState();
- if (currentChannelId === event.channelId) {
- const { channels: remainingChannels } = useSpaceStore.getState();
- const firstText = remainingChannels.find(c => c.type === 'text');
- if (firstText) {
- useChatStore.getState().setCurrentChannel(firstText.id);
- } else {
- useChatStore.getState().setCurrentChannel(null);
- }
- }
- }
break;
}