import React from 'react'
import { Trash2, Reply, ChevronUp, MessageCircle } from 'lucide-react'
import { URL_REGEX } from './CollabChat.constants'
import { formatTime, formatDateSeparator, shouldShowDateSeparator } from './CollabChat.helpers'
import { MessageText } from './CollabChatMessageText'
import { LinkPreview } from './CollabChatLinkPreview'
import { ReactionBadge } from './CollabChatReactionBadge'
export function ChatMessages(props: any) {
const { currentUser, tripId, t, is12h, can, trip, canEdit, messages, setMessages, loading, setLoading, hasMore, setHasMore, loadingMore, setLoadingMore, text, setText, replyTo, setReplyTo, hoveredId, setHoveredId, sending, setSending, showEmoji, setShowEmoji, reactMenu, setReactMenu, deletingIds, setDeletingIds, deleteTimersRef, containerRef, messagesRef, scrollRef, textareaRef, emojiBtnRef, isAtBottom, scrollToBottom, checkAtBottom, handleLoadMore, handleTextChange, handleSend, handleKeyDown, handleDelete, handleReact, handleEmojiSelect, isOwn, isEmojiOnly } = props
return (
<>
{/* Messages */}
{messages.length === 0 ? (
{t('collab.chat.empty')}
{t('collab.chat.emptyDesc') || ''}
) : (
{hasMore && (
)}
{messages.map((msg, idx) => {
const own = isOwn(msg)
const prevMsg = messages[idx - 1]
const nextMsg = messages[idx + 1]
const isNewGroup = idx === 0 || String(prevMsg?.user_id) !== String(msg.user_id)
const isLastInGroup = !nextMsg || String(nextMsg?.user_id) !== String(msg.user_id)
const showDate = shouldShowDateSeparator(msg, prevMsg)
const showAvatar = !own && isLastInGroup
const bigEmoji = isEmojiOnly(msg.text)
const hasReply = msg.reply_text || msg.reply_to
// Deleted message placeholder
if (msg._deleted) {
return (
{showDate && (
{formatDateSeparator(msg.created_at, t)}
)}
{msg.username} {t('collab.chat.deletedMessage') || 'deleted a message'} ยท {formatTime(msg.created_at, is12h)}
)
}
// Bubble border radius โ iMessage style tails
const br = own
? `18px 18px ${isLastInGroup ? '4px' : '18px'} 18px`
: `18px 18px 18px ${isLastInGroup ? '4px' : '18px'}`
return (
{/* Date separator */}
{showDate && (
{formatDateSeparator(msg.created_at, t)}
)}
{/* Avatar slot for others */}
{!own && (
{showAvatar && (
msg.user_avatar ? (

) : (
{(msg.username || '?')[0].toUpperCase()}
)
)}
)}
{/* Username for others at group start */}
{!own && isNewGroup && (
{msg.username}
)}
{/* Bubble */}
setHoveredId(msg.id)}
onMouseLeave={() => setHoveredId(null)}
onContextMenu={e => { e.preventDefault(); if (canEdit) setReactMenu({ msgId: msg.id, x: e.clientX, y: e.clientY }) }}
onTouchEnd={e => {
const now = Date.now()
const lastTap = Number(e.currentTarget.dataset.lastTap) || 0
if (now - lastTap < 300 && canEdit) {
e.preventDefault()
const touch = e.changedTouches?.[0]
if (touch) setReactMenu({ msgId: msg.id, x: touch.clientX, y: touch.clientY })
}
e.currentTarget.dataset.lastTap = String(now)
}}
>
{bigEmoji ? (
{msg.text}
) : (
{/* Inline reply quote */}
{hasReply && (
{msg.reply_username || ''}
{(msg.reply_text || '').slice(0, 80)}
)}
{hasReply ? (
) :
}
{(msg.text.match(URL_REGEX) || []).slice(0, 1).map(url => (
{ if (isAtBottom.current) setTimeout(() => scrollToBottom('smooth'), 50) }} />
))}
)}
{/* Hover actions */}
{own && canEdit && (
)}
{/* Reactions โ iMessage style floating badge */}
{msg.reactions?.length > 0 && (
{msg.reactions.map(r => {
const myReaction = r.users.some(u => String(u.user_id) === String(currentUser.id))
return (
{ if (canEdit) handleReact(msg.id, r.emoji) }} />
)
})}
)}
{/* Timestamp โ only on last message of group */}
{isLastInGroup && (
{formatTime(msg.created_at, is12h)}
)}
)
})}
)}
>
)
}