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'; import { useTransferStore } from '../../stores/transferStore'; 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; videoUrl?: string | null; videoFilename?: string | null; videoSize?: number | null; audioUrl?: string | null; audioFilename?: string | null; audioSize?: number | null; } export function buildMessageMenuItems(params: MessageMenuParams): ContextMenuItem[] { const { message, selectedText, previousMessageId, isAuthor, isDm, canAddReactions, canSendMessages, canManageMessages, onReply, onEdit, onDelete, onReaction, onOpenEmojiPicker, onMarkUnread, imageUrl, sourceUrl, videoUrl, videoFilename, videoSize, audioUrl, audioFilename, audioSize, } = 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); }, }); if (!sourceUrl) { items.push({ key: 'open-original', type: 'action', label: 'Open Original', icon: ( ), onClick: () => { window.open(imageUrl, '_blank', 'noopener'); }, }); } items.push({ key: 'image-sep', type: 'separator' }); } // ── Video Actions (when right-clicking a video attachment) ───────────── if (videoUrl && videoFilename) { items.push({ key: 'save-video', type: 'action', label: 'Save Video', icon: ( ), onClick: () => { void useTransferStore.getState().startDownload(videoUrl, { filename: videoFilename, size: videoSize ?? undefined, mimetype: 'video/*', tray: true, }); }, }); items.push({ key: 'video-sep', type: 'separator' }); } // ── Audio Actions (when right-clicking an audio attachment) ──────────── if (audioUrl && audioFilename) { items.push({ key: 'save-audio', type: 'action', label: 'Save Audio', icon: ( ), onClick: () => { void useTransferStore.getState().startDownload(audioUrl, { filename: audioFilename, size: audioSize ?? undefined, mimetype: 'audio/*', tray: true, }); }, }); items.push({ key: 'audio-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: () => (