import { formatTime } from "../../../utils/utils"; import type { Message as MessageType } from "../../../core/types"; import defaultAvatar from "../../../resources/images/default-avatar.png"; import Quote from "../core/Quote"; import { parse } from "marked"; import { useEffect, useState } from "react"; interface MessageProps { message: MessageType; isAuthor: boolean; onProfileClick: (username: string) => void; onContextMenu: (e: React.MouseEvent, message: MessageType) => void; isLoadingProfile?: boolean; isDm?: boolean; } export function Message({ message, isAuthor, onProfileClick, onContextMenu, isLoadingProfile = false, isDm = false }: MessageProps) { const [formattedMessage, setFormattedMessage] = useState({ __html: "" }); useEffect(() => { (async () => { const DOMPurify = await import("dompurify"); setFormattedMessage({ __html: DOMPurify.default.sanitize( await parse(message.content.trim()) ).trim() }); })(); }, [message]); function handleContextMenu(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); onContextMenu(e, message); } return (
{/* Add profile picture for received messages */} {!isAuthor && !isDm && (
{message.username} !isLoadingProfile && onProfileClick(message.username)} style={{ cursor: isLoadingProfile ? "default" : "pointer" }} className={isLoadingProfile ? "loading" : ""} onError={(e) => { const target = e.target as HTMLImageElement; target.src = defaultAvatar; }} />
)} {!isAuthor && !isDm && (
!isLoadingProfile && onProfileClick(message.username)} style={{ cursor: isLoadingProfile ? "default" : "pointer" }}> {message.username}
)} {/* Add reply preview if this is a reply */} {message.reply_to && ( {message.reply_to.username} {message.reply_to.content} )}
{formatTime(message.timestamp)} {message.is_edited ? " (edited)" : undefined} {isAuthor && message.is_read && ( )}
); }