diff --git a/src/app/features/room/thread/ThreadTimeline.tsx b/src/app/features/room/thread/ThreadTimeline.tsx index e684f0a44..2f6f60e91 100644 --- a/src/app/features/room/thread/ThreadTimeline.tsx +++ b/src/app/features/room/thread/ThreadTimeline.tsx @@ -545,9 +545,19 @@ export function ThreadTimeline({ room, thread, editor }: ThreadTimelineProps) { [room, thread, setReplyDraft, editor], ); + // Non-thread relations (reactions, edits) that target the thread root live only in + // the room's main timeline set (matrix-js-sdk Room.eventShouldLiveIn), so lookups + // for the root must use the room set instead of the thread set. + const getRelationTimelineSet = useCallback( + (eventId: string) => + eventId === thread.id ? room.getUnfilteredTimelineSet() : thread.getUnfilteredTimelineSet(), + [room, thread], + ); + const handleReactionToggle = useCallback( (targetEventId: string, key: string, shortcode?: string) => { - const timelineSet = thread.getUnfilteredTimelineSet(); + const isRoot = targetEventId === thread.id; + const timelineSet = getRelationTimelineSet(targetEventId); const relations = getEventReactions(timelineSet, targetEventId); const allReactions = relations?.getSortedAnnotationsByKey() ?? []; const [, reactionsSet] = allReactions.find(([k]) => k === key) ?? []; @@ -563,13 +573,14 @@ export function ThreadTimeline({ room, thread, editor }: ThreadTimelineProps) { (reactions.find(eventWithShortcode)?.getContent().shortcode as string | undefined); mx.sendEvent( room.roomId, - thread.id, + // A reaction on the root is a main-timeline event, not a thread reply. + isRoot ? null : thread.id, // eslint-disable-next-line @typescript-eslint/no-explicit-any MessageEvent.Reaction as any, getReactionContent(targetEventId, key, rShortcode), ); }, - [mx, room, thread], + [mx, room, thread, getRelationTimelineSet], ); const handleEdit = useCallback( @@ -715,7 +726,7 @@ export function ThreadTimeline({ room, thread, editor }: ThreadTimelineProps) { ): ReactNode => { const mEventId = mEvent.getId(); if (!mEventId) return null; - const timelineSet = thread.getUnfilteredTimelineSet(); + const timelineSet = getRelationTimelineSet(mEventId); const reactionRelations = getEventReactions(timelineSet, mEventId); const reactions = reactionRelations?.getSortedAnnotationsByKey(); const hasReactions = !!reactions && reactions.length > 0; @@ -783,7 +794,6 @@ export function ThreadTimeline({ room, thread, editor }: ThreadTimelineProps) { ); }, [ - thread, room, messageSpacing, messageLayout, @@ -810,6 +820,7 @@ export function ThreadTimeline({ room, thread, editor }: ThreadTimelineProps) { lotusTerminal, mx, renderMessageContent, + getRelationTimelineSet, ], );