import React from 'react'; import type { ContextMenuItem } from '../../stores/contextMenuStore'; import type { MessageWithUser } from '@backspace/shared'; import { saveImage, copyImageToClipboard } from '../../utils/imageActions'; import { useUIStore } from '../../stores/uiStore'; const QUICK_EMOJIS = ['👍', '❤️', '😂', '😮']; interface MessageMenuParams { message: MessageWithUser; selectedText: string; previousMessageId: string | null; isAuthor: boolean; isDm: boolean; canAddReactions: boolean; canSendMessages: boolean; canManageMessages: boolean; onReply: () => void; onEdit: () => void; onDelete: () => void; onReaction: (emoji: string) => void; onOpenEmojiPicker: () => void; onMarkUnread: (messageId: string) => void; imageUrl?: string | null; sourceUrl?: string | null; } export function buildMessageMenuItems(params: MessageMenuParams): ContextMenuItem[] { const { message, selectedText, previousMessageId, isAuthor, isDm, canAddReactions, canSendMessages, canManageMessages, onReply, onEdit, onDelete, onReaction, onOpenEmojiPicker, onMarkUnread, imageUrl, sourceUrl, } = params; const items: ContextMenuItem[] = []; // ── Image Actions (when right-clicking an image) ────────────────────── if (imageUrl) { items.push({ key: 'save-image', type: 'action', label: 'Save Image', icon: ( ), onClick: () => saveImage(imageUrl), }); items.push({ key: 'copy-image', type: 'action', label: 'Copy Image', icon: ( ), onClick: () => { copyImageToClipboard(imageUrl); }, }); items.push({ key: 'open-original', type: 'action', label: 'Open Original', icon: ( ), onClick: () => { window.open(imageUrl, '_blank', 'noopener'); }, }); items.push({ key: 'image-sep', type: 'separator' }); } // ── Link Actions (when URL text is suppressed) ────────────────────── if (sourceUrl) { items.push({ key: 'copy-link', type: 'action', label: 'Copy Link', icon: ( ), onClick: () => { navigator.clipboard.writeText(sourceUrl).then(() => { useUIStore.getState().addToast('Copied link', 'success', 3000); }).catch(() => { useUIStore.getState().addToast('Failed to copy link', 'warning', 3000); }); }, }); items.push({ key: 'open-link', type: 'action', label: 'Open Link', icon: ( ), onClick: () => { window.open(sourceUrl, '_blank', 'noopener'); }, }); items.push({ key: 'link-sep', type: 'separator' }); } // ── Quick Reaction Row ────────────────────────────────────────────────── if (canAddReactions) { items.push({ key: 'quick-reactions', type: 'custom', render: () => (
{QUICK_EMOJIS.map(emoji => ( ))}
), }); items.push({ key: 'reactions-sep', type: 'separator' }); } // ── Reply ─────────────────────────────────────────────────────────────── const canReply = isDm || canSendMessages; if (canReply) { items.push({ key: 'reply', type: 'action', label: 'Reply', icon: ( ), onClick: onReply, }); items.push({ key: 'reply-sep', type: 'separator' }); } // ── Clipboard group ───────────────────────────────────────────────────── items.push({ key: 'copy-selected', type: 'action', label: 'Copy Selected Text', hidden: selectedText.length === 0, icon: ( ), onClick: () => { navigator.clipboard.writeText(selectedText); }, }); items.push({ key: 'copy-text', type: 'action', label: 'Copy Text', hidden: !message.content || !!sourceUrl, icon: ( ), onClick: () => { navigator.clipboard.writeText(message.content ?? ''); }, }); items.push({ key: 'clipboard-sep', type: 'separator' }); // ── Mark Unread ───────────────────────────────────────────────────────── items.push({ key: 'mark-unread', type: 'action', label: 'Mark Unread', icon: ( ), onClick: () => { // '0' sentinel marks the entire channel as unread (when no previous message exists) onMarkUnread(previousMessageId ?? '0'); }, }); items.push({ key: 'unread-sep', type: 'separator' }); // ── Edit Message (author only) ────────────────────────────────────────── if (isAuthor) { items.push({ key: 'edit', type: 'action', label: 'Edit Message', icon: ( ), onClick: onEdit, }); } // ── Delete Message (author or moderator) ──────────────────────────────── const canDelete = isAuthor || canManageMessages; if (canDelete) { items.push({ key: 'delete', type: 'action', label: 'Delete Message', icon: ( ), onClick: onDelete, danger: true, }); } return items; }