// ConversationPreview.tsx import { useMemo } from 'react'; import { ConversationType, ConversationMarkType, ReceiveMessageOption, GroupAtType } from 'tuikit-atomicx-react/chat'; import { useUIKit, IconMuteFilled } from '@tencentcloud/uikit-base-component-react'; import cs from 'classnames'; import { useUIContext } from 'tuikit-atomicx-react/chat'; import { DEFAULT_GROUP_COMMON_AVATAR } from '../../../constant/avatar'; import { getConversationDraftAbstract } from '../../../utils/conversationDraft'; import { useTime } from '../../../hooks'; import { Avatar as DefaultAvatar } from 'tuikit-atomicx-react/chat'; import { ConversationActions as DefaultConversationActions } from '../ConversationActions'; import styles from './ConversationPreview.module.scss'; import { generateHighlightTitle, getLatestMessagePreview } from './utils'; import type { ConversationPreviewUIProps, ConversationPreviewProps, } from '../../../types/conversation'; import type { ConversationInfo } from 'tuikit-atomicx-react/chat'; function ConversationPreviewTitle( props: { conversation: ConversationInfo; highlightMatchString?: string | undefined; }, ) { const { conversation, highlightMatchString } = props; return (
{generateHighlightTitle(conversation, highlightMatchString).map((item, index) => ( {item.text} ))}
); } function ConversationPreviewTimestamp(props: { conversation: ConversationInfo }) { const { conversation } = props; const { getTimeStampAuto } = useTime(); const { lastMessage } = conversation; const lastTime = lastMessage?.timestamp?.getTime() || 0; return (
{getTimeStampAuto(lastTime)}
); } /** * Get group @ info preview text. */ function getAtInfoPreview(conversation: ConversationInfo, t: (key: string) => string): string | undefined { const { type, groupAtInfoList } = conversation || {}; if (type !== ConversationType.Group || !groupAtInfoList?.length) { return ''; } const atTypeList = groupAtInfoList.map(item => item.atType); if ( atTypeList.includes(GroupAtType.AtAllAtMe) || (atTypeList.includes(GroupAtType.AtAll) && atTypeList.includes(GroupAtType.AtMe)) ) { return `[${t('TUIConversation.at_all')}][${t('TUIConversation.someone_at_me')}]`; } if (atTypeList.includes(GroupAtType.AtAll)) { return `[${t('TUIConversation.at_all')}]`; } if (atTypeList.includes(GroupAtType.AtMe)) { return `[${t('TUIConversation.someone_at_me')}]`; } return undefined; } function ConversationPreviewAbstract(props: { conversation: ConversationInfo }) { const { conversation } = props; const { t } = useUIKit(); const { activeConversationID } = useUIContext(); const { draft } = conversation; const isActiveConversation = activeConversationID === conversation.conversationID; const draftTextAbstract = isActiveConversation ? '' : getConversationDraftAbstract(draft); const atInfoPreview = getAtInfoPreview(conversation, t); return (
{ draftTextAbstract ? ( <> {' '} { draftTextAbstract } ) : ( <> {atInfoPreview && } {getLatestMessagePreview(conversation, t, { ignoreDraft: isActiveConversation })} ) }
); } function ConversationPreviewUnread(props: { conversation: ConversationInfo }) { const { conversation } = props; const isMuted = conversation.receiveOption !== ReceiveMessageOption.Receive; let content; if (isMuted) { content = ; } else if (conversation.unreadCount > 99) { content = '99+'; } else if (conversation.unreadCount > 0) { content = conversation.unreadCount; } else if (conversation.conversationMarkList?.includes(ConversationMarkType.Unread)) { content = '1'; } else { content = null; } return (
{content}
); } function ConversationPreview(props: ConversationPreviewProps) { const { conversation, isSelected = false, enableActions = true, highlightMatchString, Preview = ConversationPreviewUI, Avatar = DefaultAvatar, ConversationActions = DefaultConversationActions, Title = ConversationPreviewTitle({ conversation, highlightMatchString }), LastMessageTimestamp = ConversationPreviewTimestamp({ conversation }), LastMessageAbstract = ConversationPreviewAbstract({ conversation }), Unread = ConversationPreviewUnread({ conversation }), onSelectConversation, actionsConfig, className, style, children, } = props; return ( {children} ); } function ConversationPreviewUI(props: ConversationPreviewUIProps) { const { conversation, isSelected, enableActions, Avatar = DefaultAvatar, ConversationActions = DefaultConversationActions, Title, LastMessageTimestamp, LastMessageAbstract, Unread, onSelectConversation, actionsConfig, className, style, children, } = props; const { activeConversation } = useUIContext(); const isMuted = conversation.receiveOption !== ReceiveMessageOption.Receive; const handleClick = () => { onSelectConversation?.(conversation); }; const showName = conversation.title || conversation.conversationID; const avatarUrl = conversation.type === ConversationType.Group ? conversation.avatarURL || DEFAULT_GROUP_COMMON_AVATAR : conversation.avatarURL || ''; const avatarUnreadCount = useMemo(() => { const hasUnreadMark = conversation.conversationMarkList?.includes(ConversationMarkType.Unread); if (isMuted) { return (conversation.unreadCount > 0 || hasUnreadMark) ? 1 : 0; } if (conversation.unreadCount > 0) { return conversation.unreadCount; } if (hasUnreadMark) { return 1; } return 0; }, [conversation, isMuted]); const avatarIsDotUnread = useMemo( () => !!(isMuted && avatarUnreadCount > 0), [isMuted, avatarUnreadCount], ); const preview = (
0 || conversation.conversationMarkList?.includes(ConversationMarkType.Unread)), [styles['conversationPreview--pin']]: conversation.isPinned, [styles['conversationPreview--mute']]: isMuted, })} style={style} onClick={handleClick} onSelect={event => event.preventDefault()} > {children || ( <>
{Title} {LastMessageTimestamp}
{LastMessageAbstract} {isMuted && (
)}
)}
); if (!enableActions) { return preview; } return ( {preview} ); } export { ConversationPreview, ConversationPreviewUI };