import type React from 'react'; import { useState, useRef, useMemo, useCallback } from 'react'; import { IconCallFilled, Dialog, useUIKit, } from '@tencentcloud/uikit-base-component-react'; import cs from 'classnames'; import { View, UserPicker, ConversationType, useChatContext, useLoginStore, } from 'tuikit-atomicx-react/chat'; import { startCall } from '../../../utils/call'; import classes from './AudioCallPicker.module.scss'; import type { GroupMember, IUserPickerRef } from 'tuikit-atomicx-react/chat'; interface AudioCallPickerProps { /** * Label text for the button */ label?: string; /** * Icon size in pixels */ iconSize?: number; /** * Whether the button is disabled */ disabled?: boolean; /** * Custom className for the button */ className?: string; /** * Custom style for the button */ style?: React.CSSProperties; /** * Custom icon slot */ children?: React.ReactNode; } interface GroupMemberOption { key: string; label: string; avatarUrl?: string; } const AUDIO_CALL_TYPE = 1; const MAX_GROUP_CALL_MEMBERS = 8; const MIN_GROUP_CALL_MEMBERS = 1; const AudioCallPicker = (props: AudioCallPickerProps) => { const { label = '', iconSize = 20, disabled = false, className, style, children, } = props; const { t } = useUIKit(); const { loginUserInfo } = useLoginStore(); const { activeConversation, memberList, hasMoreMembers, loadMembers, loadMoreMembers, } = useChatContext(); const [isGroupCallDialogVisible, setIsGroupCallDialogVisible] = useState(false); const groupMemberPickerRef = useRef(null); const selfUserId = useMemo(() => loginUserInfo?.userID, [loginUserInfo]); const isC2CConversation = useMemo(() => activeConversation?.type === ConversationType.C2C, [activeConversation]); const groupMemberOptions = useMemo(() => memberList?.map((member: GroupMember) => ({ key: member.userID, label: member.nameCard || member.nickname || member.userID, ...(member.avatarURL ? { avatarUrl: member.avatarURL } : {}), })) ?? [], [memberList]); const canStartCall = useMemo(() => { if (!activeConversation || disabled) { return false; } // TODO: add more call permission check logic return true; }, [activeConversation, disabled]); const initiatePrivateCall = useCallback((): void => { // Extract userID from C2C conversationID (format: "C2C{userID}") const peerUserId = activeConversation?.conversationID?.startsWith('C2C') ? activeConversation.conversationID.slice(3) : ''; if (!peerUserId) { console.warn('No peer user ID found for C2C call'); return; } try { startCall({ userIDList: [peerUserId], type: AUDIO_CALL_TYPE, }); } catch (error) { console.error('Failed to start private audio call:', error); } }, [activeConversation?.conversationID]); const loadMoreGroupMembers = useCallback((): void => { if (activeConversation?.type !== ConversationType.Group) { return; } if (memberList.length === 0) { loadMembers(); return; } if (hasMoreMembers) { loadMoreMembers(); } }, [activeConversation?.type, memberList.length, hasMoreMembers, loadMembers, loadMoreMembers]); const showGroupCallDialog = useCallback((): void => { loadMoreGroupMembers(); setIsGroupCallDialogVisible(true); }, [loadMoreGroupMembers]); const handleCloseGroupCallDialog = useCallback(() => { setIsGroupCallDialogVisible(false); }, []); const initiateGroupCall = useCallback((): void => { // Extract groupID from GROUP conversationID (format: "GROUP{groupID}") const currentGroupId = activeConversation?.conversationID?.startsWith('GROUP') ? activeConversation.conversationID.slice(5) : ''; if (!groupMemberPickerRef.current || !currentGroupId) { console.warn('Missing group information for group call'); return; } const selectedMembers = groupMemberPickerRef.current.getSelectedItems(); if (!Array.isArray(selectedMembers) || selectedMembers.length === 0) { console.warn('No members selected for group call'); return; } const selectedUserIds = selectedMembers.map(member => member.key); try { startCall({ userIDList: selectedUserIds, chatGroupID: currentGroupId, type: AUDIO_CALL_TYPE, }); handleCloseGroupCallDialog(); } catch (error) { console.error('Failed to start group audio call:', error); } }, [activeConversation?.conversationID, handleCloseGroupCallDialog]); const handleAudioCallClick = useCallback(() => { if (!canStartCall) { console.warn('Cannot start audio call'); return; } if (isC2CConversation) { initiatePrivateCall(); } else { showGroupCallDialog(); } }, [canStartCall, isC2CConversation, initiatePrivateCall, showGroupCallDialog]); const handleConfirmGroupCall = useCallback(() => { initiateGroupCall(); }, [initiateGroupCall]); return ( <> {/* TODO: Replace with TUIDialog component */} ); }; export { AudioCallPicker }; export type { AudioCallPickerProps };