import type React from 'react'; import { useEffect, useState } from 'react'; import { useUIKit } from '@tencentcloud/uikit-base-component-react'; import classNames from 'classnames'; import { ContactStore, GroupStore } from 'tuikit-atomicx-react/chat'; import { ContactItemType } from '../../../types/contact'; import { useContactList } from '../hooks/useContactList'; import { BlacklistInfo } from './BlacklistInfo/BlacklistInfo'; import styles from './ContactInfo.module.scss'; import { FriendApplicationInfo } from './FriendApplicationInfo/FriendApplicationInfo'; import { FriendInfo } from './FriendInfo/FriendInfo'; import { GroupApplicationInfo } from './GroupApplicationInfo/GroupApplicationInfo'; import { GroupInfo } from './GroupInfo/GroupInfo'; import { SearchGroupInfo } from './SearchGroupInfo/SearchGroupInfo'; import { SearchUserInfo } from './SearchUserInfo/SearchUserInfo'; import type { ContactGroupItem, ContactInfoProps, } from '../../../types/contact'; import type { ContactInfo as ContactInfoType, GroupInfo as GroupInfoType, FriendApplicationInfo as FriendAppInfoType, GroupApplicationInfo as GroupAppInfoType } from 'tuikit-atomicx-react/chat'; const ContactInfo: React.FC = ({ contactItem, showActions = true, PlaceholderEmpty, FriendInfoComponent = FriendInfo, GroupInfoComponent = GroupInfo, BlacklistInfoComponent = BlacklistInfo, FriendApplicationInfoComponent = FriendApplicationInfo, GroupApplicationInfoComponent = GroupApplicationInfo, SearchGroupInfoComponent = SearchGroupInfo, SearchUserInfoComponent = SearchUserInfo, onClose, onSendMessage, onDeleteFriend, onAddToBlacklist, onUpdateFriendRemark, onRemoveFromBlacklist, onEnterGroup, onLeaveGroup, onDismissGroup, onFriendApplicationAction, onGroupApplicationAction, onAddFriend, onJoinGroup, className, style, }) => { const { friendList, blackList, friendApplicationList } = ContactStore(); const { joinedGroupList } = GroupStore(); const { activeContact, setActiveContact } = useContactList(); const [contactInfo, setContactInfo] = useState(undefined); const { direction } = useUIKit(); /** * Derive the displayed contact info from the source item + latest store snapshots. * Creates a new object instead of mutating in place (React needs fresh references). */ const deriveContactInfo = (source: ContactGroupItem | undefined): ContactGroupItem | undefined => { if (!source) { return undefined; } if (source.type === ContactItemType.SEARCH_USER) { const { userID } = source.data as ContactInfoType; const blackUser = blackList.find(u => u.userID === userID); if (blackUser) { return { type: ContactItemType.BLACK, data: blackUser }; } const friend = friendList.find(u => u.userID === userID); if (friend) { return { type: ContactItemType.FRIEND, data: friend }; } const application = friendApplicationList.find(item => item.userID === userID); if (application) { return { type: ContactItemType.FRIEND_REQUEST, data: application }; } return { ...source }; } if (source.type === ContactItemType.SEARCH_GROUP) { const searchData = source.data as GroupInfoType; const joined = joinedGroupList.find(g => g.groupID === searchData.groupID); if (joined) { return { type: ContactItemType.GROUP, data: { ...searchData, ...joined, groupName: joined.groupName || searchData.groupName, avatarURL: joined.avatarURL || searchData.avatarURL, }, }; } return { ...source }; } if (source.type === ContactItemType.FRIEND) { const { userID } = source.data as ContactInfoType; const blackUser = blackList.find(u => u.userID === userID); if (blackUser) { return { type: ContactItemType.BLACK, data: blackUser }; } const friend = friendList.find(u => u.userID === userID); return { type: ContactItemType.FRIEND, data: friend ?? (source.data as ContactInfoType) }; } if (source.type === ContactItemType.BLACK) { const { userID } = source.data as ContactInfoType; const blackUser = blackList.find(u => u.userID === userID); if (!blackUser) { const friend = friendList.find(u => u.userID === userID); if (friend) { return { type: ContactItemType.FRIEND, data: friend }; } return undefined; } return { type: ContactItemType.BLACK, data: blackUser }; } if (source.type === ContactItemType.FRIEND_REQUEST) { const application = friendApplicationList.find(item => item.userID === (source.data as FriendAppInfoType).userID); if (!application) { const friend = friendList.find(item => item.userID === (source.data as FriendAppInfoType).userID); if (friend) { return { type: ContactItemType.FRIEND, data: friend, }; } } } if (source.type === ContactItemType.GROUP) { const { groupID } = source.data as GroupInfoType; const joined = joinedGroupList.find(g => g.groupID === groupID); if (!joined) { return undefined; } return { type: ContactItemType.GROUP, data: joined }; } return { ...source }; }; useEffect(() => { const source = contactItem || activeContact; const derived = deriveContactInfo(source); if ( source?.type === ContactItemType.SEARCH_USER && derived?.type === ContactItemType.FRIEND_REQUEST ) { // Persist this transition so later request updates start from the application state. setActiveContact(derived); } setContactInfo(derived); }, [activeContact, contactItem, joinedGroupList, friendList, blackList, friendApplicationList, setActiveContact]); const handleCloseContactInfo = () => { setActiveContact(undefined); onClose?.(); }; return (
{!contactInfo && PlaceholderEmpty && (
{PlaceholderEmpty}
)} {ContactItemType.FRIEND === contactInfo?.type && ( )} { ContactItemType.GROUP === contactInfo?.type && ( ) } { ContactItemType.BLACK === contactInfo?.type && ( ) } { ContactItemType.FRIEND_REQUEST === contactInfo?.type && ( onFriendApplicationAction('accept', infoItem), })} {...(onFriendApplicationAction && { onRefuse: infoItem => onFriendApplicationAction('refuse', infoItem), })} /> ) } { ContactItemType.GROUP_REQUEST === contactInfo?.type && ( onGroupApplicationAction('accept', infoItem), })} {...(onGroupApplicationAction && { onRefuse: infoItem => onGroupApplicationAction('refuse', infoItem), })} /> ) } { ContactItemType.SEARCH_USER === contactInfo?.type && ( ) } { ContactItemType.SEARCH_GROUP === contactInfo?.type && ( ) }
); }; export default ContactInfo;