-
Notifications
You must be signed in to change notification settings - Fork 163
Expand file tree
/
Copy pathEmojiReaction.tsx
More file actions
74 lines (63 loc) · 2.96 KB
/
Copy pathEmojiReaction.tsx
File metadata and controls
74 lines (63 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import * as React from 'react';
import { useRoomContext } from '../../context';
import { setupDataMessageHandler } from '@livekit/components-core';
import { DataTopic } from '@livekit/components-core';
import { useMaybeParticipantContext } from '../../context';
import { useEmojiReactionContext } from '../../context/EmojiReactionContext';
export interface EmojiReactionProps {
className?: string;
}
export function EmojiReaction({ className }: EmojiReactionProps) {
const room = useRoomContext();
const participant = useMaybeParticipantContext();
const { reactions: globalReactions } = useEmojiReactionContext();
const [localReactions, setLocalReactions] = React.useState<Array<{ emoji: string; id: string; timestamp: number }>>([]);
// Filter reactions for this specific participant
const participantReactions = React.useMemo(() => {
const fromContext = globalReactions
.filter(reaction => reaction.from.identity === participant?.identity)
.map(reaction => ({
emoji: reaction.emoji,
id: reaction.id,
timestamp: reaction.timestamp,
}));
return [...fromContext, ...localReactions];
}, [globalReactions, localReactions, participant?.identity]);
React.useEffect(() => {
if (!room || !participant) return;
const { messageObservable } = setupDataMessageHandler(room, DataTopic.REACTIONS);
const subscription = messageObservable.subscribe((message) => {
// Listen for messages from this participant (excluding local participant since they're handled by context)
if (message.from?.identity === participant.identity && !message.from?.isLocal) {
try {
const data = JSON.parse(new TextDecoder().decode(message.payload));
if (data.emoji) {
const reactionId = `${Date.now()}-${Math.random()}`;
setLocalReactions(prev => [...prev, {
emoji: data.emoji,
id: reactionId,
timestamp: Date.now()
}]);
// Remove reaction after 3 seconds
setTimeout(() => {
setLocalReactions(prev => prev.filter(r => r.id !== reactionId));
}, 3000);
}
} catch (error) {
console.error('Failed to parse emoji reaction:', error);
}
}
});
return () => subscription.unsubscribe();
}, [room, participant]);
if (participantReactions.length === 0) return null;
return (
<div className={`lk-emoji-reactions ${className || ''}`}>
{participantReactions.map((reaction) => (
<div key={reaction.id} className="lk-emoji-reaction">
{reaction.emoji}
</div>
))}
</div>
);
}