From 8bbe2a0ff040b39322caf5f7f66323ab156305de Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Mon, 6 Jul 2026 13:53:11 +0000 Subject: [PATCH] fix(dm): remove local append on send to prevent double messages --- web/src/stores/conversation.ts | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/web/src/stores/conversation.ts b/web/src/stores/conversation.ts index 6ee19e4..fc94af9 100644 --- a/web/src/stores/conversation.ts +++ b/web/src/stores/conversation.ts @@ -130,32 +130,29 @@ export const useConversationStore = create((set, get) => ({ }, sendMessage: async (conversationId, content) => { + // don't append here — WS MESSAGE_CREATE broadcast is the single source of truth. + // Appending in both places caused double messages when the WS event arrived before the HTTP response. const message = await api.post( `/conversations/${conversationId}/messages`, { content }, ); - set((state) => ({ - messagesByConversation: { - ...state.messagesByConversation, - [conversationId]: [ - ...(state.messagesByConversation[conversationId] || []), - message, - ], - }, - })); return message; }, addMessage: (message) => { - set((state) => ({ - messagesByConversation: { - ...state.messagesByConversation, - [message.conversation_id]: [ - ...(state.messagesByConversation[message.conversation_id] || []), - message, - ].sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()), - }, - })); + set((state) => { + const existing = state.messagesByConversation[message.conversation_id] || []; + if (existing.some((m) => m.id === message.id)) { + return state; + } + return { + messagesByConversation: { + ...state.messagesByConversation, + [message.conversation_id]: [...existing, message] + .sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()), + }, + }; + }); }, updateMessage: (message) => { set((state) => {