import { MESSAGE_CUSTOM_TYPE } from '@linktr.ee/messaging-taxonomy' import classNames from 'classnames' import React from 'react' import { ChannelPreviewUIComponentProps, useChatContext, } from 'stream-chat-react' import { useChannelStar } from '../../hooks/useChannelStar' import { formatRelativeTime } from '../../utils/formatRelativeTime' import { getMessageDisplayText } from '../../utils/getMessageDisplayText' import { resolveConversationParticipant } from '../../utils/resolveConversationParticipant' import { resolveParticipantDisplayName } from '../../utils/resolveParticipantDisplayName' import { Avatar } from '../Avatar' import { isChatbotMessage } from '../CustomMessage/MessageTag' import { useChannelListContext } from './ChannelListContext' /** * Custom channel preview that handles selection */ const CustomChannelPreview = React.memo( (props) => { const { channel, unread } = props const { selectedChannel, onChannelSelect, debug, channelPreview, renderMessagePreview, viewerLanguage, } = useChannelListContext() const { client } = useChatContext() const isSelected = selectedChannel?.id === channel?.id const isChannelStarred = useChannelStar(channel) if (channelPreview) { const ChannelPreview = channelPreview return ( ) } const handleClick = () => { if (channel) { onChannelSelect(channel) } } const handleKeyDown = (event: React.KeyboardEvent) => { const isActivationKey = event.key === 'Enter' || event.key === ' ' const isRepeatedKeydown = event.repeat if (!isActivationKey || isRepeatedKeydown) return event.preventDefault() handleClick() } // Get participant info const participant = resolveConversationParticipant( channel?.state?.members, client?.userID, channel?.type ) const participantName = resolveParticipantDisplayName(participant?.user) const participantImage = participant?.user?.image // Get last non-system message for preview const lastMessage = (() => { const messages = channel?.state?.messages if (!messages?.length) return undefined for (let i = messages.length - 1; i >= 0; i--) { if (messages[i].type !== 'system') return messages[i] } return undefined })() const getLastMessageText = () => { const displayText = getMessageDisplayText({ message: lastMessage, viewerLanguage, }) const { custom_type, attachment_content_type } = lastMessage?.metadata || {} if (custom_type === MESSAGE_CUSTOM_TYPE.TIP) { return displayText ? displayText : 'Sent a tip' } if (custom_type === MESSAGE_CUSTOM_TYPE.PAID) { return displayText ? displayText : 'Sent a message' } if (custom_type === MESSAGE_CUSTOM_TYPE.ATTACHMENT) { if (attachment_content_type === 'text') { return '🔒 Sent a locked message' } if (attachment_content_type === 'media') { return '🔒 Sent a locked attachment' } } if (displayText) return displayText const attachment = lastMessage?.attachments?.[0] if (attachment) { // Link previews - show the actual URL if (attachment.og_scrape_url) return attachment.og_scrape_url // Type-based detection if (attachment.type === 'image') return '📷 Sent an image' if (attachment.type === 'video') return '🎥 Sent a video' if (attachment.type === 'audio') return '🎵 Sent audio' if (attachment.type === 'file') return '📎 Sent a file' // Fallback return '📎 Sent an attachment' } return 'No messages yet' } const lastMessageText = getLastMessageText() const lastMessageTime = lastMessage?.created_at ? formatRelativeTime(new Date(lastMessage.created_at)) : '' const isLastMessageFromChatbot = lastMessage ? isChatbotMessage(lastMessage) : false const messagePreview = renderMessagePreview ? renderMessagePreview(lastMessage, lastMessageText) : `${isLastMessageFromChatbot ? '✨ ' : ''}${lastMessageText}` // Use the unread prop passed by Stream Chat (reactive and updates automatically) const unreadCount = unread ?? 0 if (debug) { console.log('📺 [ChannelList] 📋 CHANNEL PREVIEW RENDER', { channelId: channel?.id, isSelected, participantName, unreadCount, hasTimestamp: !!lastMessageTime, }) } return (
{/* Avatar */} {/* Content column */}
{/* Name and timestamp row */}

{isChannelStarred && ( Starred conversation. )} {participantName}

{lastMessageTime && ( {lastMessageTime} )}
{/* Message and unread badge row */}

{messagePreview}

{unreadCount > 0 && ( {unreadCount > 99 ? '99+' : unreadCount} )}
) } ) export default CustomChannelPreview CustomChannelPreview.displayName = 'CustomChannelPreview'