import React from "react"; import { useFileDownload } from "../../../hooks/useWorkflows"; import { Message, Document } from "./dashboardChatAreaTypes"; import messageStyles from './DashboardChatAreaStyles/DashboardChatMessages.module.css'; interface MessageItemProps { message: Message; index: number; onFilePreview?: (file: any) => void; } // Helper function to format file size const formatFileSize = (bytes?: number): string => { if (!bytes) return ''; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(1024)); return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i]; }; // Helper function to get file icon based on type or extension const getFileIcon = (type?: string, ext?: string): string => { // Use extension first if available, then fall back to MIME type const extension = ext?.toLowerCase(); const mimeType = type?.toLowerCase(); // Check extension first if (extension) { // Images if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(extension)) return '🖼️'; // Videos if (['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv'].includes(extension)) return '🎥'; // Audio if (['mp3', 'wav', 'aac', 'flac', 'ogg', 'wma'].includes(extension)) return '🎵'; // Documents if (extension === 'pdf') return '📕'; if (['doc', 'docx'].includes(extension)) return '📘'; if (['xls', 'xlsx'].includes(extension)) return '📊'; if (['ppt', 'pptx'].includes(extension)) return '📋'; if (['txt', 'md', 'rtf'].includes(extension)) return '📝'; // Archives if (['zip', 'rar', '7z', 'tar', 'gz'].includes(extension)) return '📦'; // Code files if (['js', 'ts', 'jsx', 'tsx', 'html', 'css', 'py', 'java', 'cpp', 'c', 'php'].includes(extension)) return '💻'; } // Fall back to MIME type if extension didn't match if (mimeType) { if (mimeType.includes('image')) return '🖼️'; if (mimeType.includes('video')) return '🎥'; if (mimeType.includes('audio')) return '🎵'; if (mimeType.includes('pdf')) return '📕'; if (mimeType.includes('text')) return '📝'; if (mimeType.includes('word') || mimeType.includes('document')) return '📘'; if (mimeType.includes('excel') || mimeType.includes('spreadsheet')) return '📊'; if (mimeType.includes('powerpoint') || mimeType.includes('presentation')) return '📋'; if (mimeType.includes('zip') || mimeType.includes('archive')) return '📦'; } return '📄'; }; const MessageItem: React.FC = ({ message, onFilePreview }) => { const { downloadFile, isDownloading } = useFileDownload(); // Debug: Log what the MessageItem is receiving console.log(`🎭 MessageItem rendering:`, { messageId: message.id, messageRole: message.role, content: message.content?.substring(0, 50) + (message.content?.length > 50 ? '...' : ''), contentLength: message.content?.length || 0, hasContent: !!message.content, hasDocuments: !!(message.documents), documentsArray: message.documents, documentsLength: message.documents?.length || 0, documentsCheck: message.documents && message.documents.length > 0, // Timestamp debugging timestamp: message.timestamp, hasTimestamp: !!message.timestamp, timestampType: typeof message.timestamp, }); const handleDocumentClick = (document: Document) => { console.log(`🖱️ Document clicked:`, document); // If there's a downloadUrl, use it; otherwise try the url const downloadLink = document.downloadUrl || document.url; if (downloadLink) { // Open the document in a new tab window.open(downloadLink, '_blank'); } }; const handlePreview = (document: Document, e: React.MouseEvent) => { e.stopPropagation(); console.log(`👁️ Preview requested for:`, document); // Use fileId if available, otherwise try to use id as fallback const fileId = document.fileId || parseInt(document.id || '0'); if (!fileId || isNaN(fileId)) { console.error('❌ Invalid file ID for preview:', document); return; } console.log('✅ MessageItem - Previewing file:', { fileId, document }); // Call the parent callback to show preview in the file preview quadrant if (onFilePreview) { onFilePreview({ id: fileId.toString(), name: document.name, mimeType: document.type || 'application/octet-stream', size: document.size, fileId: fileId }); } }; const handleDownload = async (document: Document, e: React.MouseEvent) => { e.stopPropagation(); console.log(`⬇️ Download requested for:`, document); // Use fileId if available, otherwise try to use id as fallback const fileId = document.fileId || parseInt(document.id || '0'); if (!fileId) { console.error('❌ No file ID for download:', document); return; } // Construct filename with extension if available const fileName = document.ext ? `${document.name}.${document.ext}` : document.name; console.log(`💾 Downloading file ${fileId} as "${fileName}"`); await downloadFile(fileId, fileName); }; // Debug: Log document check before rendering const hasDocuments = message.documents && message.documents.length > 0; console.log(`🔍 About to check documents:`, { hasDocuments: !!(message.documents), documentsLength: message.documents?.length || 0, willRenderFiles: hasDocuments }); // Log if no documents if (!hasDocuments) { console.log(`📭 No documents to render for message ${message.id}`); } // Format timestamp const formatTimestamp = (timestamp?: string) => { console.log(`⏰ formatTimestamp called with:`, { timestamp, type: typeof timestamp, hasValue: !!timestamp }); if (!timestamp) { console.log(`⏰ No timestamp provided, returning empty string`); return ''; } const date = new Date(timestamp); console.log(`⏰ Parsed date:`, { date, isValid: !isNaN(date.getTime()) }); if (isNaN(date.getTime())) { console.log(`⏰ Invalid date, returning empty string`); return ''; } const now = new Date(); const isToday = date.toDateString() === now.toDateString(); let formatted = ''; if (isToday) { formatted = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } else { formatted = date.toLocaleDateString([], { month: 'short', day: 'numeric' }) + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } console.log(`⏰ Formatted timestamp:`, { formatted }); return formatted; }; return (
{message.role === 'user' ? 'You' : message.agentName} {message.timestamp && ( • {formatTimestamp(message.timestamp)} )}
{message.content || ( [No message content] )}
{hasDocuments && (
📎 {message.role === 'user' ? 'Uploaded' : 'Attached'} Files ({message.documents!.length})
{message.documents!.map((document, docIndex) => { console.log(`📄 Rendering document ${docIndex + 1}:`, document); return (
handleDocumentClick(document)} title={`Click to open ${document.name}`} > {getFileIcon(document.type, document.ext)}
{document.ext ? `${document.name}.${document.ext}` : document.name}
{document.size && (
{formatFileSize(document.size)}
)}
); })}
)}
); }; export default MessageItem;