// 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}
>
{children || (
<>
{Title}
{LastMessageTimestamp}
{LastMessageAbstract}
{isMuted && (
)}
>
)}
);
if (!enableActions) {
return preview;
}
return (
{preview}
);
}
export { ConversationPreview, ConversationPreviewUI };