Enable users to initiate private conversations with group members directly from group chat interfaces.

Overview

The Message Privately (from a Group) feature allows users to start private, one-on-one conversations with specific group members while remaining in the group context.
  • Allows users to start private conversations with specific group members directly from a group.
  • Enables confidential discussions, sharing sensitive information, or asking personal questions without disrupting the group conversation.
  • Your app will support initiating private messages from group contexts, allowing users to seamlessly switch between group discussions and private conversations.

Prerequisites

  • React v18.2.0+
  • CometChat React UI Kit v6.1.0+
  • CometChat Chat SDK JavaScript v4.0.13+
  • Project setup with initialized CometChat credentials (App ID, Auth Key, Region)
  • TypeScript support (recommended)
  • Group chat functionality already implemented
  • User management and conversation handling already implemented

Components

Component / ClassRole
CometChatGroupMembersDisplays group members with click handlers for private messaging
CometChatUsersAlternative user list component for private messaging
CometChatMessageComposerInput component for composing private messages
CometChatMessageListDisplays private conversation messages
CometChatMessageHeaderHeader showing private chat information

Integration Steps

1. Group Member Click Handler Setup

File: CometChatHome.tsx
const handleGroupMemberClick = (groupMember: CometChat.GroupMember) => {
    const user = groupMember as CometChat.User;
    startPrivateChatFromGroup(user, currentGroup);
}

const startPrivateChatFromGroup = (user: CometChat.User, group: CometChat.Group) => {
    setAppState({ type: "updatePreviousGroup", payload: group });
    
    CometChat.getConversation(user.getUid(), CometChatUIKitConstants.MessageReceiverType.user)
        .then((conversation) => {
            setSelectedItem(conversation);
            setAppState({ type: "updateSideComponent", payload: { visible: false, type: "" } });
            setShowPrivateChat(true);
        })
        .catch((error) => {
            console.error("Failed to start private chat:", error);
            showErrorMessage("Unable to start private conversation");
        });
}

2. Group Members Component Integration

File: CometChatHome.tsx
const GroupMembersWithPrivateMessaging = ({ group }: { group: CometChat.Group }) => {
    return (
        <CometChatGroupMembers
            group={group}
            onItemClick={handleGroupMemberClick}
            options={[
                {
                    id: "message_privately",
                    title: getLocalizedString("message_privately"),
                    iconURL: messageIcon,
                    onClick: (member: CometChat.GroupMember) => {
                        handleGroupMemberClick(member);
                    }
                }
            ]}
            selectionMode={SelectionMode.none}
        />
    );
}

3. Private Chat Interface from Group Context

File: CometChatHome.tsx
const PrivateChatFromGroupView = ({ user, previousGroup }: { 
    user: CometChat.User, 
    previousGroup: CometChat.Group 
}) => {
    const returnToGroup = () => {
        setShowPrivateChat(false);
        CometChat.getConversation(previousGroup.getGuid(), CometChatUIKitConstants.MessageReceiverType.group)
            .then((conversation) => {
                setSelectedItem(conversation);
            });
    };

    return (
        <div className="cometchat-private-chat-from-group">
            <CometChatMessageHeader
                user={user}
                onBack={returnToGroup}
                showBackButton={true}
                subtitle={`${getLocalizedString("private_message_from")} ${previousGroup.getName()}`}
            />
            <CometChatMessageList user={user} onThreadRepliesClick={() => {}} />
            <CometChatMessageComposer user={user} />
        </div>
    );
}

4. State Management for Group-to-Private Transition

File: appReducer.ts
interface AppState {
    previousGroup?: CometChat.Group;
    showPrivateChat?: boolean;
    privateChatUser?: CometChat.User;
}

case "updatePreviousGroup": {
    return { ...state, ["previousGroup"]: action.payload };
}
case "updateShowPrivateChat": {
    return { ...state, ["showPrivateChat"]: action.payload };
}
case "updatePrivateChatUser": {
    return { ...state, ["privateChatUser"]: action.payload };
}

Implementation Flow

  • Fetch Data / Group Members
File: CometChatHome.tsx
<CometChatGroupMembers
    group={currentGroup}
    onItemClick={handleGroupMemberClick}
    groupMemberRequestBuilder={new CometChat.GroupMembersRequestBuilder()
        .setLimit(50)
        .joinedOnly(true)}
