import { useCallback, useEffect, useRef, useState } from 'react'; import { useUIKit, IconLoading } from '@tencentcloud/uikit-base-component-react'; import cs from 'classnames'; import { useMessageActionStore, View, Avatar } from 'tuikit-atomicx-react/chat'; import { Dialog } from '../../../baseComp/Dialog'; import classes from './ReadReceiptInfo.module.scss'; import type { MessageInfo } from 'tuikit-atomicx-react/chat'; interface IReadReceiptInfoProps { /** Message */ message: MessageInfo; /** Whether the modal is open */ open: boolean; /** Read count */ readCount?: number; /** Unread count */ unreadCount?: number; /** Callback fired when the modal is closed */ onClose?: (e?: unknown, reason?: 'backdropClick' | 'escapeKeyDown') => void | undefined; /** Additional class names for styling */ className?: string | undefined; /** Custom style */ style?: React.CSSProperties | undefined; } // Tab button component function TabButton({ active, label, onClick, }: { active: boolean; label: string; onClick: () => void; }) { return ( ); } // User list item component function UserItem({ user }: { user: { userID: string; nickname?: string; avatarURL?: string; friendRemark?: string; nameCard?: string } }) { const displayName = user.friendRemark || user.nameCard || user.nickname || user.userID; return ( {displayName} ); } // Loading component function Loading({ text }: { text: string }) { return ( {text} ); } // Empty state component function Empty({ text }: { text: string }) { return ( {text} ); } // List end component function ListEnd({ text }: { text: string }) { return ( {text} ); } // User list component function UserList({ users, loading, hasMore, onScroll, emptyText, loadingText, noMoreText, listRef, }: { users: Array<{ userID: string; nickname?: string; avatarURL?: string; friendRemark?: string; nameCard?: string }>; loading: boolean; hasMore: boolean; onScroll: (event: React.UIEvent) => void; emptyText: string; loadingText: string; noMoreText: string; listRef: React.RefObject; }) { const [isVisible, setIsVisible] = useState(false); useEffect(() => { let timer: any; if (users.length > 0 && !loading) { timer = setTimeout(() => { setIsVisible(true); }, 50); } else if (users.length === 0) { setIsVisible(false); } return () => clearTimeout(timer); }, [users.length, loading]); const renderUserList = () => { if (users.length === 0) { if (loading) { return ; } return ; } const listContainerClass = `${classes['read-receipt-info__user-list-container']} ${ isVisible ? classes['read-receipt-info__user-list-container--visible'] : '' }`; return (
{users.map(user => )} {loading && } {!hasMore && }
); }; return ( {renderUserList()} ); } function ReadReceiptInfo(props: IReadReceiptInfoProps) { const { open, message, readCount = 0, unreadCount = 0, className, onClose, style, } = props; const { t } = useUIKit(); const [activeTab, setActiveTab] = useState<'read' | 'unread'>('read'); const [readLoading, setReadLoading] = useState(false); const [unreadLoading, setUnreadLoading] = useState(false); const [loadMoreLoading, setLoadMoreLoading] = useState(false); const readListRef = useRef(null); const unreadListRef = useRef(null); const { readMemberList, unreadMemberList, hasMoreReadMembers, hasMoreUnreadMembers, loadReadMembers, loadUnreadMembers, loadMoreMembers, } = useMessageActionStore(message); const loadReadUsers = useCallback(async () => { setReadLoading(true); try { await loadReadMembers(100); } catch (error) { console.error('Failed to load read users:', error); } finally { setReadLoading(false); } }, [loadReadMembers]); const loadUnreadUsers = useCallback(async () => { setUnreadLoading(true); try { await loadUnreadMembers(50); } catch (error) { console.error('Failed to load unread users:', error); } finally { setUnreadLoading(false); } }, [loadUnreadMembers]); // Handle scroll to load more const handleScroll = useCallback((event: React.UIEvent) => { const { currentTarget } = event; const { scrollTop, scrollHeight, clientHeight } = currentTarget; if (scrollHeight - scrollTop - clientHeight >= 50) { return; } if (loadMoreLoading) { return; } const shouldLoad = (activeTab === 'read' && hasMoreReadMembers && !readLoading) || (activeTab === 'unread' && hasMoreUnreadMembers && !unreadLoading); if (!shouldLoad) { return; } setLoadMoreLoading(true); loadMoreMembers(activeTab === 'read') .finally(() => { setLoadMoreLoading(false); }); }, [activeTab, readLoading, unreadLoading, hasMoreReadMembers, hasMoreUnreadMembers, loadMoreLoading, loadMoreMembers]); // Load data when modal opens useEffect(() => { if (open) { loadReadUsers(); loadUnreadUsers(); } }, [open, loadReadUsers, loadUnreadUsers]); // Refresh when counts change useEffect(() => { if (!open || !message?.msgID) { return; } if (readLoading || unreadLoading) { return; } if (activeTab === 'read') { loadReadUsers(); } else { loadUnreadUsers(); } }, [readCount, unreadCount]); return ( {})} title={t('MessageList.read_receipt_detail')} showClose footer={null} width="100%" > setActiveTab('read')} /> setActiveTab('unread')} /> {activeTab === 'read' && ( )} {activeTab === 'unread' && ( )} ); } export { ReadReceiptInfo, };