From 86717a286783455b85da9b7f5d4085fdcf812760 Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Mon, 27 Jul 2026 09:05:23 -0400 Subject: [PATCH] fix(web): normalize channel IDs to lowercase across stores and WS --- web/src/stores/channel.ts | 9 +++++---- web/src/stores/readStates.ts | 8 +++++--- web/src/stores/ws.ts | 5 +++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/web/src/stores/channel.ts b/web/src/stores/channel.ts index 3c03551..2348d62 100644 --- a/web/src/stores/channel.ts +++ b/web/src/stores/channel.ts @@ -49,13 +49,14 @@ export const useChannelStore = create((set) => ({ }, setActiveChannel: (id) => { - set({ activeChannelId: id }); - if (id) { + const chId = id ? id.toLowerCase() : null; + set({ activeChannelId: chId }); + if (chId) { // ponytail: persist last active channel for session restore const state = useChannelStore.getState(); for (const [serverId, channels] of Object.entries(state.channelsByServer)) { - if (channels.some((c) => c.id === id)) { - localStorage.setItem('dumpster:lastChannel', JSON.stringify({ serverId, channelId: id })); + if (channels.some((c) => c.id.toLowerCase() === chId)) { + localStorage.setItem('dumpster:lastChannel', JSON.stringify({ serverId, channelId: chId })); break; } } diff --git a/web/src/stores/readStates.ts b/web/src/stores/readStates.ts index 4c4c483..e693051 100644 --- a/web/src/stores/readStates.ts +++ b/web/src/stores/readStates.ts @@ -27,11 +27,12 @@ export const useReadStatesStore = create()((set, get) => ({ }, markRead: async (channelId: string, messageId: string) => { + const chId = channelId.toLowerCase(); set((state) => ({ - states: { ...state.states, [channelId]: messageId }, + states: { ...state.states, [chId]: messageId }, })); try { - await api.put(`/channels/${channelId}/read`, { last_read_message_id: messageId }); + await api.put(`/channels/${chId}/read`, { last_read_message_id: messageId }); } catch { // optimistic update, ignore failure } @@ -45,8 +46,9 @@ export const useReadStatesStore = create()((set, get) => ({ }, hasUnread: (channelId: string, latestMessageId?: string): boolean => { + const chId = channelId.toLowerCase(); const state = get().states; - const lastRead = state[channelId]; + const lastRead = state[chId]; // never viewed: unread if there are messages if (!lastRead) return !!latestMessageId; // viewed but newer messages exist diff --git a/web/src/stores/ws.ts b/web/src/stores/ws.ts index 32c19b2..132d013 100644 --- a/web/src/stores/ws.ts +++ b/web/src/stores/ws.ts @@ -61,7 +61,7 @@ function extractIds(payload: UnknownPayload | undefined): { channel_id?: string; ? payload.id : null; if (!messageId) return null; - if (typeof payload.channel_id === 'string') return { channel_id: payload.channel_id, message_id: messageId }; + if (typeof payload.channel_id === 'string') return { channel_id: payload.channel_id.toLowerCase(), message_id: messageId }; if (typeof payload.conversation_id === 'string') return { conversation_id: payload.conversation_id.toLowerCase(), message_id: messageId }; return null; } @@ -150,7 +150,8 @@ export const useWebSocketStore = create((set, get) => ({ } } else { const msg = payload as unknown as Message; - addMessage(msg); + const normalizedMsg = { ...msg, channel_id: (msg.channel_id || '').toLowerCase() }; + addMessage(normalizedMsg); // Desktop notification const currentUserId = useAuthStore.getState().user?.id;