diff --git a/libs/api/room/ws_universal.rs b/libs/api/room/ws_universal.rs index 011c0e7..bd8dfc1 100644 --- a/libs/api/room/ws_universal.rs +++ b/libs/api/room/ws_universal.rs @@ -397,7 +397,7 @@ async fn poll_push_streams( if let Some(reactions) = event.reactions.clone() { return Some(WsPushEvent::ReactionUpdated { room_id: event.room_id, - message_id: event.id, + message_id: event.message_id.unwrap_or(event.id), reactions, }); } diff --git a/libs/queue/producer.rs b/libs/queue/producer.rs index 0bbcbb7..9c4f9cd 100644 --- a/libs/queue/producer.rs +++ b/libs/queue/producer.rs @@ -176,7 +176,7 @@ impl MessageProducer { pub async fn publish_reaction_event( &self, room_id: uuid::Uuid, - _message_id: uuid::Uuid, + message_id: uuid::Uuid, reactions: Vec, ) { let Some(pubsub) = &self.pubsub else { @@ -196,6 +196,7 @@ impl MessageProducer { seq: 0, display_name: None, reactions: Some(reactions), + message_id: Some(message_id), }; pubsub.publish_room_message(room_id, &event).await; } diff --git a/libs/queue/types.rs b/libs/queue/types.rs index b6d1596..43049b5 100644 --- a/libs/queue/types.rs +++ b/libs/queue/types.rs @@ -35,6 +35,9 @@ pub struct RoomMessageEvent { /// Present when this event carries reaction updates for the message. #[serde(skip_serializing_if = "Option::is_none")] pub reactions: Option>, + /// Target message ID for reaction update events. + #[serde(skip_serializing_if = "Option::is_none")] + pub message_id: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -61,6 +64,7 @@ impl From for RoomMessageEvent { seq: e.seq, display_name: None, reactions: None, + message_id: None, } } } diff --git a/libs/room/src/service.rs b/libs/room/src/service.rs index 8ddd2d9..d928224 100644 --- a/libs/room/src/service.rs +++ b/libs/room/src/service.rs @@ -1065,6 +1065,7 @@ impl RoomService { display_name: Some(ai_display_name.clone()), in_reply_to: None, reactions: None, + message_id: None, }; room_manager.broadcast(room_id_inner, msg_event).await; room_manager.metrics.messages_sent.increment(1); @@ -1207,6 +1208,7 @@ impl RoomService { display_name: model_display_name, in_reply_to: None, reactions: None, + message_id: None, }; room_manager.broadcast(room_id, event).await; diff --git a/src/components/room/DiscordChatPanel.tsx b/src/components/room/DiscordChatPanel.tsx index 478a925..786b190 100644 --- a/src/components/room/DiscordChatPanel.tsx +++ b/src/components/room/DiscordChatPanel.tsx @@ -79,6 +79,7 @@ export function DiscordChatPanel({ room, isAdmin, onClose, onDelete }: DiscordCh (content: string) => { sendMessage(content, 'text', replyingTo?.id ?? undefined); setReplyingTo(null); + messageInputRef.current?.clearContent(); }, [sendMessage, replyingTo], ); diff --git a/src/components/room/message/MessageBubble.tsx b/src/components/room/message/MessageBubble.tsx index eed60d5..2acd2cc 100644 --- a/src/components/room/message/MessageBubble.tsx +++ b/src/components/room/message/MessageBubble.tsx @@ -11,7 +11,6 @@ import { Button } from '@/components/ui/button'; import { parseFunctionCalls, type FunctionCall } from '@/lib/functionCallParser'; import { formatMessageTime } from '../shared/formatters'; import { cn } from '@/lib/utils'; -import { SmilePlus } from 'lucide-react'; import { useUser, useRoom, useTheme } from '@/contexts'; import { memo, useMemo, useState, useCallback, useRef } from 'react'; import { ModelIcon } from '../icon-match'; @@ -20,6 +19,7 @@ import { MessageContent } from './MessageContent'; import { ThreadIndicator } from '../RoomThreadPanel'; import { getSenderDisplayName, getSenderModelId, getAvatarFromUiMessage, getSenderUserUid, isUserSender } from '../sender'; import { MessageReactions } from './MessageReactions'; +import { ReactionPicker } from './ReactionPicker'; // Sender colors — AI Studio clean palette const SENDER_COLORS: Record = { @@ -375,14 +375,7 @@ export const MessageBubble = memo(function MessageBubble({ className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity absolute -top-3 right-3" style={{ background: 'var(--card)', border: '1px solid var(--room-border)', borderRadius: 6 }} > - + {onReply && (
- {EMOJIS.map(e => ( + {COMMON_EMOJIS.map(emoji => ( ))}
@@ -448,7 +434,7 @@ export const IMEditor = forwardRef(function IMEdi > - {showEmoji && setShowEmoji(false)} onSelect={(n, u) => { editor?.chain().focus().insertContent({ type: 'emoji', attrs: { name: n, url: u } }).insertContent(' ').run(); setShowEmoji(false); }} p={p} />} + {showEmoji && setShowEmoji(false)} onSelect={(emoji) => { editor?.chain().focus().insertContent(emoji).insertContent(' ').run(); setShowEmoji(false); }} p={p} />}