multica/apps/web/components/common/emoji-picker.tsx
Jiayuan 7c1aabbe3a feat(reactions): add emoji reactions for comments and issue descriptions
Add Slack-style emoji reactions to comments and issue descriptions with
full-stack support: database tables, REST API endpoints, real-time
WebSocket sync, optimistic UI updates, and inbox notifications.

- New `comment_reaction` and `issue_reaction` tables with migrations
- POST/DELETE endpoints for adding/removing reactions on both comments
  and issue descriptions
- Real-time WS events (reaction:added/removed, issue_reaction:added/removed)
- Shared ReactionBar component with quick emoji picker and full emoji-mart
  picker (lazy-loaded)
- Optimistic add/remove with rollback on failure
- Inbox notifications for comment author and issue creator when reacted to
- Reactions included in timeline, comment list, and issue detail responses
2026-03-30 22:37:59 +08:00

42 lines
1,015 B
TypeScript

"use client";
import { useEffect, useRef, useCallback } from "react";
import data from "@emoji-mart/data";
import { Picker } from "emoji-mart";
interface EmojiPickerProps {
onSelect: (emoji: string) => void;
}
export function EmojiPicker({ onSelect }: EmojiPickerProps) {
const containerRef = useRef<HTMLDivElement>(null);
const onSelectRef = useRef(onSelect);
onSelectRef.current = onSelect;
const handleSelect = useCallback((emoji: { native: string }) => {
onSelectRef.current(emoji.native);
}, []);
useEffect(() => {
const container = containerRef.current;
if (!container) return;
const picker = new Picker({
data,
onEmojiSelect: handleSelect,
theme: "auto",
set: "native",
previewPosition: "none",
skinTonePosition: "search",
maxFrequentRows: 2,
});
container.appendChild(picker as unknown as Node);
return () => {
container.replaceChildren();
};
}, [handleSelect]);
return <div ref={containerRef} />;
}