/>
  • Load User Data / Conversation State
File: CometChatHome.tsx
const startPrivateChatFromGroup = async (user: CometChat.User, group: CometChat.Group) => {
    try {
        setAppState({ type: "updatePreviousGroup", payload: group });
        const conversation = await CometChat.getConversation(
            user.getUid(), 
            CometChatUIKitConstants.MessageReceiverType.user
        );
        
        setSelectedItem(conversation);
        setAppState({ type: "updatePrivateChatUser", payload: user });
        setAppState({ type: "updateShowPrivateChat", payload: true });
        
    } catch (error) {
        console.error("Failed to start private chat:", error);
        showErrorMessage("Unable to start private conversation");
    }
}
  • Send Private Message / Action Handler
File: CometChatHome.tsx
const sendPrivateMessageFromGroup = async (messageText: string, receiverId: string) => {
    const textMessage = new CometChat.TextMessage(
        receiverId,
        messageText,
        CometChatUIKitConstants.MessageReceiverType.user
    );
    
    try {
        const sentMessage = await CometChat.sendMessage(textMessage);
        console.log("Private message sent from group context:", sentMessage);
        showSuccessMessage("Private message sent");
    } catch (error) {
        console.error("Failed to send private message:", error);
        showErrorMessage("Failed to send private message");
    }
}
  • Live Updates / Context Switching
Files: CometChatHome.tsx, appReducer.ts
useEffect(() => {
    const messageListener = CometChat.addMessageListener(
        "privateMessageFromGroupListener",
        new CometChat.MessageListener({
            onTextMessageReceived: (textMessage: CometChat.TextMessage) => {
                if (textMessage.getReceiverType() === CometChatUIKitConstants.MessageReceiverType.user) {
                    updatePrivateConversation(textMessage);
                    if (!showPrivateChat) {
                        showNotification(`Private message from ${textMessage.getSender().getName()}`);
                    }
                }
            }
        })
    );
    
    return () => CometChat.removeMessageListener("privateMessageFromGroupListener");
}, [showPrivateChat]);

Customization Options

  • Styling: Override CSS classes for private chat from group interface
  • Member Options: Customize available actions for group members
  • Navigation: Customize return-to-group behavior and transitions
  • Message Types: Support various message types in private conversations
  • Context Display: Customize how group context is shown in private chat
  • Member Filtering: Control which group members can receive private messages

Filtering / Edge Cases

  • Handle permissions
  • Preserve group context
  • Manage blocked users
  • Scale for large groups

Error Handling & Context Management

const startPrivateChatFromGroup = async (user: CometChat.User, group: CometChat.Group) => {
    try {
        if (user.getBlockedByMe()) {
            showErrorMessage("Cannot send private message to blocked user");
            return;
        }
        if (!group.getMembers().some(member => member.getUid() === user.getUid())) {
            showErrorMessage("User is no longer a member of this group");
            return;
        }
        
        setAppState({ type: "updatePreviousGroup", payload: group });
        const conversation = await CometChat.getConversation(
            user.getUid(), 
            CometChatUIKitConstants.MessageReceiverType.user
        );
        
        setSelectedItem(conversation);
        setAppState({ type: "updateShowPrivateChat", payload: true });
        
    } catch (error) {
        if (error.code === "ERR_USER_NOT_FOUND") {
            showErrorMessage("User not found or unavailable");
        } else if (error.code === "ERR_CONVERSATION_CREATE_FAILED") {
            showErrorMessage("Unable to create private conversation");
        } else {
            showErrorMessage("An error occurred while starting private chat");
        }
    }
}

Summary / Feature Matrix

FeatureComponent / MethodFile Reference
Group member selectionCometChatGroupMembersCometChatHome.tsx
Private chat initiationstartPrivateChatFromGroup()CometChatHome.tsx
Private chat interfacePrivateChatFromGroupViewCometChatHome.tsx
Context preservationupdatePreviousGroupappReducer.ts
Private message sendingsendPrivateMessageFromGroup()CometChatHome.tsx
Return to groupreturnToGroup()CometChatHome.tsx
Member optionsoptions in CometChatGroupMembersCometChatHome.tsx
State managementupdateShowPrivateChatappReducer.ts

Next Steps & Further Reading