diff --git a/src/contexts/room-context.tsx b/src/contexts/room-context.tsx index a87c8ad..428155b 100644 --- a/src/contexts/room-context.tsx +++ b/src/contexts/room-context.tsx @@ -424,8 +424,20 @@ export function RoomProvider({ // Use ref to get current activeRoomId to avoid stale closure if (payload.room_id === activeRoomIdRef.current) { setMessages((prev) => { - // Deduplicate by both ID (for normal) and seq (for optimistic replacement) - if (prev.some((m) => m.id === payload.id)) { + // Check if this is a reaction-update event (same ID, different reactions). + // publish_reaction_event sends RoomMessageEvent with reactions field set. + const existingIdx = prev.findIndex((m) => m.id === payload.id); + if (existingIdx !== -1) { + // Message already exists — update reactions if provided. + // Reaction events have empty content/sender_type. + if (payload.reactions !== undefined) { + const updated = [...prev]; + updated[existingIdx] = { ...updated[existingIdx], reactions: payload.reactions }; + const msg = updated[existingIdx]; + saveMessage(msg).catch(() => {}); + return updated; + } + // Duplicate of a real message — ignore return prev; } // Also check if there's an optimistic message with the same seq that should be replaced diff --git a/src/lib/ws-protocol.ts b/src/lib/ws-protocol.ts index 89b6543..f04e533 100644 --- a/src/lib/ws-protocol.ts +++ b/src/lib/ws-protocol.ts @@ -166,6 +166,8 @@ export interface RoomMessagePayload { send_at: string; seq: number; display_name?: string; + /** Present when this event carries reaction updates for the message */ + reactions?: ReactionItem[]; } export interface ProjectEventPayload {