fix: clear message cache on reconnect to prevent stale scroll position

After a server restart, navigating to a previously-visited channel showed
messages at a stale middle position instead of scrolling to the bottom.
The in-memory message cache survived the reconnect, so loadMessages()
bailed (cache hit) and the scroll-to-bottom logic never fired.

Now the ready handler clears the messages and hasMore maps for all
channels belonging to the reconnecting origin (including DMs for home).
The currently open channel is force-reloaded immediately; other channels
get fresh-fetched on next visit, triggering proper scroll-to-bottom.

Also fixes voice channel settings gear icon placement to match text
channels (flex-1 pushes icon to right edge).
This commit is contained in:
Jannis Braun
2026-03-16 22:34:21 +01:00
parent bfecb41c66
commit 1c806be94f
2 changed files with 28 additions and 8 deletions
@@ -138,8 +138,8 @@ export function VoiceChannel({ channelId, channelName, onClick, locked, canManag
<path d="M11 5L6 9H2V15H6L11 19V5ZM15.54 8.46C16.48 9.4 17 10.67 17 12S16.48 14.6 15.54 15.54L14.12 14.12C14.69 13.55 15 12.79 15 12S14.69 10.45 14.12 9.88L15.54 8.46ZM19.07 4.93C20.91 6.77 22 9.28 22 12C22 14.72 20.91 17.23 19.07 19.07L17.66 17.66C19.11 16.21 20 14.21 20 12C20 9.79 19.11 7.79 17.66 6.34L19.07 4.93Z" />
</svg>
)}
<span className="truncate text-[15px] font-medium">{channelName}</span>
{canManage && onSettingsClick && (
<span className="truncate text-[15px] font-medium flex-1 text-left">{channelName}</span>
{canManage && (
<svg
width="16"
height="16"
@@ -148,7 +148,7 @@ export function VoiceChannel({ channelId, channelName, onClick, locked, canManag
className="flex-shrink-0 opacity-0 group-hover:opacity-100 text-txt-tertiary hover:text-txt-primary transition-opacity"
onClick={(e) => {
e.stopPropagation();
onSettingsClick();
onSettingsClick?.();
}}
>
<path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.07.62-.07.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z" />
+24 -4
View File
@@ -143,11 +143,31 @@ function handleEvent(origin: string, event: ServerEvent): void {
}
}
// Only force-reload the current channel on reconnect; other channels keep their cache
// Clear stale message cache for all channels on this origin so the next
// visit does a fresh fetch (and scroll-to-bottom fires correctly).
// Force-reload the currently open channel immediately.
{
const chatState = useChatStore.getState();
const { channelOriginMap } = useSpaceStore.getState();
const newMessages = new Map(chatState.messages);
const newHasMore = new Map(chatState.hasMore);
for (const [channelId, chOrigin] of channelOriginMap) {
if (chOrigin === origin) {
newMessages.delete(channelId);
newHasMore.delete(channelId);
}
}
if (isHome) {
const { loadMessages: reloadMessages, currentChannelId } = useChatStore.getState();
if (currentChannelId) {
reloadMessages(currentChannelId, true);
for (const key of [...newMessages.keys()]) {
if (key.startsWith('dm-')) {
newMessages.delete(key);
newHasMore.delete(key);
}
}
}
useChatStore.setState({ messages: newMessages, hasMore: newHasMore });
if (chatState.currentChannelId) {
chatState.loadMessages(chatState.currentChannelId, true);
}
}