import React, { useRef, useState } from 'react'; import { X, Clock, Send, GripVertical, Zap, Sparkles, ChevronDown, ChevronUp } from 'lucide-react'; import { Button } from './ui/button'; import { ImageData } from '../types/message'; import { defineMessages, useIntl } from '../i18n'; const i18n = defineMessages({ paused: { id: 'messageQueue.paused', defaultMessage: 'Paused', }, next: { id: 'messageQueue.next', defaultMessage: 'Next', }, sendNow: { id: 'messageQueue.sendNow', defaultMessage: 'Send this message now', }, expandQueue: { id: 'messageQueue.expandQueue', defaultMessage: 'Expand queue', }, queuePausedCompact: { id: 'messageQueue.queuePausedCompact', defaultMessage: 'Queue paused - click "Send" or add new message to resume', }, queuePaused: { id: 'messageQueue.queuePaused', defaultMessage: 'Queue Paused', }, messageQueue: { id: 'messageQueue.messageQueue', defaultMessage: 'Message Queue', }, messageCount: { id: 'messageQueue.messageCount', defaultMessage: '{count, plural, one {# message} other {# messages}} {status}', }, waiting: { id: 'messageQueue.waiting', defaultMessage: 'waiting', }, queued: { id: 'messageQueue.queued', defaultMessage: 'queued', }, clearAll: { id: 'messageQueue.clearAll', defaultMessage: 'Clear All', }, collapseQueue: { id: 'messageQueue.collapseQueue', defaultMessage: 'Collapse queue', }, queuePausedExpanded: { id: 'messageQueue.queuePausedExpanded', defaultMessage: 'Queue paused by interruption. Use "Send Now" or add a new message to resume.', }, save: { id: 'messageQueue.save', defaultMessage: 'Save', }, cancel: { id: 'messageQueue.cancel', defaultMessage: 'Cancel', }, clickToEdit: { id: 'messageQueue.clickToEdit', defaultMessage: '{content} (Click to edit)', }, cannotSendWhileEditing: { id: 'messageQueue.cannotSendWhileEditing', defaultMessage: 'Cannot send while editing', }, stopAndSend: { id: 'messageQueue.stopAndSend', defaultMessage: 'Stop current processing and send this message now', }, removeFromQueue: { id: 'messageQueue.removeFromQueue', defaultMessage: 'Remove this message from queue', }, dragToReorder: { id: 'messageQueue.dragToReorder', defaultMessage: 'Drag messages to reorder priority', }, }); export interface QueuedMessage { id: string; content: string; timestamp: number; images: ImageData[]; } interface MessageQueueProps { queuedMessages: QueuedMessage[]; onRemoveMessage: (id: string) => void; onClearQueue: () => void; onStopAndSend?: (messageId: string) => void; onEditMessage?: (messageId: string, newContent: string) => void; onTriggerQueueProcessing?: () => void; editingMessageIdRef?: React.MutableRefObject; onReorderMessages?: (reorderedMessages: QueuedMessage[]) => void; sendingMessageIds?: ReadonlySet; className?: string; isPaused?: boolean; } export const MessageQueue: React.FC = ({ queuedMessages, onRemoveMessage, onClearQueue, onStopAndSend, onEditMessage, onTriggerQueueProcessing, editingMessageIdRef, onReorderMessages, sendingMessageIds, className = '', isPaused = false, }) => { const intl = useIntl(); const [isExpanded, setIsExpanded] = useState(true); const [draggedItem, setDraggedItem] = useState(null); const [dragOverItem, setDragOverItem] = useState(null); const [hoveredMessage, setHoveredMessage] = useState(null); const [editingMessage, setEditingMessage] = useState(null); const [editContent, setEditContent] = useState(''); const onTriggerQueueProcessingRef = useRef(onTriggerQueueProcessing); onTriggerQueueProcessingRef.current = onTriggerQueueProcessing; const isSendingMessage = (messageId: string) => sendingMessageIds?.has(messageId) ?? false; if (queuedMessages.length === 0) { return null; } const handleDragStart = (e: React.DragEvent, messageId: string) => { if (isSendingMessage(messageId)) { e.preventDefault(); return; } setDraggedItem(messageId); e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', messageId); }; const handleDragOver = (e: React.DragEvent, messageId: string) => { if (isSendingMessage(messageId)) { return; } e.preventDefault(); e.dataTransfer.dropEffect = 'move'; setDragOverItem(messageId); }; const handleDragLeave = () => { setDragOverItem(null); }; const handleDrop = (e: React.DragEvent, targetMessageId: string) => { e.preventDefault(); if (!draggedItem || !onReorderMessages || isSendingMessage(targetMessageId)) return; const draggedIndex = queuedMessages.findIndex((msg) => msg.id === draggedItem); const targetIndex = queuedMessages.findIndex((msg) => msg.id === targetMessageId); if (draggedIndex === -1 || targetIndex === -1 || draggedIndex === targetIndex) { setDraggedItem(null); setDragOverItem(null); return; } const newMessages = [...queuedMessages]; const [removed] = newMessages.splice(draggedIndex, 1); newMessages.splice(targetIndex, 0, removed); onReorderMessages(newMessages); setDraggedItem(null); setDragOverItem(null); }; const handleDragEnd = () => { setDraggedItem(null); setDragOverItem(null); }; const formatTimestamp = (timestamp: number) => { const now = Date.now(); const diff = now - timestamp; if (diff < 60000) return 'now'; if (diff < 3600000) return `${Math.floor(diff / 60000)}m`; return `${Math.floor(diff / 3600000)}h`; }; const nextMessage = queuedMessages[0]; const remainingCount = queuedMessages.length - 1; const nextMessageIsSending = isSendingMessage(nextMessage.id); const hasSendingMessages = queuedMessages.some((message) => isSendingMessage(message.id)); // Compact View if (!isExpanded) { return (
{/* Compact Header */}
setIsExpanded(true)} >
{isPaused ? (
) : (
)} {isPaused ? intl.formatMessage(i18n.paused) : intl.formatMessage(i18n.next)}
{/* Next message preview */}

{nextMessage.content.length > 40 ? `${nextMessage.content.substring(0, 40)}...` : nextMessage.content}

{/* Queue count */} {remainingCount > 0 && (
+{remainingCount}
)}
{/* Quick Send Now button */} {onStopAndSend && ( )} {/* Expand button */}
{/* Paused state indicator */} {isPaused && (
{intl.formatMessage(i18n.queuePausedCompact)}
)}
); } // Expanded View return (
{/* Expanded Header */}
{isPaused ? (
) : (
)}
{isPaused ? intl.formatMessage(i18n.queuePaused) : intl.formatMessage(i18n.messageQueue)} {intl.formatMessage(i18n.messageCount, { count: queuedMessages.length, status: isPaused ? intl.formatMessage(i18n.waiting) : intl.formatMessage(i18n.queued), })}
{queuedMessages.length > 1 && ( )} {/* Collapse button */}
{/* Status Banner for Paused State */} {isPaused && (
{intl.formatMessage(i18n.queuePausedExpanded)}
)} {/* Message Bubbles */}
{queuedMessages.map((message, index) => { const isSending = isSendingMessage(message.id); const isEditing = editingMessage === message.id; return (
handleDragStart(e, message.id)} onDragOver={(e) => handleDragOver(e, message.id)} onDragLeave={handleDragLeave} onDrop={(e) => handleDrop(e, message.id)} onDragEnd={handleDragEnd} onMouseEnter={() => setHoveredMessage(message.id)} onMouseLeave={() => setHoveredMessage(null)} > {/* Main message bubble */}
{/* Priority indicator */}
{index + 1}
{/* Drag handle */} {onReorderMessages && !isSending && (
)}
{/* Message content */}
{isEditing ? (