diff --git a/images/message-structure-hierarchy-card.svg b/images/message-structure-hierarchy-card.svg new file mode 100644 index 000000000..49472b390 --- /dev/null +++ b/images/message-structure-hierarchy-card.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Category + Type + Type + Type + Action + status + + + + + + + Message + + + + message + + + + custom + + + + action + + + + call + + + + card + + + + + + + text + image + audio + video + file + + + groupMember + joined + left + kicked + banned + unbanned + added + scopeChanged + + + message + edited + deleted + + + audio + video + + + initiated + ongoing + rejected + cancel + busy + unanswered + ended + + diff --git a/sdk/react-native/ai-agents.mdx b/sdk/react-native/ai-agents.mdx index 05f8e5bde..32452827c 100644 --- a/sdk/react-native/ai-agents.mdx +++ b/sdk/react-native/ai-agents.mdx @@ -57,13 +57,16 @@ Events arrive via `onAIAssistantEventReceived` in this order: | 3 | Tool Call Arguments | Arguments being passed to the tool | | 4 | Tool Call End | Tool execution completed | | 5 | Tool Call Result | Tool's output is available | -| 6 | Text Message Start | Agent started composing a reply | -| 7 | Text Message Content | Streaming content chunks (multiple) | -| 8 | Text Message End | Agent reply is complete | -| 9 | Run Finished | Run finalized; persisted messages follow | +| 6 | Card Start | Agent started generating a card | +| 7 | Card | Full card payload is available | +| 8 | Card End | Card generation is complete | +| 9 | Text Message Start | Agent started composing a reply | +| 10 | Text Message Content | Streaming content chunks (multiple) | +| 11 | Text Message End | Agent reply is complete | +| 12 | Run Finished | Run finalized; persisted messages follow | -`Run Start` and `Run Finished` are always emitted. Tool Call events only appear when tools are invoked — there can be multiple tool call cycles in a single run. Text Message events are always emitted and carry the assistant's reply incrementally. +`Run Start` and `Run Finished` are always emitted. Tool Call events only appear when tools are invoked — there can be multiple tool call cycles in a single run. Card events (`Card Start` → `Card` → `Card End`) only appear when the agent produces a card, and may repeat for each card. Text Message events are always emitted and carry the assistant's reply incrementally. ### Event Object Properties @@ -88,6 +91,9 @@ Some events carry additional data: | Text Message Content | `getDelta()` | The streaming text chunk for progressive rendering | | Tool Call Arguments | `getToolCallId()`, `getDelta()` | Tool call ID and argument chunk | | Tool Call Result | `getToolCallId()`, `getContent()`, `getRole()` | Tool call ID, result content, and role | +| Card Start | `getCardId()`, `getExecutionText()`, `getStreamMessageId()` | Card ID, a human-readable status string, and the stream message ID | +| Card | `getCardId()`, `getCard()`, `getStreamMessageId()` | Card ID, the raw card payload, and the stream message ID | +| Card End | `getCardId()`, `getStreamMessageId()` | Card ID and the stream message ID | @@ -137,11 +143,67 @@ CometChat.removeAIAssistantListener("unique_listener_id"); - Tool Call Arguments: Arguments being passed to the tool. - Tool Call End: Tool execution completed. - Tool Call Result: Tool's output is available. +- Card Start: The agent started generating a card. Carries `cardId` and `executionText` (a human-readable status like "Building your product card..."). +- Card: The full card payload is available. Use `getCard()` to retrieve the raw card JSON and pass it to the renderer. +- Card End: The card generation flow is finalized. - Text Message Start: The agent started composing a reply. - Text Message Content: Streaming content chunks for progressive rendering. - Text Message End: The agent reply is complete. - Run Finished: The run is finalized; persisted messages will follow. +#### Card Streaming Events + +When the agent generates a card, the run emits a card cycle (`Card Start` → `Card` → `Card End`). All three are `AIAssistantBaseEvent` subclasses delivered through the same `onAIAssistantEventReceived` callback — no separate listener is required. + +| Class | Event type (`getType()`) | Getters | +|-------|--------------------------|---------| +| `AIAssistantCardStartedEvent` | `card_start` | `getCardId()`, `getExecutionText()`, `getStreamMessageId()` | +| `AIAssistantCardReceivedEvent` | `card` | `getCardId()`, `getCard()`, `getStreamMessageId()` | +| `AIAssistantCardEndedEvent` | `card_end` | `getCardId()`, `getStreamMessageId()` | + + + +```typescript +CometChat.addAIAssistantListener("unique_listener_id", { + onAIAssistantEventReceived: (event: CometChat.AIAssistantBaseEvent) => { + if (event instanceof CometChat.AIAssistantCardStartedEvent) { + console.log("Card generation started:", event.getCardId()); + console.log("Execution text:", event.getExecutionText()); + } else if (event instanceof CometChat.AIAssistantCardReceivedEvent) { + console.log("Card received:", event.getCardId()); + const cardPayload = event.getCard(); + // Pass cardPayload to your card renderer + } else if (event instanceof CometChat.AIAssistantCardEndedEvent) { + console.log("Card generation ended:", event.getCardId()); + } + }, +}); +``` + + + + +```javascript +CometChat.addAIAssistantListener("unique_listener_id", { + onAIAssistantEventReceived: (event) => { + if (event instanceof CometChat.AIAssistantCardStartedEvent) { + console.log("Card generation started:", event.getCardId()); + console.log("Execution text:", event.getExecutionText()); + } else if (event instanceof CometChat.AIAssistantCardReceivedEvent) { + console.log("Card received:", event.getCardId()); + const cardPayload = event.getCard(); + // Pass cardPayload to your card renderer + } else if (event instanceof CometChat.AIAssistantCardEndedEvent) { + console.log("Card generation ended:", event.getCardId()); + } + }, +}); +``` + + + + + ### Agentic Messages After the run completes, these messages arrive via `MessageListener`: @@ -220,6 +282,83 @@ The `getToolCalls()` method on `AIToolArgumentMessage` returns an array of `AITo Always remove listeners when they're no longer needed (e.g., on component unmount or page navigation). Failing to remove listeners can cause memory leaks and duplicate event handling. +### AIAssistantMessage Elements + +Starting from React Native SDK **4.0.26**, a persisted `AIAssistantMessage` carries its content as an ordered list of blocks via `getElements()`. This is the preferred render source — when present, walk the list in order and render each block. If the agent response contains only a card (no accompanying text), the text returned by `getAssistantMessageData().getText()` will be empty, so always prefer `getElements()`. + +`getElements()` returns an array of `AIAssistantElement` (or `null` for older messages without elements). Each element exposes: + +| Method | Return Type | Description | +|--------|-------------|-------------| +| `getType()` | `string` | The block type, e.g. `"text"` or `"card"`. Determines the shape of `getData()`. | +| `getData()` | `string \| object` | The block's raw body. `"text"` → `string`; `"card"` → `{ card, cardId }`; other types → raw JSON value. The SDK never interprets this — it returns the value as-is. | + + + +```typescript +function handleAIAssistantMessage(message: CometChat.AIAssistantMessage) { + const elements = message.getElements(); + + if (elements && elements.length > 0) { + // Preferred path: walk elements in order + elements.forEach((element: CometChat.AIAssistantElement) => { + switch (element.getType()) { + case "text": + console.log("Text block:", element.getData()); + break; + case "card": { + const { card, cardId } = element.getData() as { + card: object; + cardId: string; + }; + console.log("Card block:", cardId); + // Pass card to your card renderer + break; + } + default: + console.log("Unknown element type:", element.getType()); + } + }); + } else { + // Fallback for older messages without elements + console.log("Message text:", message.getAssistantMessageData().getText()); + } +} +``` + + + + +```javascript +function handleAIAssistantMessage(message) { + const elements = message.getElements(); + + if (elements && elements.length > 0) { + elements.forEach((element) => { + switch (element.getType()) { + case "text": + console.log("Text block:", element.getData()); + break; + case "card": { + const { card, cardId } = element.getData(); + console.log("Card block:", cardId); + // Pass card to your card renderer + break; + } + default: + console.log("Unknown element type:", element.getType()); + } + }); + } else { + console.log("Message text:", message.getAssistantMessageData().getText()); + } +} +``` + + + + + --- ## Next Steps diff --git a/sdk/react-native/campaigns.mdx b/sdk/react-native/campaigns.mdx index 2c340bbdc..683654d63 100644 --- a/sdk/react-native/campaigns.mdx +++ b/sdk/react-native/campaigns.mdx @@ -518,3 +518,53 @@ When a user taps a button or link inside a card, the action callback receives on | `initiateCall` | callType (audio/video), uid, guid | Start a call | | `apiCall` | url, method, headers, body | Make an HTTP request | | `customCallback` | callbackId, payload | App-specific logic | + +--- + +## Card Messages + +Besides the notification feed, the **same Card Schema JSON** can arrive as a chat message. A `CardMessage` is a message with `category: "card"` — created and sent via the Platform (REST) API or the Dashboard Bubble Builder. The SDK only **receives** card messages; it does not send them. + +Card messages are delivered through the `onCardMessageReceived` callback of the [`MessageListener`](/sdk/react-native/real-time-listeners#message-listener), not through the notification feed listener. The payload from `getCard()` is the same Card Schema JSON described above, so you render it with the same [`CometChatCardView`](#rendering-cards) and handle the same [card actions](#supported-card-actions). + +### CardMessage Fields + +| Method | Return Type | Description | +| --- | --- | --- | +| `getCard()` | object | The raw Card Schema JSON payload. Pass directly to the Cards renderer. | +| `getText()` | string | Preview text for push notifications and the conversation list. | +| `getFallbackText()` | string | Fallback text from inside the card (`card.fallbackText`), used for accessibility or when the renderer fails. | +| `getTags()` | `Array` | Tags associated with this message. | + + + +```typescript +CometChat.addMessageListener("unique_listener_id", { + onCardMessageReceived: (cardMessage: CometChat.CardMessage) => { + console.log("Card message received:", cardMessage.getId()); + const cardJson: string = JSON.stringify(cardMessage.getCard()); // same schema as feed cards + const fallback: string = cardMessage.getFallbackText(); + const previewText: string = cardMessage.getText(); + // Pass cardJson to CometChatCardView + }, +}); +``` + + +```javascript +CometChat.addMessageListener("unique_listener_id", { + onCardMessageReceived: (cardMessage) => { + console.log("Card message received:", cardMessage.getId()); + const cardJson = JSON.stringify(cardMessage.getCard()); // same schema as feed cards + const fallback = cardMessage.getFallbackText(); + const previewText = cardMessage.getText(); + // Pass cardJson to CometChatCardView + }, +}); +``` + + + + +Card messages are **receive-only**. They are created and sent exclusively via the Platform (REST) API and Dashboard Bubble Builder. The SDK exposes the raw payload via `getCard()` — the CometChat Cards library is responsible for drawing the card UI. + diff --git a/sdk/react-native/message-structure-and-hierarchy.mdx b/sdk/react-native/message-structure-and-hierarchy.mdx index 7b41e3db4..ab688fbe9 100644 --- a/sdk/react-native/message-structure-and-hierarchy.mdx +++ b/sdk/react-native/message-structure-and-hierarchy.mdx @@ -1,7 +1,7 @@ --- title: "Message Structure and Hierarchy" sidebarTitle: "Message Structure" -description: "Understand the message categories, types, and hierarchy in the CometChat React Native SDK including text, media, custom, action, call, and interactive messages." +description: "Understand the message categories, types, and hierarchy in the CometChat React Native SDK including text, media, custom, card, action, and call messages." --- @@ -9,17 +9,17 @@ description: "Understand the message categories, types, and hierarchy in the Com Message categories and types: - **message** → `text`, `image`, `video`, `audio`, `file` - **custom** → Developer-defined types (e.g., `location`, `poll`) +- **card** → `CardMessage` (receive-only rich cards) - **action** → `groupMember` (joined/left/kicked/banned), `message` (edited/deleted) - **call** → `audio`, `video` -- **interactive** → `form`, `card`, `customInteractive` -Every message in CometChat belongs to a category (`message`, `custom`, `action`, `call`, `interactive`) and has a specific type within that category. +Every message in CometChat belongs to a category (`message`, `custom`, `card`, `action`, `call`) and has a specific type within that category. ## Message Hierarchy - + ## Categories Overview @@ -28,9 +28,9 @@ Every message in CometChat belongs to a category (`message`, `custom`, `action`, | --- | --- | --- | | `message` | `text`, `image`, `video`, `audio`, `file` | Standard user messages | | `custom` | Developer-defined | Custom data (location, polls, etc.) | +| `card` | `CardMessage` | Receive-only rich, structured cards | | `action` | `groupMember`, `message` | System-generated events | | `call` | `audio`, `video` | Call-related messages | -| `interactive` | `form`, `card`, `customInteractive` | Interactive messages (forms, cards) | ## Checking Message Category and Type @@ -122,17 +122,20 @@ const customMessage = new CometChat.CustomMessage( See [Send Message → Custom Messages](/sdk/react-native/send-message#custom-message) for details. -## Interactive Messages (`interactive` Category) +## Card Messages (`card` Category) -An InteractiveMessage encapsulates an interactive unit within a chat message, such as an embedded form that users can fill out directly within the chat interface. +A message with category `card` is a [`CardMessage`](/sdk/react-native/campaigns#card-messages) — a rich, structured card rendered from Card Schema JSON. -| Type | Description | -| --- | --- | -| `form` | Interactive form messages | -| `card` | Interactive card messages | -| `customInteractive` | Custom interaction messages | +Card messages are **receive-only**: they cannot be sent from the SDK. They are created and sent exclusively via the **Platform (REST) API** or the **Dashboard Bubble Builder**, and delivered through the `onCardMessageReceived` callback of the `MessageListener`. + +| Method | Return Type | Description | +| --- | --- | --- | +| `getCard()` | object | The raw Card Schema JSON payload. Pass it to the [`CometChatCardView`](/sdk/react-native/campaigns#rendering-cards) renderer. | +| `getText()` | string | Preview text for notifications and the conversation list. | +| `getFallbackText()` | string | Fallback text used for accessibility or when the renderer fails. | +| `getTags()` | `Array` | Tags associated with the message. | -See [Interactive Messages](/sdk/react-native/interactive-messages) for details. +See [Receive Messages → Card Messages](/sdk/react-native/receive-messages#card-messages) and [Campaigns → Card Messages](/sdk/react-native/campaigns#card-messages) for details. ## Action Messages (`action` Category) @@ -178,8 +181,8 @@ See [Default Calling](/sdk/react-native/default-call) or [Direct Calling](/sdk/r Listen for incoming messages in real time - - Build forms, cards, and custom interactive messages + + Receive and render rich, structured card messages Advanced message filtering with RequestBuilder diff --git a/sdk/react-native/real-time-listeners.mdx b/sdk/react-native/real-time-listeners.mdx index dc8980fed..1a8a385c1 100644 --- a/sdk/react-native/real-time-listeners.mdx +++ b/sdk/react-native/real-time-listeners.mdx @@ -351,6 +351,7 @@ Receive events for incoming messages, typing indicators, read/delivery receipts, | **onTransientMessageReceived(receipt: [CometChat.TransientMessage](/sdk/reference/auxiliary#transientmessage))** | This event is triggered when a Transient Message is received. | | **onMessageReactionAdded(receipt: [CometChat.ReactionEvent](/sdk/reference/auxiliary#reactionevent))** | This event is triggered when a reaction is added to a message in a user/group conversation. | | **onMessageReactionRemoved(receipt: [CometChat.ReactionEvent](/sdk/reference/auxiliary#reactionevent))** | This event is triggered when a reaction is removed from a message in a user/group conversation. | +| **onCardMessageReceived(message: CometChat.CardMessage)** | This event is triggered when a card message (`category: "card"`) is received. See [Campaigns → Card Messages](/sdk/react-native/campaigns#card-messages). | To add the `MessageListener`: @@ -402,6 +403,9 @@ CometChat.addMessageListener( onMessageReactionRemoved: (reaction: CometChat.ReactionEvent) => { console.log("Message Reaction removed", reaction); }, + onCardMessageReceived: (cardMessage: CometChat.CardMessage) => { + console.log("Card message received", cardMessage); + }, }) ); ``` @@ -455,6 +459,9 @@ CometChat.addMessageListener( onMessageReactionRemoved: (reaction) => { console.log("Message Reaction removed", reaction); }, + onCardMessageReceived: (cardMessage) => { + console.log("Card message received", cardMessage); + }, }) ); ``` diff --git a/sdk/react-native/receive-messages.mdx b/sdk/react-native/receive-messages.mdx index 8e6499597..13328bc50 100644 --- a/sdk/react-native/receive-messages.mdx +++ b/sdk/react-native/receive-messages.mdx @@ -90,6 +90,44 @@ Always remove listeners when they're no longer needed (e.g., on component unmoun As a sender, you will not receive your own message in a real-time event. However, if a user is logged in on multiple devices, they will receive the event on the other devices. +## Card Messages + +A [`CardMessage`](/sdk/react-native/campaigns#card-messages) (`category: "card"`) is delivered through the `onCardMessageReceived` callback of the `MessageListener`. Card messages are **receive-only** — they are created and sent via the Platform (REST) API or Dashboard Bubble Builder, not from the SDK. + + + +```typescript +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onCardMessageReceived: (cardMessage: CometChat.CardMessage) => { + console.log("Card message received", cardMessage); + // getCard() returns the raw Card Schema JSON — pass it to your card renderer + const card = cardMessage.getCard(); + }, + }) +); +``` + + + +```javascript +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onCardMessageReceived: (cardMessage) => { + console.log("Card message received", cardMessage); + // getCard() returns the raw Card Schema JSON — pass it to your card renderer + const card = cardMessage.getCard(); + }, + }) +); +``` + + + +For the full `CardMessage` field reference, see [Campaigns → Card Messages](/sdk/react-native/campaigns#card-messages). + ## Missed Messages Fetch messages that were sent while the user was offline using `getLastDeliveredMessageId()` and `fetchNext()`. diff --git a/sdk/react-native/send-message.mdx b/sdk/react-native/send-message.mdx index d63cb2632..05f5518dd 100644 --- a/sdk/react-native/send-message.mdx +++ b/sdk/react-native/send-message.mdx @@ -874,6 +874,59 @@ customMessage.setConversationText("Shared a location"); --- +## Card Message + +A `CardMessage` is a structured, interactive message rendered as a card bubble. It belongs to the `card` category and carries a block of Card Schema JSON that the CometChat Cards library draws. + + +**Card Messages cannot be sent through the SDK.** The `CardMessage` class is **receive-only** — it has no public constructor and the SDK exposes no `sendCardMessage()` method. Card Messages are created server-side via the **Platform (REST) API** or the **Dashboard Bubble Builder**, and delivered to clients like any other message, through the `onCardMessageReceived` callback of the `MessageListener`. + +To create and send a Card Message, use the REST API. See the [Send Message REST API reference](https://www.cometchat.com/docs/rest-api/messages/send-message) for the message creation flow. + + +On the receiving end, the `CardMessage` object gives you access to the card payload and its related fields. + + + +```typescript +const card: object = cardMessage.getCard(); // raw card schema/payload +const text: string = cardMessage.getText(); // preview text for notifications and the conversation list +const fallbackText: string = cardMessage.getFallbackText(); // shown when the card cannot be rendered +const tags: Array = cardMessage.getTags(); // tags associated with the message +``` + + + +```javascript +const card = cardMessage.getCard(); // raw card schema/payload +const text = cardMessage.getText(); // preview text for notifications and the conversation list +const fallbackText = cardMessage.getFallbackText(); // shown when the card cannot be rendered +const tags = cardMessage.getTags(); // tags associated with the message +``` + + + +The `CardMessage` class provides the following methods: + +| Method | Returns | Description | +| --- | --- | --- | +| `getCard()` | `object` | The raw card schema/payload passed to the Cards renderer. | +| `getText()` | `string` | Preview text for notifications and the conversation list. | +| `getFallbackText()` | `string` | Text displayed when the card payload cannot be rendered. | +| `getTags()` | `Array` | Tags associated with the message. | + +`CardMessage` extends `BaseMessage`, so it also exposes the standard message fields (`getId()`, `getSender()`, `getReceiverId()`, `getSentAt()`, `getCategory()` = `card`, etc.). + +To handle incoming Card Messages on the client, implement [`onCardMessageReceived`](/sdk/react-native/receive-messages#card-messages) on your `MessageListener`. + +### Render a Card Message + +A `CardMessage` carries raw Card Schema JSON in `getCard()`. To draw it natively, pass it to the **CometChat Cards** renderer (`@cometchat/cards-react-native`) via the [`CometChatCardView`](/sdk/react-native/campaigns#rendering-cards) component. It is a pure renderer: you hand it the card JSON and an action callback, and you own all action behavior (opening URLs, navigating to chats, API calls, etc.). + +See [Campaigns → Rendering Cards](/sdk/react-native/campaigns#rendering-cards) for the dependency setup, the `CometChatCardView` example, and the [supported card actions](/sdk/react-native/campaigns#supported-card-actions). If the card JSON is empty or invalid, fall back to `getFallbackText()` (then `getText()`). + +--- + ## Next Steps diff --git a/ui-kit/react-native/events.mdx b/ui-kit/react-native/events.mdx index d261a1112..3e9a15eda 100644 --- a/ui-kit/react-native/events.mdx +++ b/ui-kit/react-native/events.mdx @@ -14,7 +14,7 @@ description: "Listen to UI Kit events for conversations, users, groups, messages | Group events | `ccGroupCreated`, `ccGroupDeleted`, `ccGroupLeft`, `ccGroupMemberScopeChanged`, `ccGroupMemberKicked`, `ccGroupMemberBanned`, `ccGroupMemberUnbanned`, `ccGroupMemberJoined`, `ccGroupMemberAdded`, `ccOwnershipChanged` | | Message events | `ccMessageSent`, `ccMessageEdited`, `ccMessageDeleted`, `ccMessageRead`, `ccLiveReaction`, plus SDK listener events | | Call events | `onIncomingCallAccepted`, `onIncomingCallRejected`, `onCallEnded`, `onCallInitiated`, `onOutgoingCallAccepted`, `onOutgoingCallRejected` | -| UI events | `ccActiveChatChanged` | +| UI events | `ccActiveChatChanged`, `ccCardActionClicked` | | Purpose | Decoupled communication between UI Kit components — subscribe to events to react to changes without direct component references | @@ -87,7 +87,7 @@ It consists of the following events: | onTransientMessageReceived | This event is emitted when the CometChat SDK listener emits a transient message. | | onInteractionGoalCompleted | This event is emitted when the CometChat SDK listener indicates that an interaction goal has been completed. | | onFormMessageReceived | This event is emitted when an interactive message of 'form' type is received from the CometChat SDK listener. | -| onCardMessageReceived | This event is emitted when an interactive message of 'card' type is received from the CometChat SDK listener. | +| onCardMessageReceived | This event is emitted when a card message (`category: "card"`) is received from the CometChat SDK listener. Used by the Card message bubble to render developer-defined cards. | | onSchedulerMessageReceived | This event is emitted when an interactive message of 'scheduler' type is received from the CometChat SDK listener. | | onCustomInteractiveMessageReceived | This event is emitted when an interactive message of 'customInteractive' type is received from the CometChat SDK listener. | @@ -115,6 +115,7 @@ It consists of the following events: | Name | Description | | ------------------- | ---------------------------------------------------------------------------- | | ccActiveChatChanged | This event is triggered when the user navigates to a particular chat window. | +| ccCardActionClicked | This event is triggered when the user clicks an action on a card message bubble. The event payload contains the `message` and the clicked `action`. | ---