import React, { useState, useRef, useEffect } from 'react' import ReactMarkdown from 'react-markdown' const QUICK_REACTIONS = ['๐Ÿ‘', 'โค๏ธ', '๐Ÿ”ฅ', '๐Ÿ˜‚', '๐Ÿ‘', '๐Ÿ˜ฎ'] export default function MessageBubble({ message, isMine, showAvatar, endsSequence = true, isNewlyArrived = false, prefersReducedMotion = false, onReact, onUnreact, onEdit, onDelete = null, onReport = null, onOpenImage = null, seenText = null }) { const [showPicker, setShowPicker] = useState(false) const [showActions, setShowActions] = useState(false) const [editing, setEditing] = useState(false) const [editBody, setEditBody] = useState(message.body ?? '') const [savingEdit, setSavingEdit] = useState(false) const [isArrivalVisible, setIsArrivalVisible] = useState(true) const editRef = useRef(null) const isDeleted = !!message.deleted_at const isEdited = !!message.edited_at const username = message.sender?.username ?? 'Unknown' const time = formatTime(message.created_at) const initials = username.charAt(0).toUpperCase() useEffect(() => { if (editing) { editRef.current?.focus() editRef.current?.setSelectionRange(editBody.length, editBody.length) } }, [editing, editBody.length]) useEffect(() => { if (prefersReducedMotion || !isNewlyArrived) { setIsArrivalVisible(true) return undefined } setIsArrivalVisible(false) const frame = window.requestAnimationFrame(() => setIsArrivalVisible(true)) return () => window.cancelAnimationFrame(frame) }, [isNewlyArrived, prefersReducedMotion]) const reactionGroups = groupReactions(message.reactions ?? []) const handleSaveEdit = async () => { const trimmed = editBody.trim() if (!trimmed || trimmed === message.body || savingEdit) return setSavingEdit(true) try { await onEdit(message.id, trimmed) setEditing(false) } finally { setSavingEdit(false) } } const handleEditKeyDown = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() handleSaveEdit() } if (e.key === 'Escape') { setEditing(false) setEditBody(message.body) } } return (
!isDeleted && !editing && setShowPicker(true)} onMouseLeave={() => { setShowPicker(false) setShowActions(false) }} >
{initials}
{showAvatar ? (
{username} {time}
) : null}
{!editing && !isDeleted ? ( ) : null} {editing ? (