diff --git a/docs.json b/docs.json index 6fe2a0c0..57a343bf 100644 --- a/docs.json +++ b/docs.json @@ -2517,54 +2517,39 @@ ] }, { - "group": "Setup", + "group": "Integration Guides", "pages": [ - "sdk/javascript/setup-sdk" + "sdk/javascript/guides", + "sdk/javascript/guide-chat-only", + "sdk/javascript/guide-calls-only", + "sdk/javascript/guide-chat-calls", + "sdk/javascript/guide-moderation", + "sdk/javascript/guide-notifications" ] }, { - "group": "Authentication", + "group": "Setup & Authentication", "pages": [ + "sdk/javascript/setup-sdk", "sdk/javascript/authentication-overview", "sdk/javascript/login-listener" ] }, { - "group": "Messaging", + "group": "Core Features", "pages": [ "sdk/javascript/messaging-overview", "sdk/javascript/send-message", "sdk/javascript/receive-message", - "sdk/javascript/additional-message-filtering", - "sdk/javascript/retrieve-conversations", - "sdk/javascript/threaded-messages", - "sdk/javascript/edit-message", - "sdk/javascript/delete-message", - "sdk/javascript/flag-message", - "sdk/javascript/delete-conversation", - "sdk/javascript/typing-indicators", - "sdk/javascript/interactive-messages", - "sdk/javascript/transient-messages", "sdk/javascript/delivery-read-receipts", + "sdk/javascript/typing-indicators", + "sdk/javascript/user-presence", + "sdk/javascript/reactions", "sdk/javascript/mentions", - "sdk/javascript/reactions" - ] - }, - { - "group": "Calling", - "pages": [ - "sdk/javascript/calling-overview", - "sdk/javascript/calling-setup", - "sdk/javascript/default-call", - "sdk/javascript/direct-call", - "sdk/javascript/standalone-calling", - "sdk/javascript/recording", - "sdk/javascript/virtual-background", - "sdk/javascript/video-view-customisation", - "sdk/javascript/custom-css", - "sdk/javascript/presenter-mode", - "sdk/javascript/call-logs", - "sdk/javascript/session-timeout" + "sdk/javascript/threaded-messages", + "sdk/javascript/flag-message", + "sdk/javascript/retrieve-conversations", + "sdk/javascript/additional-message-filtering" ] }, { @@ -2576,12 +2561,6 @@ "sdk/javascript/block-users" ] }, - { - "group": "User Presence", - "pages": [ - "sdk/javascript/user-presence" - ] - }, { "group": "Groups", "pages": [ @@ -2599,16 +2578,43 @@ "sdk/javascript/transfer-group-ownership" ] }, - "sdk/javascript/ai-moderation", - "sdk/javascript/ai-agents", { - "group": "Resources", + "group": "Message Management", "pages": [ - "sdk/javascript/resources-overview", - "sdk/javascript/all-real-time-listeners", - "sdk/javascript/upgrading-from-v3" + "sdk/javascript/edit-message", + "sdk/javascript/delete-message", + "sdk/javascript/delete-conversation", + "sdk/javascript/interactive-messages", + "sdk/javascript/transient-messages" ] }, + { + "group": "Calling", + "pages": [ + "sdk/javascript/calling-overview", + "sdk/javascript/calling-setup", + "sdk/javascript/default-call", + "sdk/javascript/direct-call", + "sdk/javascript/standalone-calling", + "sdk/javascript/recording", + "sdk/javascript/virtual-background", + "sdk/javascript/video-view-customisation", + "sdk/javascript/custom-css", + "sdk/javascript/presenter-mode", + "sdk/javascript/call-logs", + "sdk/javascript/session-timeout" + ] + }, + { + "group": "AI Features", + "pages": [ + "sdk/javascript/ai-moderation", + "sdk/javascript/ai-agents", + "sdk/javascript/ai-chatbots-overview", + "sdk/javascript/ai-user-copilot-overview" + ] + }, + "sdk/javascript/extensions-overview", { "group": "Advanced", "pages": [ @@ -2617,6 +2623,14 @@ "sdk/javascript/managing-web-sockets-connections-manually" ] }, + { + "group": "Resources", + "pages": [ + "sdk/javascript/resources-overview", + "sdk/javascript/all-real-time-listeners", + "sdk/javascript/upgrading-from-v3" + ] + }, { "group": "UI Kits", "pages": [ @@ -2625,9 +2639,6 @@ "sdk/javascript/angular-overview" ] }, - "sdk/javascript/extensions-overview", - "sdk/javascript/ai-user-copilot-overview", - "sdk/javascript/ai-chatbots-overview", "sdk/javascript/webhooks-overview", "sdk/javascript/changelog" ] diff --git a/sdk/documentation-improvement-guidelines.md b/sdk/documentation-improvement-guidelines.md new file mode 100644 index 00000000..6342ca73 --- /dev/null +++ b/sdk/documentation-improvement-guidelines.md @@ -0,0 +1,1194 @@ +# CometChat SDK Documentation Improvement Guidelines + +These guidelines document the patterns, standards, and improvements applied to SDK documentation. Use this as a reference when improving documentation for any SDK technology (JavaScript, Android, iOS, Flutter, React Native) with AI assistance. + +> **Scope:** This document covers SDK documentation only. For UI Kit documentation guidelines, see `ui-kit/[technology]/documentation-improvement-guidelines.md`. + +--- + +## Table of Contents + +1. [Quick Reference Blocks](#1-quick-reference-blocks) +2. [Available Via Notes](#2-available-via-notes) +3. [Code Examples: Tab Conventions](#3-code-examples-tab-conventions) +4. [Tab Naming Standards](#4-tab-naming-standards) +5. [Mintlify Components](#5-mintlify-components) +6. [Next Steps Navigation](#6-next-steps-navigation) +7. [Page Structure Templates](#7-page-structure-templates) +8. [Feature Page Anatomy](#8-feature-page-anatomy) +9. [Navigation Organization](#9-navigation-organization) +10. [Integration Guides](#10-integration-guides) +11. [Glossary & Key Concepts](#11-glossary--key-concepts) +12. [Security & Init Warnings](#12-security--init-warnings) +13. [Cross-Linking & References](#13-cross-linking--references) +14. [What NOT to Do](#14-what-not-to-do) +15. [File Classification](#15-file-classification) +16. [File-by-File Checklist](#16-file-by-file-checklist) +17. [Prompt Template for AI Assistants](#17-prompt-template-for-ai-assistants) + +--- + +## 1. Quick Reference Blocks + +Every content page should have a Quick Reference block at the very top, immediately after the frontmatter. + +**Why:** AI agents parsing docs need a fast, copy-paste-ready summary. Developers scanning docs want the TL;DR. + +### Feature Pages (Messaging, Users, Groups, Calling, etc.) + +Show the most common API calls for that feature: + +```mdx +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Send text message to user +const msg = new CometChat.TextMessage("UID", "Hello!", CometChat.RECEIVER_TYPE.USER); +await CometChat.sendMessage(msg); + +// Send to group +const msg = new CometChat.TextMessage("GUID", "Hello!", CometChat.RECEIVER_TYPE.GROUP); +await CometChat.sendMessage(msg); + +// Media message +const msg = new CometChat.MediaMessage("UID", file, CometChat.MESSAGE_TYPE.IMAGE, CometChat.RECEIVER_TYPE.USER); +await CometChat.sendMediaMessage(msg); +``` + +``` + +### Overview/Hub Pages + +For overview pages that link to sub-pages, list the paths instead of code: + +```mdx + +**Quick Reference for AI Agents & Developers** + +Choose your path: +- **Chat Only** → [guide-chat-only](/sdk/javascript/guide-chat-only) - Text, media, groups +- **Calls Only** → [guide-calls-only](/sdk/javascript/guide-calls-only) - Standalone video/audio +- **Chat + Calls** → [guide-chat-calls](/sdk/javascript/guide-chat-calls) - Full communication + +``` + +### Setup/Getting Started Pages + +Show install + init + login in one block: + +```mdx + +**Quick Setup Reference** + +```bash +# Install +npm install @cometchat/chat-sdk-javascript + +# Initialize (run once at app start) +CometChat.init(APP_ID, appSettings) + +# Login (after init) +CometChat.login(UID, AUTH_KEY) # Dev only +CometChat.login(AUTH_TOKEN) # Production +``` + +**Required Credentials:** App ID, Region, Auth Key (dev) or Auth Token (prod) +**Get from:** [CometChat Dashboard](https://app.cometchat.com) → Your App → API & Auth Keys + +``` + +### Reference Pages (Listeners, Message Structure, Key Concepts) + +Show the most-used API calls or constants: + +```mdx + +**Quick Reference for AI Agents & Developers** + +```javascript +// Add message listener +CometChat.addMessageListener("LISTENER_ID", new CometChat.MessageListener({ + onTextMessageReceived: (message) => { }, + onMediaMessageReceived: (message) => { } +})); + +// Remove listener +CometChat.removeMessageListener("LISTENER_ID"); +``` + +``` + +### Rules (all page types) + +- Keep it to 5–15 lines of code maximum +- Show the most common use cases only +- Use real method names and constants — no pseudocode +- Include comments explaining what each snippet does +- Use `await` style for brevity (async/await is most readable) +- Skip error handling in the quick reference (full examples come later) + +### Skip Quick Reference for + +- Redirect-only pages (changelog links, sample app links) +- Pure navigation/index pages with no content +- Version-specific legacy folders (`2.0/`, `3.0/`) + +--- + +## 2. Available Via Notes + +Add an "Available via" note on **feature pages only** — pages that document a user-facing capability. + +### What qualifies as a feature page + +- Messaging: `send-message`, `receive-message`, `edit-message`, `delete-message`, `threaded-messages`, `reactions`, `mentions`, `interactive-messages`, `transient-messages` +- Users: `user-presence`, `block-users`, `retrieve-users`, `user-management` +- Groups: `groups-overview`, `create-group`, `join-group`, `leave-group`, `delete-group`, `update-group`, `retrieve-groups`, `retrieve-group-members`, `group-add-members`, `group-kick-ban-members`, `group-change-member-scope`, `transfer-group-ownership` +- Conversations: `retrieve-conversations`, `delete-conversation` +- Receipts & indicators: `delivery-read-receipts`, `typing-indicators` +- Calling: `default-call`/`default-calling`, `direct-call`/`direct-calling`, `call-logs`, `recording` +- AI: `ai-agents`, `ai-chatbots-overview`, `ai-moderation`, `ai-user-copilot-overview` +- Other: `flag-message`, `mentions` + +### What does NOT get "Available via" + +- Setup/installation pages (`overview`, `setup`, `setup-sdk`, `calling-setup`) +- Configuration pages (`managing-web-sockets-connections-manually`, `session-timeout`, `connection-status`) +- Styling/customization pages (`custom-css`, `video-view-customisation`, `virtual-background`, `presenter-mode`) +- Reference pages (`all-real-time-listeners`, `message-structure-and-hierarchy`, `key-concepts`, `login-listener`) +- Guide pages (`guide-chat-only`, `guide-calls-only`, `guide-chat-calls`, `guide-moderation`, `guide-notifications`, `guides`) +- Overview/hub pages that just link to sub-pages (`messaging-overview`, `users-overview`, `calling-overview`, `advanced-overview`, `resources-overview`, `extensions-overview`) +- Migration pages (`upgrading-from-v3`, `upgrading-from-v2`) +- Framework-specific pages (`react-overview`, `angular-overview`, `vue-overview`) +- Changelog, rate limits, webhooks overview +- Standalone calling (implementation approach, not a feature) + +### Pattern + +```mdx + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + +``` + +### Common combinations + +| Feature Type | Available Via | +| --- | --- | +| Messaging features (send, receive, edit, delete, threads, reactions) | SDK \| REST API \| UI Kits | +| Calling features (ringing, direct call) | SDK \| UI Kits | +| User/Group management | SDK \| REST API \| UI Kits | +| Conversations (retrieve, delete) | SDK \| REST API \| UI Kits | +| Receipts, typing indicators | SDK \| REST API \| UI Kits | +| AI features (moderation, agents, copilot) | SDK \| REST API \| UI Kits \| Dashboard | +| Call logs | SDK \| REST API \| Dashboard | +| Flag/report message | SDK \| REST API \| Dashboard | +| Recording | SDK \| Dashboard | +| Advanced filtering | SDK \| REST API | + +### Placement + +Right after the introductory sentence/paragraph, before the first `##` section heading. + +--- + +## 3. Code Examples: Tab Conventions + +Every code example should provide multiple language variants in tabs. The tabs differ by SDK technology. + +### JavaScript SDK + +```mdx + + +```javascript +CometChat.sendMessage(textMessage).then( + (message) => console.log("Sent:", message), + (error) => console.log("Error:", error) +); +``` + + +```typescript +CometChat.sendMessage(textMessage).then( + (message: CometChat.TextMessage) => console.log("Sent:", message), + (error: CometChat.CometChatException) => console.log("Error:", error) +); +``` + + +```javascript +try { + const message = await CometChat.sendMessage(textMessage); + console.log("Sent:", message); +} catch (error) { + console.log("Error:", error); +} +``` + + +``` + +### Android SDK + +```mdx + + +```kotlin +CometChat.sendMessage(textMessage, object : CometChat.CallbackListener() { + override fun onSuccess(message: TextMessage) { + Log.d(TAG, "Message sent: ${message.text}") + } + override fun onError(e: CometChatException) { + Log.e(TAG, "Error: ${e.message}") + } +}) +``` + + +```java +CometChat.sendMessage(textMessage, new CometChat.CallbackListener() { + @Override + public void onSuccess(TextMessage message) { + Log.d(TAG, "Message sent: " + message.getText()); + } + @Override + public void onError(CometChatException e) { + Log.e(TAG, "Error: " + e.getMessage()); + } +}); +``` + + +``` + +### iOS SDK + +```mdx + + +```swift +CometChat.sendTextMessage(message: textMessage, onSuccess: { message in + print("Message sent: \(message.text)") +}, onError: { error in + print("Error: \(error?.errorDescription)") +}) +``` + + +``` + +### Flutter SDK + +```mdx + + +```dart +CometChat.sendMessage(textMessage, onSuccess: (TextMessage message) { + debugPrint("Message sent: ${message.text}"); +}, onError: (CometChatException e) { + debugPrint("Error: ${e.message}"); +}); +``` + + +``` + +### React Native SDK + +```mdx + + +```javascript +CometChat.sendMessage(textMessage).then( + (message) => console.log("Sent:", message), + (error) => console.log("Error:", error) +); +``` + + +```typescript +CometChat.sendMessage(textMessage).then( + (message: CometChat.TextMessage) => console.log("Sent:", message), + (error: CometChat.CometChatException) => console.log("Error:", error) +); +``` + + +``` + +### Contextual tabs (all platforms) + +When showing alternative approaches (not language variants), use descriptive tab titles: + +```mdx + + + + + + + + +``` + +```mdx + +... +... +... +... + +``` + +### Rules + +- Every major code block should have language tabs — don't leave single-language examples +- TypeScript tabs should add proper type annotations, not just rename the file +- Async/Await tab (JavaScript SDK) should show try/catch pattern +- Simple one-liners (e.g., `CometChat.disconnect()`) can skip tabs — use a single block +- Keep code copy-paste ready: include variable declarations, imports where needed +- Use realistic placeholder values: `"user_uid"`, `"group_guid"`, `"YOUR_APP_ID"` +- For "To User" / "To Group" tabs, show the same operation for both receiver types + +--- + +## 4. Tab Naming Standards + +Use consistent tab titles across all pages. Never use arbitrary or inconsistent titles. + +### Correct tab titles by platform + +| Platform | Primary Tab | Secondary Tab | Tertiary Tab | +| --- | --- | --- | --- | +| JavaScript SDK | `JavaScript` | `TypeScript` | `Async/Await` | +| Android SDK | `Kotlin` | `Java` | — | +| iOS SDK | `Swift` | `Objective-C` (if supported) | — | +| Flutter SDK | `Dart` | — | — | +| React Native SDK | `JavaScript` | `TypeScript` | — | + +### Contextual tab titles (all platforms) + +| Tab Content | Title | +| --- | --- | +| Send to user | `To User` | +| Send to group | `To Group` | +| npm install | `npm` | +| yarn install | `yarn` | +| pnpm install | `pnpm` | +| CDN script tag | `CDN` | +| ES Module import | `ES Modules` | +| CommonJS require | `CommonJS` | +| Dashboard setup | `Dashboard (Testing)` | +| REST API setup | `REST API (Production)` | +| SDK setup | `SDK (On-the-fly)` | +| All users presence | `All Users` | +| By role presence | `By Role` | +| Friends only presence | `Friends Only` | +| File input upload | `From File Input` | +| URL upload | `From URLs` | +| Users only filter | `Users Only` | +| Groups only filter | `Groups Only` | +| Hide AI agents | `Hide AI Agents` | +| Only AI agents | `Only AI Agents` | + +### When to use language tabs vs contextual tabs + +- **Language tabs** (JavaScript/TypeScript/Async/Await): When showing the same code in different language styles +- **Contextual tabs** (To User/To Group, npm/yarn): When showing alternative approaches or configurations +- **Framework tabs** (React/Next.js/Vue/Angular/Nuxt): When showing framework-specific implementations + +--- + +## 5. Mintlify Components + +Use these Mintlify components consistently across all pages: + +### Steps — For sequential procedures + +```mdx + + + npm install @cometchat/chat-sdk-javascript + + + CometChat.init(appID, appSettings); + + +``` + +**Use for:** Setup flows, multi-step procedures, getting started guides, authentication flows. + +### Tabs — For code variants and alternative approaches + +**Use for:** Language variants (JS/TS/Async), package manager options (npm/yarn), platform-specific code, alternative approaches (To User/To Group), framework-specific implementations (React/Vue/Angular). + +### CardGroup + Card — For navigation and next steps + +```mdx + + + Send text, media, and custom messages + + +``` + +**Use for:** Next Steps sections, feature overviews, choosing between options, guide hub pages. + +### AccordionGroup + Accordion — For supplementary info + +```mdx + + + Explanation of the best practice. + + +``` + +**Use for:** Best practices, FAQs, troubleshooting tips, edge cases, common errors, framework-specific patterns. + +### Note, Warning, Info — For callouts + +```mdx +Informational callout — general tips and context. +Critical warning — data loss, security, breaking changes. +Highlighted info — quick references, availability, requirements. +``` + +**Use for:** + +- `` — Prerequisites, tips, general information, "Available via" notes, test user info +- `` — Destructive operations, security concerns (Auth Key in production), init-before-login, mutually exclusive options +- `` — Quick references, feature requirements, plan restrictions, feature flags + +### Frame — For images/screenshots + +```mdx + + + +``` + +**Use for:** Architecture diagrams, flow diagrams, dashboard screenshots. + +### Mermaid — For flow diagrams + +```mdx +```mermaid +sequenceDiagram + participant User + participant App + participant CometChat + User->>App: Login + App->>CometChat: CometChat.login() +``` +``` + +**Use for:** Authentication flows, message delivery flows, call signaling flows. Preserve existing mermaid diagrams — never remove them. + +--- + +## 6. Next Steps Navigation + +Every content page should end with a `## Next Steps` section using CardGroup. + +### Pattern + +```mdx +--- + +## Next Steps + + + + One-line description of what they'll learn + + + One-line description + + +``` + +### Rules + +- Always use `cols={2}` for consistency +- Include 2–4 cards (not more) +- Link to logically next topics (what would the developer need after this?) +- Use descriptive FontAwesome icon names +- Keep descriptions to one short sentence +- Use `## Next Steps` as the heading — not `## Next Steps & Further Reading` or other variants +- Do NOT include bullet-list links alongside the CardGroup — the cards are sufficient + +### Logical next step patterns + +| Current Page | Suggested Next Steps | +| --- | --- | +| Overview | Setup SDK, Key Concepts | +| Setup SDK | Authentication, Send First Message | +| Authentication | Send Message, User Management | +| Send Message | Receive Messages, Edit Message, Interactive Messages | +| Receive Message | Delivery Receipts, Typing Indicators | +| Edit Message | Delete Message, Send Message | +| Delete Message | Edit Message, Receive Message | +| Threaded Messages | Send Message, Receive Message | +| Reactions | Send Message, Receive Message | +| Mentions | Send Message, Receive Message | +| Users Overview | Retrieve Users, User Presence, Block Users | +| User Presence | Retrieve Users, Connection Status | +| Block Users | Retrieve Users, User Management | +| Groups Overview | Create Group, Retrieve Groups | +| Create Group | Join Group, Add Members | +| Join Group | Leave Group, Retrieve Members | +| Retrieve Conversations | Delete Conversation, Typing Indicators, Read Receipts | +| Calling Overview | Calling Setup, Default Call | +| Default Call (Ringing) | Direct Call, Call Logs, Recording | +| Direct Call | Default Call, Recording | +| Call Logs | Default Call, Recording | +| AI Agents | AI Chatbots, AI Moderation | +| Guides Hub | Individual guides | +| Key Concepts | Setup SDK, Send Message | + +--- + +## 7. Page Structure Templates + +### Feature Page Structure + +```text +1. Frontmatter (title, sidebarTitle, description) +2. Quick Reference block (Info component with code) +3. Introductory sentence (1-2 lines, what this feature does) +4. Available Via note (feature pages only) +5. Main content sections with code examples in tabs +6. Parameter tables after code examples +7. Common Use Cases / Examples +8. Real-Time Events / Listeners (if applicable) +9. Best Practices (AccordionGroup) — if applicable +10. Troubleshooting (AccordionGroup) — if applicable +11. Next Steps (CardGroup) +``` + +### Overview/Hub Page Structure + +```text +1. Frontmatter (title, sidebarTitle, description) +2. Quick Reference block (Info with links to sub-pages) +3. Introductory paragraph +4. Available Via note (if this is a feature overview like Groups Overview) +5. Key concepts / types / constants tables +6. Quick Start examples +7. Sub-feature CardGroups (management, membership, etc.) +8. Object properties table +9. Common Use Cases with code +10. Real-Time Events +11. Next Steps (CardGroup) +``` + +### Setup/Getting Started Page Structure + +```text +1. Frontmatter (title, sidebarTitle, description) +2. Quick Reference block (Info with install + init + login) +3. Intro paragraph +4. Prerequisites (Steps component) +5. Installation (Tabs for npm/yarn/pnpm/CDN) +6. Import (Tabs for ES Modules/CommonJS/CDN) +7. Initialize CometChat (Tabs for JS/TS/Async) +8. Complete Quick Start example +9. Configuration Options (tables + code) +10. Framework Integration (Tabs for React/Next.js/Vue/Angular/Nuxt) +11. Next Steps (CardGroup) +``` + +### Authentication Page Structure + +```text +1. Frontmatter (title, sidebarTitle, description) +2. Quick Reference block (Info with login methods) +3. Intro paragraph + note about user management +4. Authentication Flow (mermaid diagram) +5. Choose Your Method (CardGroup: Auth Key vs Auth Token) +6. Create a User (Tabs: Dashboard/REST API/SDK) +7. Login with Auth Key (Tabs: JS/TS/Async) + Warning +8. Login with Auth Token (Tabs: JS/TS/Async) + Steps +9. Check Login Status +10. Logout +11. Server-Side Token Generation (Tabs: Node.js/Python) +12. User Object properties table +13. Login Listeners +14. Best Practices (AccordionGroup) +15. Troubleshooting (AccordionGroup) +16. Next Steps (CardGroup) +``` + +### Guide Page Structure + +```text +1. Frontmatter (title, sidebarTitle, description) +2. Quick Reference block (Info with guide path links) +3. What you'll build (outcome) +4. Prerequisites (accounts, keys, dependencies) +5. Step-by-step implementation (Steps component) +6. Complete working code at the end +7. Integration Checklist +8. Next Steps (CardGroup — related guides + feature docs) +``` + +### Migration Page Structure + +```text +1. Frontmatter (title, description) +2. Quick Reference block (Info with summary of key changes) +3. Breaking changes list +4. Migration steps +5. API changes tables +6. Next Steps (CardGroup) +``` + +### Frontmatter template + +```yaml +--- +title: "Human-Readable Title" +sidebarTitle: "Short Sidebar Name" # Optional, only if title is too long for sidebar +description: "One sentence describing what this page covers" +--- +``` + +--- + +## 8. Feature Page Anatomy + +Every SDK feature page follows a consistent structure. When improving these pages, enhance each section without changing the order. + +### 1. Quick Reference + Intro + +- Quick Reference block with copy-paste ready code +- 1–2 sentence description of what the feature does +- "Available via" note (feature pages only) +- Type/method overview table (if multiple operations exist) + +### 2. Main Operations + +Each operation gets its own `##` section with: +- Code examples in language tabs (JS/TS/Async or platform equivalents) +- Contextual tabs where applicable (To User / To Group) +- Parameter table after the code +- Optional features (metadata, tags, etc.) as sub-sections + +### 3. Response/Object Properties + +- Table showing the returned object's properties +- Getter methods and their return types +- Example code accessing properties + +### 4. Filtering / Request Builders + +- `RequestBuilder` pattern with all available methods +- Filter options table +- Pagination examples (`fetchNext()` pattern) + +### 5. Real-Time Events / Listeners + +- Listener registration code +- All event callbacks documented +- Cleanup/removal code +- Link to full listeners reference + +### 6. Common Use Cases + +- Complete working examples for typical scenarios +- Framework-specific examples (React hooks, Vue composables, etc.) + +### 7. Best Practices & Troubleshooting + +- AccordionGroup with best practices +- AccordionGroup with common errors and solutions + +### 8. Next Steps + +- CardGroup with 2-4 related pages + +### Adding Missing Tabs + +When improving existing pages: + +- If a code block shows `.then()` pattern → add TypeScript and Async/Await tabs +- If a code block shows only Async/Await → add JavaScript (.then()) and TypeScript tabs +- If a code block shows only TypeScript → add JavaScript and Async/Await tabs +- For Android: if only Java → add Kotlin tab; if only Kotlin → add Java tab +- Do NOT convert existing single-tab examples to no-tab code blocks — always keep tabs + +### Parameter Table Format + +The existing SDK docs use this table format: + +```markdown +| Parameter | Type | Description | +| --- | --- | --- | +| `receiverID` | string | UID of user or GUID of group | +| `messageText` | string | The text content | +| `receiverType` | string | `CometChat.RECEIVER_TYPE.USER` or `GROUP` | +``` + +Preserve this format. When adding new parameters, follow the same pattern. + +### Object Properties Table Format + +```markdown +| Property | Method | Description | +| --- | --- | --- | +| ID | `getConversationId()` | Unique conversation identifier | +| Type | `getConversationType()` | `user` or `group` | +| Last Message | `getLastMessage()` | Most recent message object | +``` + +### Filter Options Table Format + +```markdown +| Method | Description | +| --- | --- | +| `setLimit(limit)` | Number of results (max 50) | +| `setSearchKeyword(keyword)` | Search by name | +| `setTags(tags)` | Filter by tags | +``` + +--- + +## 9. Navigation Organization + +The SDK sidebar should follow this structure (adapt per technology): + +```text +SDK v4 +├── Overview +├── Setup +├── Key Concepts +├── Authentication +│ └── Login, Logout, Auth Tokens +├── Messaging +│ ├── Overview +│ ├── Send Message +│ ├── Receive Message +│ ├── Edit / Delete Message +│ ├── Threaded Messages +│ ├── Reactions +│ ├── Mentions +│ ├── Message Structure & Hierarchy +│ ├── Interactive Messages +│ ├── Transient Messages +│ └── Additional Message Filtering +├── Users +│ ├── Overview +│ ├── Retrieve Users +│ ├── User Presence +│ ├── Block Users +│ └── User Management +├── Groups +│ ├── Overview +│ ├── Create / Update / Delete Group +│ ├── Join / Leave Group +│ ├── Retrieve Groups / Members +│ ├── Add Members / Kick-Ban +│ ├── Change Scope / Transfer Ownership +├── Conversations +│ ├── Retrieve Conversations +│ └── Delete Conversation +├── Receipts & Indicators +│ ├── Delivery & Read Receipts +│ ├── Typing Indicators +│ └── Flag Message +├── Calling +│ ├── Overview +│ ├── Setup +│ ├── Default Calling (Ringing) +│ ├── Direct Calling +│ ├── Standalone Calling +│ ├── Recording +│ ├── Call Logs +│ ├── Session Timeout +│ ├── Presenter Mode +│ ├── Virtual Background +│ ├── Video View Customisation +│ └── Custom CSS +├── AI Features +│ ├── AI Agents +│ ├── AI Chatbots +│ ├── AI Moderation +│ └── AI User Copilot +├── Advanced +│ ├── Connection Status +│ ├── WebSocket Management +│ ├── Login Listeners +│ ├── All Real-Time Listeners +│ └── Webhooks +├── Integration Guides +│ ├── Hub Page +│ ├── Chat Only +│ ├── Calls Only +│ ├── Chat + Calls +│ ├── Moderation +│ └── Notifications +├── Framework Guides (JavaScript SDK only) +│ ├── React +│ ├── Angular +│ └── Vue +├── Resources +│ ├── Rate Limits +│ ├── Extensions +│ └── Changelog +└── Migration Guide +``` + +--- + +## 10. Integration Guides + +The SDK should have step-by-step integration guides for common scenarios. These are separate from feature docs — they walk through a complete implementation from zero. + +### Guides to have + +- **Chat Only** — Text + media + groups (no calling) +- **Calls Only** — Standalone video/audio (no chat SDK) +- **Chat + Calls** — Full communication suite +- **Moderation** — Content filtering setup +- **Notifications** — Push alerts + +### Guide structure + +```text +1. What you'll build (outcome) +2. Prerequisites (accounts, keys, dependencies) +3. Step-by-step implementation (Steps component) +4. Complete working code at the end +5. Integration checklist +6. Next steps / what to add +``` + +### Rules + +- Every step must have copy-paste ready code +- Include expected output or what the developer should see +- Link back to detailed feature docs for customization +- Keep guides focused — one scenario per guide +- Include a "Quick Decision Guide" table on the hub page + +--- + +## 11. Glossary & Key Concepts + +SDK-specific terms that should be defined or linked when first used: + +| Term | Definition | +| --- | --- | +| UID | Unique User Identifier — alphanumeric string you assign to each user | +| GUID | Group Unique Identifier — alphanumeric string you assign to each group | +| Auth Key | Development-only credential for quick testing. Never use in production | +| Auth Token | Secure, per-user token generated via REST API. Use in production | +| REST API Key | Server-side credential for REST API calls. Never expose in client code | +| Receiver Type | Specifies if a message target is a `user` or `group` | +| Scope | Group member role: `admin`, `moderator`, or `participant` | +| Listener | Callback handler for real-time events (messages, presence, calls, groups) | +| Conversation | A chat thread between two users or within a group | +| Metadata | Custom JSON data attached to users, groups, or messages | +| Tags | String labels for categorizing users, groups, conversations, or messages | +| RequestBuilder | Builder pattern class for constructing filtered/paginated queries | +| AppSettings | Configuration object for initializing the SDK (App ID, Region, presence) | +| Transient Message | Ephemeral message not stored on server (typing indicators, live reactions) | +| Interactive Message | Message with actionable UI elements (forms, cards, buttons) | + +Include 10–20 terms. Define acronyms. Link to relevant pages where the concept is explained in detail. + +--- + +## 12. Security & Init Warnings + +### Init Warning + +```mdx + +`CometChat.init()` must be called before any other SDK method. Calling `login()`, `sendMessage()`, or registering listeners before `init()` will fail. + +``` + +### Auth Key Warning + +```mdx + +**Auth Key** is for development/testing only. In production, generate **Auth Tokens** on your server using the REST API and pass them to the client. Never expose Auth Keys in production client code. + +``` + +### SSR/Framework Note (JavaScript SDK only) + +```mdx + +**Server-Side Rendering (SSR):** CometChat SDK requires browser APIs (`window`, `WebSocket`). For Next.js, Nuxt, or other SSR frameworks, initialize the SDK only on the client side using dynamic imports or `useEffect`. See the [Framework Integration](/sdk/javascript/setup-sdk#framework-integration) section. + +``` + +### Listener Cleanup Warning + +```mdx + +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. + +``` + +### Destructive Operation Warning + +```mdx + +This operation is irreversible. Deleted [messages/groups/conversations] cannot be recovered. + +``` + +### Placement + +- Init + Auth Key warnings: on `overview` and `setup` pages +- SSR note: on `overview` and framework-specific pages (JavaScript SDK only) +- Listener cleanup: on any page that registers listeners +- Destructive warnings: on delete pages (`delete-message`, `delete-group`, `delete-conversation`) + +--- + +## 13. Cross-Linking & References + +Link related concepts together. When a page references a concept explained elsewhere, add an inline link. + +### Standard cross-links + +- On messaging pages: "For a deeper understanding of how messages are structured, see [Message Structure & Hierarchy](/sdk/[tech]/message-structure-and-hierarchy)." +- On any page using listeners: "Remember to [remove listeners](/sdk/[tech]/all-real-time-listeners) when they're no longer needed." +- On pages using RequestBuilders: "See [Additional Message Filtering](/sdk/[tech]/additional-message-filtering) for all builder options." +- On feature pages: Link to the REST API equivalent when available. +- On calling pages: Link to [Calling Setup](/sdk/[tech]/calling-setup) for SDK installation. +- On AI pages: Link to Dashboard for enabling features. + +### Related feature links + +- Send Message → Receive Message, Edit Message, Delete Message +- Receive Message → Delivery Receipts, Typing Indicators +- Create Group → Join Group, Add Members, Retrieve Groups +- Groups Overview → all group sub-pages +- Users Overview → all user sub-pages +- Default Call ↔ Direct Call ↔ Standalone Calling +- Retrieve Conversations → Delete Conversation, Typing Indicators + +--- + +## 14. What NOT to Do + +Lessons learned from the SDK documentation improvement process: + +1. **Do NOT remove existing prose or explanatory text.** Even if it seems verbose, developers rely on explanations. Only add — never subtract content. + +2. **Do NOT remove code examples.** Every code snippet exists for a reason. Add more variants (TypeScript, Async/Await, Kotlin) but never remove existing ones. + +3. **Do NOT remove mermaid diagrams or flow charts.** Visual aids help developers understand authentication flows, message delivery, and call signaling. + +4. **Do NOT remove framework-specific guides.** React, Angular, Vue, Next.js, Nuxt guides are all valuable even if they seem redundant. + +5. **Do NOT minimize or condense docs.** The goal is comprehensive, not concise. More detail is better than less. + +6. **Do NOT add "Available via" to non-feature pages.** Setup guides, configuration pages, reference pages, guide pages, and migration pages should not have availability notes. + +7. **Do NOT change section headings** that developers may have bookmarked or that other pages link to. + +8. **Do NOT restructure content within pages** unless explicitly asked. Navigation reorganization (sidebar order) is fine; content reorganization within pages is risky. + +9. **Do NOT remove AccordionGroup sections** (best practices, troubleshooting, common errors). These are high-value for developers debugging issues. + +10. **Do NOT remove server-side code examples** (Node.js, Python token generation). These are critical for production implementations. + +11. **Do NOT add UI Kit component code to SDK docs.** SDK docs show raw API calls. UI Kit component rendering belongs in UI Kit docs. + +12. **Do NOT remove "Complete Working Example" sections.** These end-to-end examples are the most valuable part of many pages. + +--- + +## 15. File Classification + +### Full Treatment (Quick Reference + Available Via + Next Steps) + +**Messaging feature pages:** +- `send-message`, `receive-message`, `edit-message`, `delete-message` +- `threaded-messages`, `reactions`, `mentions` +- `interactive-messages`, `transient-messages` +- `delivery-read-receipts`, `typing-indicators` +- `flag-message` + +**User feature pages:** +- `user-presence`, `block-users`, `retrieve-users`, `user-management` + +**Group feature pages:** +- `groups-overview`, `create-group`, `join-group`, `leave-group`, `delete-group`, `update-group` +- `retrieve-groups`, `retrieve-group-members` +- `group-add-members`, `group-kick-ban-members` / `group-kick-member` +- `group-change-member-scope`, `transfer-group-ownership` + +**Conversation feature pages:** +- `retrieve-conversations`, `delete-conversation` + +**Calling feature pages:** +- `default-call` / `default-calling`, `direct-call` / `direct-calling` +- `call-logs`, `recording` + +**AI feature pages:** +- `ai-agents`, `ai-chatbots-overview`, `ai-moderation`, `ai-user-copilot-overview` + +### Quick Reference + Next Steps Only (No "Available Via") + +**Setup/config pages:** +- `overview`, `setup` / `setup-sdk`, `calling-setup` +- `key-concepts`, `authentication-overview` + +**Reference pages:** +- `all-real-time-listeners` / `all-real-time-delegates-listeners` +- `message-structure-and-hierarchy` +- `additional-message-filtering` +- `connection-status`, `session-timeout` +- `managing-web-sockets-connections-manually` / `managing-web-socket-connections-manually` +- `login-listener` / `login-listeners` + +**Calling config/customization pages:** +- `standalone-calling`, `presenter-mode`, `virtual-background` +- `video-view-customisation`, `custom-css` + +**Overview/hub pages:** +- `messaging-overview`, `users-overview`, `groups-overview` (gets Available Via), `calling-overview` +- `advanced-overview`, `resources-overview`, `extensions-overview` +- `ai-user-copilot-overview` (gets Available Via — it's a feature) + +**Guide pages:** +- `guides`, `guide-chat-only`, `guide-calls-only`, `guide-chat-calls` +- `guide-moderation`, `guide-notifications` + +**Framework pages (JavaScript SDK only):** +- `react-overview`, `angular-overview`, `vue-overview` + +**Migration pages:** +- `upgrading-from-v3`, `upgrading-from-v2`, `upgrading-from-v3-to-v4` + +**Platform-specific pages:** +- `android-overview`, `ios-overview` +- `publishing-app-on-playstore`, `publishing-app-on-appstore` +- `connection-behaviour`, `web-socket-connection-behaviour` +- Platform-specific push notification pages (iOS) + +**Resource pages:** +- `rate-limits`, `webhooks-overview` + +### Skip Entirely + +- `changelog` (auto-generated or link page) +- Legacy version folders (`2.0/`, `3.0/`) +- `research.md` (internal notes) + +--- + +## 16. File-by-File Checklist + +Use this checklist when improving each SDK documentation file: + +```text +[ ] Frontmatter has title, description (and sidebarTitle if needed) +[ ] Quick Reference block present at top (Info component with code) +[ ] "Available via" note present (ONLY if this is a feature page) +[ ] Introductory sentence explains what the feature does +[ ] All code examples have language tabs (JS/TS/Async or platform equivalents) +[ ] Tab titles use standard names (JavaScript/TypeScript/Async/Await, Kotlin/Java, Swift, Dart) +[ ] Parameter tables follow code examples where applicable +[ ] Object properties tables present for returned objects +[ ] Filter options table present for RequestBuilder pages +[ ] Pagination example shown for list/fetch operations +[ ] Real-time listeners documented with register + cleanup code +[ ] Best Practices section (AccordionGroup) where applicable +[ ] Troubleshooting section (AccordionGroup) where applicable +[ ] Next Steps section at bottom with CardGroup (2-4 relevant links) +[ ] Next Steps uses ## Next Steps heading (not variants) +[ ] No bullet-list links alongside CardGroup in Next Steps +[ ] Cross-links to related pages where concepts are referenced +[ ] Security warnings where applicable (init, auth keys, destructive operations) +[ ] Listener cleanup warnings on pages that register listeners +[ ] No content, code examples, diagrams, or explanatory text removed +[ ] Code is copy-paste ready with realistic placeholders +[ ] Mermaid diagrams preserved (never removed) +[ ] Framework-specific examples preserved +[ ] Server-side code examples preserved +[ ] Page reads naturally from top to bottom — journey feels logical +``` + +--- + +## 17. Prompt Template for AI Assistants + +When asking an AI assistant to improve SDK docs for any technology, use this prompt: + +```text +Improve the [TECHNOLOGY] SDK documentation files following these guidelines: + +1. Add a Quick Reference block at the top of every content page using component + with copy-paste ready code snippets (5-15 lines, most common use cases) + +2. Add "Available via: SDK | REST API | UI Kits" notes on FEATURE PAGES ONLY + (not setup, config, reference, guide, or migration pages) + +3. Ensure all code examples have language tabs: + - For JavaScript: JavaScript | TypeScript | Async/Await + - For Android: Kotlin | Java + - For iOS: Swift + - For Flutter: Dart + - For React Native: JavaScript | TypeScript + +4. Use standard tab titles: "JavaScript", "TypeScript", "Async/Await", "Kotlin", "Java", etc. + Use contextual titles for approach tabs: "To User", "To Group", "npm", "yarn" + +5. Add a description field to frontmatter on every page + +6. Add Next Steps navigation at the bottom of every page using + with 2-4 cards linking to logically next topics. Use ## Next Steps heading only. + +7. Use Mintlify components: , , , , + , , , , , + +8. CRITICAL: Do NOT remove any existing content, code examples, mermaid diagrams, + framework guides, server-side examples, or explanatory text. Only ADD improvements. + +9. Add cross-links between related feature pages + +10. Add security warnings on init/login pages + (Auth Key for dev only, Auth Token for production) + +11. Add listener cleanup warnings on pages that register listeners + +12. Add Best Practices and Troubleshooting AccordionGroups where applicable + +13. Preserve existing mermaid diagrams and flow charts + +Reference: sdk/documentation-improvement-guidelines.md +``` + +--- + +## Summary of Improvements Applied (JavaScript SDK) + +All ~75 content files in `sdk/javascript/` have been improved: + +1. **Quick Reference blocks** added to all content files +2. **Multi-language tabs** (JavaScript, TypeScript, Async/Await) added to all code examples +3. **Next Steps navigation** (CardGroup) added to bottom of every page +4. **"Available via" notes** added to all feature pages +5. **Integration Guides** created: 6 new step-by-step guides (chat-only, calls-only, chat+calls, moderation, notifications, hub page) +6. **Glossary** added to key-concepts.mdx with 15 defined terms +7. **Framework Integration** section with React, Next.js (App/Pages Router), Vue, Nuxt, Angular +8. **Complete Working Examples** added to overview and setup pages +9. **Common Errors & Solutions** AccordionGroup added to overview +10. **Best Practices & Troubleshooting** AccordionGroups added to authentication and feature pages +11. **Init + Auth Key warnings** added to overview and setup pages +12. **SSR/framework note** added to overview +13. **Message structure cross-links** added throughout messaging pages +14. **Mintlify components** used throughout: Steps, Tabs, CardGroup, Card, AccordionGroup, Accordion, Note, Warning, Info, Frame +15. **Existing content preserved** — no diagrams, code examples, or explanatory text removed \ No newline at end of file diff --git a/sdk/javascript/additional-message-filtering.mdx b/sdk/javascript/additional-message-filtering.mdx index 6648ba35..6c392a85 100644 --- a/sdk/javascript/additional-message-filtering.mdx +++ b/sdk/javascript/additional-message-filtering.mdx @@ -2,28 +2,56 @@ title: "Additional Message Filtering" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Build message request with filters +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID("user123") // or .setGUID("group123") + .setLimit(50) // Max 100 + .setMessageId(messageId) // Messages after/before this ID + .setTimestamp(timestamp) // Messages after/before this time + .setUnread(true) // Only unread messages + .setCategories(["message"]) // Filter by category + .setTypes(["text", "image"]) // Filter by type + .hideReplies(true) // Exclude threaded messages + .hideDeletedMessages(true) // Exclude deleted messages + .setTags(["starred"]) // Filter by tags + .build(); -The `MessagesRequest` class as you must be familiar with helps you to fetch messages based on the various parameters provided to it. This document will help you understand better the various options that are available using the `MessagesRequest` class. - -The `MessagesRequest` class is designed using the `Builder design pattern`. In order to obtain an object of the `MessagesRequest` class, you will have to make use of the `MessagesRequestBuilder` class in the `MessagesRequest` class. - -The `MessagesRequestBuilder` class allows you to set various parameters to the `MessagesRequest` class based on which the messages are fetched. - -Steps to generate an object of the MessagesRequest class: - -1. Create an object of the `MessagesRequestBuilder` class. -2. Set all the parameters you wish to set. -3. Call the `build()` method of the `MessagesRequestBuilder` class to get an object of the `MessagesRequest` class. - -Once you have an object of the `MessagesRequest` class, you can call either the `fetchNext()` method or the `fetchPrevious()` method using the object. +// Fetch messages +const messages = await messagesRequest.fetchPrevious(); // or fetchNext() +``` + -1. fetchNext() - Calling this method will return the messages after the specified parameters. -2. fetchPrevious() - Calling this method will give you messages before the specified parameters. +Use `MessagesRequestBuilder` to filter and fetch messages with fine-grained control. This page covers all available filtering options. -Since messages are obtained in a paginated manner, a `maximum of 100` messages can be pulled in a single iteration. Calling the `fetchPrevious()`/`fetchNext()` method on the same `MessagesRequest` object will get you the next set of messages. + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) + -Now that you are clear how to use the `MessagesRequest` class, below are the various options available: +The `MessagesRequestBuilder` uses the Builder pattern. Create a builder, set your filters, call `build()`, then use `fetchPrevious()` or `fetchNext()` to retrieve messages. + + + + `new CometChat.MessagesRequestBuilder()` + + + Chain methods like `.setUID()`, `.setLimit()`, `.setCategories()`, etc. + + + Call `.build()` to get a `MessagesRequest` object + + + Call `fetchPrevious()` (older messages) or `fetchNext()` (newer messages) + + + + +Messages are paginated — max **100** per request. Call `fetchPrevious()`/`fetchNext()` again on the same object to get the next page. + ## Number of messages fetched @@ -1474,3 +1502,15 @@ let GUID: string = "GUID", + + +## Next Steps + + + + Fetch and display conversation lists + + + Send text, media, and custom messages + + diff --git a/sdk/javascript/advanced-overview.mdx b/sdk/javascript/advanced-overview.mdx index 7a8e791f..0f6198ac 100644 --- a/sdk/javascript/advanced-overview.mdx +++ b/sdk/javascript/advanced-overview.mdx @@ -1,8 +1,176 @@ --- title: "Advanced" sidebarTitle: "Overview" +description: "Master advanced SDK features for production-ready applications" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Connection status listener +CometChat.addConnectionListener("CONN_LISTENER", new CometChat.ConnectionListener({ + onConnected: () => console.log("Connected"), + onDisconnected: () => console.log("Disconnected"), + onConnecting: () => console.log("Connecting...") +})); -This section helps you to know about the Connection Listeners. +// Manual WebSocket control +CometChat.connect(); // Connect +CometChat.disconnect(); // Disconnect + +// Login listener +CometChat.addLoginListener("AUTH_LISTENER", new CometChat.LoginListener({ + loginSuccess: (user) => console.log("Logged in"), + logoutSuccess: () => console.log("Logged out") +})); +``` + + +Build robust, production-ready chat applications with advanced SDK capabilities including connection management, real-time listeners, and performance optimization. + +## Advanced Capabilities + + + + Monitor WebSocket connection state and handle network changes gracefully + + + Take full control of WebSocket connections for advanced use cases + + + Comprehensive guide to all event listeners available in the SDK + + + Handle authentication state changes and session management + + + +## When to Use Advanced Features + +| Feature | Use Case | Benefit | +|---------|----------|---------| +| Connection Status | Mobile apps, unstable networks | Graceful offline handling | +| Manual WebSocket | Background apps, battery optimization | Resource efficiency | +| Real-Time Listeners | Custom UI updates, analytics | Full event control | +| Login Listener | Multi-device sync, security | Session management | + +## Connection Management + +Understanding connection states is crucial for production applications: + +```mermaid +stateDiagram-v2 + [*] --> Disconnected + Disconnected --> Connecting: connect() + Connecting --> Connected: Success + Connecting --> Disconnected: Failure + Connected --> Disconnected: Network loss + Connected --> FeatureThrottled: Rate limited + FeatureThrottled --> Connected: Throttle lifted +``` + + + +```javascript +// Monitor connection status +CometChat.addConnectionListener( + "CONNECTION_LISTENER", + new CometChat.ConnectionListener({ + onConnected: () => { + console.log("Connected to CometChat"); + // Enable chat features + }, + onDisconnected: () => { + console.log("Disconnected from CometChat"); + // Show offline indicator + }, + onConnecting: () => { + console.log("Connecting..."); + // Show loading state + }, + onFeatureThrottled: () => { + console.log("Feature throttled"); + // Handle rate limiting + } + }) +); +``` + + +```typescript +// Monitor connection status +CometChat.addConnectionListener( + "CONNECTION_LISTENER", + new CometChat.ConnectionListener({ + onConnected: (): void => { + console.log("Connected to CometChat"); + // Enable chat features + }, + onDisconnected: (): void => { + console.log("Disconnected from CometChat"); + // Show offline indicator + }, + onConnecting: (): void => { + console.log("Connecting..."); + // Show loading state + }, + onFeatureThrottled: (): void => { + console.log("Feature throttled"); + // Handle rate limiting + } + }) +); +``` + + + +## Best Practices + + + + Implement reconnection logic and offline indicators to maintain good UX during network issues. + + ```javascript + onDisconnected: () => { + showOfflineIndicator(); + queueOutgoingMessages(); + } + ``` + + + + Remove listeners when components unmount to prevent memory leaks. + + ```javascript + // On component unmount + CometChat.removeConnectionListener("CONNECTION_LISTENER"); + ``` + + + + Disconnect WebSocket when app goes to background to save battery and resources. + + ```javascript + document.addEventListener("visibilitychange", () => { + if (document.hidden) { + CometChat.disconnect(); + } else { + CometChat.connect(); + } + }); + ``` + + + +## Next Steps + + + + Deep dive into connection state management + + + Learn manual connection control + + diff --git a/sdk/javascript/ai-agents.mdx b/sdk/javascript/ai-agents.mdx index f4b88d96..688edc71 100644 --- a/sdk/javascript/ai-agents.mdx +++ b/sdk/javascript/ai-agents.mdx @@ -2,10 +2,36 @@ title: "AI Agents" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Listen for real-time AI events +CometChat.addAIAssistantListener("AI_LISTENER", { + onAIAssistantEventReceived: (event) => console.log("AI event:", event) +}); + +// Listen for AI messages (after run completes) +CometChat.addMessageListener("MSG_LISTENER", { + onAIAssistantMessageReceived: (msg) => console.log("AI reply:", msg), + onAIToolResultReceived: (msg) => console.log("Tool result:", msg), + onAIToolArgumentsReceived: (msg) => console.log("Tool args:", msg) +}); + +// Remove listeners +CometChat.removeAIAssistantListener("AI_LISTENER"); +``` + + # AI Agents Overview AI Agents enable intelligent, automated interactions within your application. They can process user messages, trigger tools, and respond with contextually relevant information. For a broader introduction, see the [AI Agents section](/ai-agents). + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) | [Widget Builder](/ai-agents/chat-widget) + + > **Note:** > Currently, an Agent only responds to **Text Messages**. @@ -69,6 +95,88 @@ Notes: +#### Handling Specific Event Types + +Use the event's `type` property to handle each stage of the run: + + + + ```javascript + CometChat.addAIAssistantListener("AI_EVENTS", { + onAIAssistantEventReceived: (event) => { + switch (event.getType()) { + case "run_start": + console.log("Agent run started"); + showLoadingIndicator(); + break; + + case "tool_call_start": + console.log("Tool invoked:", event.getData()); + break; + + case "tool_call_arguments": + console.log("Tool arguments:", event.getData()); + break; + + case "tool_call_end": + console.log("Tool execution complete"); + break; + + case "tool_call_result": + console.log("Tool result:", event.getData()); + break; + + case "text_message_start": + console.log("Agent started composing reply"); + break; + + case "text_message_content": + // Streaming content — append to UI for progressive rendering + appendToAgentReply(event.getData()); + break; + + case "text_message_end": + console.log("Agent reply complete"); + break; + + case "run_finished": + console.log("Run finalized"); + hideLoadingIndicator(); + break; + } + } + }); + ``` + + + ```typescript + CometChat.addAIAssistantListener("AI_EVENTS", { + onAIAssistantEventReceived: (event: CometChat.AIAssistantBaseEvent) => { + switch (event.getType()) { + case "run_start": + console.log("Agent run started"); + showLoadingIndicator(); + break; + + case "text_message_content": + appendToAgentReply(event.getData()); + break; + + case "tool_call_result": + console.log("Tool result:", event.getData()); + break; + + case "run_finished": + console.log("Run finalized"); + hideLoadingIndicator(); + break; + } + } + }); + ``` + + + #### Event descriptions - Run Start: A new run has begun for the user’s message. - Tool Call Start: The agent decided to invoke a tool. @@ -131,4 +239,112 @@ These events are received via the **`MessageListener`** after the run completes. CometChat.removeMessageListener(listnerId); ``` - \ No newline at end of file + + +## Complete Example + +Here's a full implementation that handles both real-time streaming events and persisted agentic messages: + +```javascript +class AIAgentHandler { + constructor() { + this.currentReply = ""; + this.isRunning = false; + this.setupListeners(); + } + + setupListeners() { + // Real-time streaming events + CometChat.addAIAssistantListener("AI_STREAM", { + onAIAssistantEventReceived: (event) => { + switch (event.getType()) { + case "run_start": + this.isRunning = true; + this.currentReply = ""; + this.onRunStart(); + break; + + case "text_message_content": + this.currentReply += event.getData(); + this.onStreamChunk(this.currentReply); + break; + + case "tool_call_start": + this.onToolCallStart(event.getData()); + break; + + case "tool_call_result": + this.onToolCallResult(event.getData()); + break; + + case "run_finished": + this.isRunning = false; + this.onRunFinished(this.currentReply); + break; + } + } + }); + + // Persisted messages (for history and offline retrieval) + CometChat.addMessageListener("AI_MESSAGES", { + onAIAssistantMessageReceived: (message) => { + // Full agent reply — use for message history display + console.log("Agent reply persisted:", message.getText()); + }, + onAIToolResultReceived: (message) => { + console.log("Tool result persisted:", message); + }, + onAIToolArgumentsReceived: (message) => { + console.log("Tool arguments persisted:", message); + } + }); + } + + // Override these in your UI layer + onRunStart() { /* Show typing indicator */ } + onStreamChunk(partialText) { /* Update UI with streaming text */ } + onToolCallStart(data) { /* Show "Agent is using a tool..." */ } + onToolCallResult(data) { /* Display tool output */ } + onRunFinished(fullReply) { /* Finalize UI, hide typing indicator */ } + + cleanup() { + CometChat.removeAIAssistantListener("AI_STREAM"); + CometChat.removeMessageListener("AI_MESSAGES"); + } +} + +// Usage +const handler = new AIAgentHandler(); + +// Send a message to the agent (agents respond to text messages) +const message = new CometChat.TextMessage( + "AGENT_UID", + "What's the weather in San Francisco?", + CometChat.RECEIVER_TYPE.USER +); +await CometChat.sendMessage(message); +// The agent processes the message and events stream in via the listeners above +``` + + +Always remove both `AIAssistantListener` and `MessageListener` when your component unmounts or the user navigates away to prevent memory leaks. + + +--- + +## Next Steps + + + + Automatically moderate messages with AI + + + Create intelligent chatbot experiences + + + Handle all real-time message events + + + Create and configure agents in the dashboard + + \ No newline at end of file diff --git a/sdk/javascript/ai-moderation.mdx b/sdk/javascript/ai-moderation.mdx index 768de540..6f49a73d 100644 --- a/sdk/javascript/ai-moderation.mdx +++ b/sdk/javascript/ai-moderation.mdx @@ -2,11 +2,34 @@ title: "AI Moderation" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Send message and check moderation status +const message = await CometChat.sendMessage(textMessage); +if (message.getModerationStatus() === CometChat.ModerationStatus.PENDING) { + console.log("Message under review"); +} + +// Listen for moderation results +CometChat.addMessageListener("MOD_LISTENER", new CometChat.MessageListener({ + onMessageModerated: (msg) => { + const status = msg.getModerationStatus(); + // CometChat.ModerationStatus.APPROVED or DISAPPROVED + } +})); +``` + + ## Overview AI Moderation in the CometChat SDK helps ensure that your chat application remains safe and compliant by automatically reviewing messages for inappropriate content. This feature leverages AI to moderate messages in real-time, reducing manual intervention and improving user experience. +**Available via:** SDK | Dashboard + For a broader understanding of moderation features, configuring rules, and managing flagged messages, see the [Moderation Overview](/moderation/overview). @@ -121,6 +144,31 @@ When you send a text, image, or video message, check the initial moderation stat ); ``` + + ```javascript + const sendModeratedMessage = async () => { + try { + const textMessage = new CometChat.TextMessage( + receiverUID, + "Hello, how are you?", + CometChat.RECEIVER_TYPE.USER + ); + + const message = await CometChat.sendMessage(textMessage); + + // Check moderation status + const status = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.PENDING) { + console.log("Message is under moderation review"); + // Show pending indicator in UI + } + } catch (error) { + console.log("Message sending failed:", error); + } + }; + ``` + ### Step 2: Listen for Moderation Results diff --git a/sdk/javascript/all-real-time-listeners.mdx b/sdk/javascript/all-real-time-listeners.mdx index a70adfb5..ee920fd3 100644 --- a/sdk/javascript/all-real-time-listeners.mdx +++ b/sdk/javascript/all-real-time-listeners.mdx @@ -1,233 +1,225 @@ --- -title: "All Real Time Listeners" +title: "All Real-Time Listeners" +description: "Complete reference for all event listeners in the CometChat JavaScript SDK" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Message Listener +CometChat.addMessageListener("MSG_LISTENER", new CometChat.MessageListener({ + onTextMessageReceived: (msg) => console.log(msg.getText()), + onTypingStarted: (indicator) => console.log("typing..."), + onMessagesRead: (receipt) => console.log("read") +})); + +// User Listener (presence) +CometChat.addUserListener("USER_LISTENER", new CometChat.UserListener({ + onUserOnline: (user) => console.log(user.getUid(), "online"), + onUserOffline: (user) => console.log(user.getUid(), "offline") +})); + +// Group Listener +CometChat.addGroupListener("GROUP_LISTENER", new CometChat.GroupListener({ + onGroupMemberJoined: (action, user, group) => console.log("joined") +})); + +// Call Listener +CometChat.addCallListener("CALL_LISTENER", new CometChat.CallListener({ + onIncomingCallReceived: (call) => console.log("incoming call") +})); + +// Remove listeners +CometChat.removeMessageListener("MSG_LISTENER"); +``` + + +CometChat provides real-time event listeners to keep your application synchronized with chat activities. This guide covers all available listeners and their callback methods. + +## Available Listeners + + + + Online/offline presence events + + + Group membership and scope changes + + + Messages, typing, receipts, reactions + + + Incoming and outgoing call events + + + +## Quick Reference + +| Listener | Key Events | Use Case | +|----------|------------|----------| +| User | `onUserOnline`, `onUserOffline` | Presence indicators | +| Group | `onGroupMemberJoined`, `onGroupMemberLeft`, `onMemberAddedToGroup` | Group roster updates | +| Message | `onTextMessageReceived`, `onTypingStarted`, `onMessagesRead` | Chat UI updates | +| Call | `onIncomingCallReceived`, `onOutgoingCallAccepted` | Call handling | - -CometChat provides 4 listeners viz. - -1. [User Listener](/sdk/javascript/all-real-time-listeners#user-listener) -2. [Group Listener](/sdk/javascript/all-real-time-listeners#group-listener) -3. [Message Listener](/sdk/javascript/all-real-time-listeners#message-listener) -4. [Call Listener](/sdk/javascript/all-real-time-listeners#call-listener) +--- ## User Listener -The `UserListener` class provides you with live events related to users. Below are the callback methods provided by the `UserListener` class. - -| Method | Information | -| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **onUserOnline(user: CometChat.User)** | This method is triggered when a user comes online and is available to chat. The details of the user can be obtained from the user object received as the method parameter. | -| **onUserOffline(user: CometChat.User)** | This method is triggered when a user goes offline. The details of the user can be obtained from the User object received as the parameter. | +Monitor user presence changes in real-time. -To add the `UserListener`, you need to use the `addUserListener()` method provided by the `CometChat` class. +| Method | Description | +|--------|-------------| +| `onUserOnline(user)` | Triggered when a user comes online | +| `onUserOffline(user)` | Triggered when a user goes offline | -```js -var listenerID = "UNIQUE_LISTENER_ID"; +```javascript +const listenerID = "USER_LISTENER"; + CometChat.addUserListener( listenerID, new CometChat.UserListener({ onUserOnline: (onlineUser) => { - console.log("On User Online:", { onlineUser }); + console.log("User online:", onlineUser.getUid()); + // Update UI to show online status }, onUserOffline: (offlineUser) => { - console.log("On User Offline:", { offlineUser }); - }, + console.log("User offline:", offlineUser.getUid()); + // Update UI to show offline status + } }) ); -``` +// Remove when no longer needed +CometChat.removeUserListener(listenerID); +``` - ```typescript -var listenerID: string = "UNIQUE_LISTENER_ID"; +const listenerID: string = "USER_LISTENER"; + CometChat.addUserListener( listenerID, new CometChat.UserListener({ - onUserOnline: (onlineUser: CometChat.User) => { - /* when someuser/friend comes online, user will be received here */ - console.log("On User Online:", { onlineUser }); - }, - onUserOffline: (offlineUser: CometChat.User) => { - /* when someuser/friend went offline, user will be received here */ - console.log("On User Offline:", { offlineUser }); + onUserOnline: (onlineUser: CometChat.User): void => { + console.log("User online:", onlineUser.getUid()); }, + onUserOffline: (offlineUser: CometChat.User): void => { + console.log("User offline:", offlineUser.getUid()); + } }) ); -``` - - - - -where `UNIQUE_LISTENER_ID` is the unique identifier for the listener. Please make sure that no two listeners are added with the same listener id as this could lead to unexpected behavior resulting in loss of events. - -Once the `UserListener` is not in use, you need to remove the listener using the `removeUserListener()` method which takes the id of the listener to be removed as the parameter. - - - -```js -CometChat.removeUserListener(UNIQUE_LISTENER_ID); -``` - - - - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +// Remove when no longer needed CometChat.removeUserListener(listenerID); ``` - - -## Group Listener + +Use unique listener IDs. Duplicate IDs cause unexpected behavior and lost events. + -The `GroupListener` class provides you with all the real-time events related to groups. Below are the callback methods provided by the `GroupListener` class. +--- -| Method | Information | -| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| **onGroupMemberJoined(action: CometChat.Action, joinedUser: CometChat.User, joinedGroup: CometChat.Group)** | This method is triggered when a user joins any group. All the members present in the group will receive this event. | -| **onGroupMemberLeft(action: CometChat.Action, leftUser: CometChat.User, leftGroup: CometChat.Group)** | This method is triggered when a user who was a member of any group leaves the group. All the members of the group receive this event. | -| **onGroupMemberKicked(action: CometChat.Action, kickedUser: CometChat.User, kickedBy: CometChat.User, kickedFrom: CometChat.Group)** | This method is triggered when a user is kicked from a group. All the members including the user receive this event | -| **onGroupMemberBanned(action: CometChat.Action, bannedUser: CometChat.User, bannedBy: CometChat.User, bannedFrom: CometChat.Group)** | This method is triggered when a user is banned from a group. All the members including the user receive this event | -| **onGroupMemberUnbanned(action: CometChat.Action, unbannedUser: CometChat.User, unbannedBy: CometChat.User, unbannedFrom: CometChat.Group)** | This method is triggered when a user is banned from a group. All the members of the group receive this event. | -| **onGroupMemberScopeChanged(action: CometChat.Action, changedUser: CometChat.User, newScope: string, oldScope: string, changedGroup: CometChat.Group)** | This method is triggered when the scope of any Group Member has been changed. All the members that are a part of that group receive this event | -| **onMemberAddedToGroup(action: CometChat.Action, userAdded: CometChat.User, addedBy: CometChat.User, addedTo: CometChat.Group)** | This method is triggered when a user is added to any group. All the members including the user himself receive this event. | +## Group Listener + +Track all group membership and permission changes. -To add the `GroupListener`, you need to use the `addGroupListener()` method provided by the `CometChat` class. +| Method | Description | +|--------|-------------| +| `onGroupMemberJoined(action, joinedUser, joinedGroup)` | User joined a group | +| `onGroupMemberLeft(action, leftUser, leftGroup)` | User left a group | +| `onGroupMemberKicked(action, kickedUser, kickedBy, kickedFrom)` | User was kicked | +| `onGroupMemberBanned(action, bannedUser, bannedBy, bannedFrom)` | User was banned | +| `onGroupMemberUnbanned(action, unbannedUser, unbannedBy, unbannedFrom)` | User was unbanned | +| `onGroupMemberScopeChanged(action, changedUser, newScope, oldScope, changedGroup)` | User scope changed | +| `onMemberAddedToGroup(action, userAdded, addedBy, addedTo)` | User was added to group | -```js +```javascript +const listenerID = "GROUP_LISTENER"; + CometChat.addGroupListener( - "UNIQUE_LISTENER_ID", + listenerID, new CometChat.GroupListener({ onGroupMemberJoined: (message, joinedUser, joinedGroup) => { - console.log("onGroupMemberJoined", { message, joinedUser, joinedGroup }); + console.log(`${joinedUser.getName()} joined ${joinedGroup.getName()}`); }, onGroupMemberLeft: (message, leftUser, leftGroup) => { - console.log("onGroupMemberLeft", { message, leftUser, leftGroup }); + console.log(`${leftUser.getName()} left ${leftGroup.getName()}`); }, onGroupMemberKicked: (message, kickedUser, kickedBy, kickedFrom) => { - console.log("onGroupMemberKicked", { - message, - kickedUser, - kickedBy, - kickedFrom, - }); + console.log(`${kickedUser.getName()} was kicked by ${kickedBy.getName()}`); }, onGroupMemberBanned: (message, bannedUser, bannedBy, bannedFrom) => { - console.log("onGroupMemberBanned", { - message, - bannedUser, - bannedBy, - bannedFrom, - }); + console.log(`${bannedUser.getName()} was banned`); }, - onGroupMemberUnbanned: ( - message, - unbannedUser, - unbannedBy, - unbannedFrom - ) => { - console.log("onGroupMemberUnbanned", { - message, - unbannedUser, - unbannedBy, - unbannedFrom, - }); + onGroupMemberUnbanned: (message, unbannedUser, unbannedBy, unbannedFrom) => { + console.log(`${unbannedUser.getName()} was unbanned`); }, - onGroupMemberScopeChanged: ( - message, - changedUser, - newScope, - oldScope, - changedGroup - ) => { - console.log("onGroupMemberScopeChanged", { - message, - changedUser, - newScope, - oldScope, - changedGroup, - }); - }, - onMemberAddedToGroup: (message, userAdded, addedby, addedTo) => { - console.log("onMemberAddedToGroup", { - message, - userAdded, - addedby, - addedTo, - }); + onGroupMemberScopeChanged: (message, changedUser, newScope, oldScope, changedGroup) => { + console.log(`${changedUser.getName()} scope: ${oldScope} → ${newScope}`); }, + onMemberAddedToGroup: (message, userAdded, addedBy, addedTo) => { + console.log(`${userAdded.getName()} was added by ${addedBy.getName()}`); + } }) ); -``` +// Remove when no longer needed +CometChat.removeGroupListener(listenerID); +``` - ```typescript +const listenerID: string = "GROUP_LISTENER"; + CometChat.addGroupListener( - "UNIQUE_LISTENER_ID", + listenerID, new CometChat.GroupListener({ onGroupMemberJoined: ( message: CometChat.Action, joinedUser: CometChat.User, joinedGroup: CometChat.Group - ) => { - console.log("onGroupMemberJoined", { message, joinedUser, joinedGroup }); + ): void => { + console.log(`${joinedUser.getName()} joined ${joinedGroup.getName()}`); }, onGroupMemberLeft: ( message: CometChat.Action, leftUser: CometChat.User, leftGroup: CometChat.Group - ) => { - console.log("onGroupMemberLeft", { message, leftUser, leftGroup }); + ): void => { + console.log(`${leftUser.getName()} left ${leftGroup.getName()}`); }, onGroupMemberKicked: ( message: CometChat.Action, kickedUser: CometChat.User, kickedBy: CometChat.User, kickedFrom: CometChat.Group - ) => { - console.log("onGroupMemberKicked", { - message, - kickedUser, - kickedBy, - kickedFrom, - }); + ): void => { + console.log(`${kickedUser.getName()} was kicked by ${kickedBy.getName()}`); }, onGroupMemberBanned: ( message: CometChat.Action, bannedUser: CometChat.User, bannedBy: CometChat.User, bannedFrom: CometChat.Group - ) => { - console.log("onGroupMemberBanned", { - message, - bannedUser, - bannedBy, - bannedFrom, - }); + ): void => { + console.log(`${bannedUser.getName()} was banned`); }, onGroupMemberUnbanned: ( message: CometChat.Action, unbannedUser: CometChat.User, unbannedBy: CometChat.User, unbannedFrom: CometChat.Group - ) => { - console.log("onGroupMemberUnbanned", { - message, - unbannedUser, - unbannedBy, - unbannedFrom, - }); + ): void => { + console.log(`${unbannedUser.getName()} was unbanned`); }, onGroupMemberScopeChanged: ( message: CometChat.Action, @@ -235,298 +227,312 @@ CometChat.addGroupListener( newScope: string, oldScope: string, changedGroup: CometChat.Group - ) => { - console.log("onGroupMemberScopeChanged", { - message, - changedUser, - newScope, - oldScope, - changedGroup, - }); + ): void => { + console.log(`${changedUser.getName()} scope: ${oldScope} → ${newScope}`); }, onMemberAddedToGroup: ( message: CometChat.Action, userAdded: CometChat.User, - addedby: CometChat.User, + addedBy: CometChat.User, addedTo: CometChat.Group - ) => { - console.log("onMemberAddedToGroup", { - message, - userAdded, - addedby, - addedTo, - }); - }, + ): void => { + console.log(`${userAdded.getName()} was added by ${addedBy.getName()}`); + } }) ); -``` - - - - -where `UNIQUE_LISTENER_ID` is the unique identifier for the listener. Please make sure that no two listeners are added with the same listener id as this could lead to unexpected behavior resulting in loss of events. - -Once the `GroupListener` is not in use, you need to remove the listener using the `removeGroupListener()` method which takes the id of the listener to be removed as the parameter. - - - -```js -CometChat.removeGroupListener(UNIQUE_LISTENER_ID); -``` - - - - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +// Remove when no longer needed CometChat.removeGroupListener(listenerID); ``` - - +--- + ## Message Listener -The `MessageListener` class provides you with live events related to messages. Below are the callback methods provided by the `MessageListener` class. - -| Method | Information | -| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -| **onTextMessageReceived(message: CometChat.TextMessage)** | This event is triggered when a Text Message is received. | -| **onMediaMessageReceived(message: CometChat.MediaMessage)** | This event is triggered when a Media Message is received. | -| **onCustomMessageReceived(message: CometChat.CustomMessage)** | This event is triggered when a Custom Message is received. | -| **onTypingStarted(typingIndicator: CometChat.TypingIndicator)** | This event is triggered when a user starts typing in a user/group conversation | -| **onTypingEnded(typingIndicator: CometChat.TypingIndicator)** | This event is triggered when a user stops typing in a user/group conversation. | -| **onMessagesDelivered(messageReceipt: CometChat.MessageReceipt)** | This event is triggered when a set of messages are marked as delivered for any particular conversation. | -| **onMessagesRead(messageReceipt: CometChat.MessageReceipt)** | This event is triggered when a set of messages are marked as read for any particular conversation. | -| **onMessageEdited(message: CometChat.BaseMessage)** | This method is triggered when a particular message has been edited in a user/group conversation. | -| **onMessageDeleted(message: CometChat.BaseMessage)** | This event is triggered when a particular message is deleted in a user/group conversation. | -| **onInteractiveMessageReceived(message: CometChat.InteractiveMessage)** | This event is triggered when an Interactive Message is received. | -| **onInteractionGoalCompleted(receipt: CometChat.InteractionReceipt)** | This event is triggered when an interaction Goal is achieved. | -| **onTransientMessageReceived(receipt: CometChat.TransientMessage)** | This event is triggered when a Transient Message is received. | -| **onMessageReactionAdded(receipt: CometChat.ReactionEvent)** | This event is triggered when a reaction is added to a message in a user/group conversation. | -| **onMessageReactionRemoved(receipt: CometChat.ReactionEvent)** | This event is triggered when a reaction is remove from a message in a user/group conversation. | -| **onMessageModerated(message: CometChat.BaseMessage)** | This event is triggered when a message sent by the logged-in user is successfully processed by moderation and receives either an `approved` or `disapproved` status. | -To add the `MessageListener`, you need to use the `addMessageListener()` method provided by the `CometChat` class. +Handle all message-related events including typing indicators, receipts, and reactions. + +| Method | Description | +|--------|-------------| +| `onTextMessageReceived(message)` | Text message received | +| `onMediaMessageReceived(message)` | Media message received | +| `onCustomMessageReceived(message)` | Custom message received | +| `onInteractiveMessageReceived(message)` | Interactive message received | +| `onTypingStarted(typingIndicator)` | User started typing | +| `onTypingEnded(typingIndicator)` | User stopped typing | +| `onMessagesDelivered(messageReceipt)` | Messages marked delivered | +| `onMessagesRead(messageReceipt)` | Messages marked read | +| `onMessageEdited(message)` | Message was edited | +| `onMessageDeleted(message)` | Message was deleted | +| `onTransientMessageReceived(message)` | Transient message received | +| `onMessageReactionAdded(reaction)` | Reaction added to message | +| `onMessageReactionRemoved(reaction)` | Reaction removed from message | +| `onMessageModerated(message)` | Message moderation status updated | -```js +```javascript +const listenerID = "MESSAGE_LISTENER"; + CometChat.addMessageListener( - "UNIQUE_LISTENER_ID", + listenerID, new CometChat.MessageListener({ + // Message events onTextMessageReceived: (textMessage) => { - console.log("Text message received successfully", textMessage); + console.log("Text message:", textMessage.getText()); }, onMediaMessageReceived: (mediaMessage) => { - console.log("Media message received successfully", mediaMessage); + console.log("Media message:", mediaMessage.getAttachment()); }, onCustomMessageReceived: (customMessage) => { - console.log("Custom message received successfully", customMessage); - }, - onMessagesDelivered: (messageReceipt) => { - console.log("Message Delivered", messageReceipt); + console.log("Custom message:", customMessage.getCustomData()); }, - onMessagesRead: (messageReceipt) => { - console.log("Message Read", messageReceipt); + onInteractiveMessageReceived: (message) => { + console.log("Interactive message:", message); }, + + // Typing events onTypingStarted: (typingIndicator) => { - console.log("Typing Started", typingIndicator); + console.log(`${typingIndicator.getSender().getName()} is typing...`); }, onTypingEnded: (typingIndicator) => { - console.log("Typing Ended", typingIndicator); - }, - onMessagesDeleted: (message) => { - console.log("Message Deleted", message); + console.log(`${typingIndicator.getSender().getName()} stopped typing`); }, - onMessageEdited: (message) => { - console.log("Message Edited", message); + + // Receipt events + onMessagesDelivered: (messageReceipt) => { + console.log("Messages delivered:", messageReceipt.getMessageId()); }, - onInteractiveMessageReceived: (message) => { - console.log("interactive Message received", message); + onMessagesRead: (messageReceipt) => { + console.log("Messages read:", messageReceipt.getMessageId()); }, - onInteractionGoalCompleted: (message) => { - console.log("Message interaction goal completed", message); + + // Edit/Delete events + onMessageEdited: (message) => { + console.log("Message edited:", message.getId()); }, - onTransientMessageReceived: (message) => { - console.log("Transient Message received", message); + onMessageDeleted: (message) => { + console.log("Message deleted:", message.getId()); }, + + // Reaction events onMessageReactionAdded: (reaction) => { - console.log("Message Reaction added", reaction); + console.log("Reaction added:", reaction.getReaction()); }, onMessageReactionRemoved: (reaction) => { - console.log("Message Reaction removed", reaction); + console.log("Reaction removed:", reaction.getReaction()); }, - onMessageModerated: (message) => { - console.log("Message Moderated", message); + + // Other events + onTransientMessageReceived: (message) => { + console.log("Transient message:", message); }, + onMessageModerated: (message) => { + console.log("Message moderated:", message); + } }) ); -``` +// Remove when no longer needed +CometChat.removeMessageListener(listenerID); +``` - ```typescript +const listenerID: string = "MESSAGE_LISTENER"; + CometChat.addMessageListener( - "UNIQUE_LISTENER_ID", + listenerID, new CometChat.MessageListener({ - onTextMessageReceived: (textMessage: CometChat.TextMessage) => { - console.log("Text message received successfully", textMessage); - }, - onMediaMessageReceived: (mediaMessage: CometChat.MediaMessage) => { - console.log("Media message received successfully", mediaMessage); + // Message events + onTextMessageReceived: (textMessage: CometChat.TextMessage): void => { + console.log("Text message:", textMessage.getText()); }, - onCustomMessageReceived: (customMessage: CometChat.CustomMessage) => { - console.log("Custom message received successfully", customMessage); + onMediaMessageReceived: (mediaMessage: CometChat.MediaMessage): void => { + console.log("Media message:", mediaMessage.getAttachment()); }, - onMessagesDelivered: (messageReceipt: CometChat.MessageReceipt) => { - console.log("Message Delivered", messageReceipt); + onCustomMessageReceived: (customMessage: CometChat.CustomMessage): void => { + console.log("Custom message:", customMessage.getCustomData()); }, - onMessagesRead: (messageReceipt: CometChat.MessageReceipt) => { - console.log("Message Read", messageReceipt); + onInteractiveMessageReceived: (message: CometChat.InteractiveMessage): void => { + console.log("Interactive message:", message); }, - onTypingStarted: (typingIndicator: CometChat.TypingIndicator) => { - console.log("Typing Started", typingIndicator); + + // Typing events + onTypingStarted: (typingIndicator: CometChat.TypingIndicator): void => { + console.log(`${typingIndicator.getSender().getName()} is typing...`); }, - onTypingEnded: (typingIndicator: CometChat.TypingIndicator) => { - console.log("Typing Ended", typingIndicator); + onTypingEnded: (typingIndicator: CometChat.TypingIndicator): void => { + console.log(`${typingIndicator.getSender().getName()} stopped typing`); }, - onMessageDeleted: (message: CometChat.BaseMessage) => { - console.log("Message Delted", message); + + // Receipt events + onMessagesDelivered: (messageReceipt: CometChat.MessageReceipt): void => { + console.log("Messages delivered:", messageReceipt.getMessageId()); }, - onMessageEdited: (message: CometChat.BaseMessage) => { - console.log("Message Edited", message); + onMessagesRead: (messageReceipt: CometChat.MessageReceipt): void => { + console.log("Messages read:", messageReceipt.getMessageId()); }, - onInteractiveMessageReceived: (message: CometChat.InteractiveMessage) => { - console.log("interactive Message received", message); + + // Edit/Delete events + onMessageEdited: (message: CometChat.BaseMessage): void => { + console.log("Message edited:", message.getId()); }, - onInteractionGoalCompleted: (receipt: CometChat.InteractionReceipt) => { - console.log("Message interaction goal completed", message); + onMessageDeleted: (message: CometChat.BaseMessage): void => { + console.log("Message deleted:", message.getId()); }, - onTransientMessageReceived: (message: CometChat.TransientMessage) => { - console.log("Transient Message received", message); + + // Reaction events + onMessageReactionAdded: (reaction: CometChat.ReactionEvent): void => { + console.log("Reaction added:", reaction.getReaction()); }, - onMessageReactionAdded: (reaction: CometChat.ReactionEvent) => { - console.log("Message Reaction added", reaction); + onMessageReactionRemoved: (reaction: CometChat.ReactionEvent): void => { + console.log("Reaction removed:", reaction.getReaction()); }, - onMessageReactionRemoved: (reaction: CometChat.ReactionEvent) => { - console.log("Message Reaction removed", reaction); - }, - onMessageModerated: (message: CometChat.BaseMessage) => { - console.log("Message Moderated", message); + + // Other events + onTransientMessageReceived: (message: CometChat.TransientMessage): void => { + console.log("Transient message:", message); }, + onMessageModerated: (message: CometChat.BaseMessage): void => { + console.log("Message moderated:", message); + } }) ); -``` - - - - -where `UNIQUE_LISTENER_ID` is the unique identifier for the listener. Please make sure that no two listeners are added with the same listener id as this could lead to unexpected behavior resulting in loss of events. - -Once the `MessageListener` is not in use, you need to remove the listener using the `removeMessageListener()` method which takes the id of the listener to be removed as the parameter. - - - -```js -CometChat.removeMessageListener(UNIQUE_LISTENER_ID); -``` - - - - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +// Remove when no longer needed CometChat.removeMessageListener(listenerID); ``` - - -## Call Listener +--- -The `CallListener` class provides you with live events related to calls. Below are the callback methods provided by the `CallListener` class. +## Call Listener -| Method | Information | -| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **onIncomingCallReceived(call: CometChat.Call)** | This event is triggered when the logged-in user receives an incoming call. The details of the call can be obtained from the Call object received as the method parameter. | -| **onOutgoingCallAccepted(call: CometChat.Call)** | This event is triggered when the call initiated by the logged-in user is accepted by the recipient. The details of the call can be obtained from the Call object received as the method parameter. | -| **onOutgoingCallRejected(call: CometChat.Call)** | This event is triggered when the call initiated by the logged-in user is rejected by the recipient. The details of the call can be obtained from the Call object received as the method parameter | -| **onIncomingCallCancelled(call: CometChat.Call)** | This event is triggered when an incoming call is canceled by the initiator of the call. The details of the call can be obtained from the Call object received as the method parameter | +Handle voice and video call events. -To add the `CallListener`, you need to use the `addCallListener()` method provided by the `CometChat` class. +| Method | Description | +|--------|-------------| +| `onIncomingCallReceived(call)` | Incoming call received | +| `onOutgoingCallAccepted(call)` | Outgoing call was accepted | +| `onOutgoingCallRejected(call)` | Outgoing call was rejected | +| `onIncomingCallCancelled(call)` | Incoming call was cancelled | -```js +```javascript +const listenerID = "CALL_LISTENER"; + CometChat.addCallListener( - "UNIQUE_LISTENER_ID", + listenerID, new CometChat.CallListener({ - onIncomingCallReceived(call) { - console.log("Incoming call:", call); - }, - onOutgoingCallAccepted(call) { - console.log("Outgoing call accepted:", call); - }, - onOutgoingCallRejected(call) { - console.log("Outgoing call rejected:", call); - }, - onIncomingCallCancelled(call) { - console.log("Incoming call canceled:", call); - }, + onIncomingCallReceived: (call) => { + console.log("Incoming call from:", call.getSender().getName()); + // Show incoming call UI + }, + onOutgoingCallAccepted: (call) => { + console.log("Call accepted"); + // Start the call + }, + onOutgoingCallRejected: (call) => { + console.log("Call rejected"); + // Handle rejection + }, + onIncomingCallCancelled: (call) => { + console.log("Call cancelled"); + // Dismiss incoming call UI + } }) ); -``` +// Remove when no longer needed +CometChat.removeCallListener(listenerID); +``` - ```typescript +const listenerID: string = "CALL_LISTENER"; + CometChat.addCallListener( - "UNIQUE_LISTENER_ID", + listenerID, new CometChat.CallListener({ - onIncomingCallReceived: (call: CometChat.Call) => { - console.log("Incoming call:", call); + onIncomingCallReceived: (call: CometChat.Call): void => { + console.log("Incoming call from:", call.getSender().getName()); }, - onOutgoingCallAccepted: (call: CometChat.Call) => { - console.log("Outgoing call accepted:", call); + onOutgoingCallAccepted: (call: CometChat.Call): void => { + console.log("Call accepted"); }, - onOutgoingCallRejected: (call: CometChat.Call) => { - console.log("Outgoing call rejected:", call); - }, - onIncomingCallCancelled: (call: CometChat.Call) => { - console.log("Incoming call canceled:", call); + onOutgoingCallRejected: (call: CometChat.Call): void => { + console.log("Call rejected"); }, + onIncomingCallCancelled: (call: CometChat.Call): void => { + console.log("Call cancelled"); + } }) ); -``` - - - - -where `UNIQUE_LISTENER_ID` is the unique identifier for the listener. Please make sure that no two listeners are added with the same listener id as this could lead to unexpected behavior resulting in loss of events. - -Once the `CallListener` is not in use, you need to remove the listener using the `removeCallListener()` method which takes the id of the listener to be removed as the parameter. - - - -```js -CometChat.removeCallListener(UNIQUE_LISTENER_ID); -``` - - - - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +// Remove when no longer needed CometChat.removeCallListener(listenerID); ``` - - + +--- + +## Best Practices + + + + Each listener must have a unique ID. Using duplicate IDs causes events to be lost. + + ```javascript + // Good: Unique IDs per component + CometChat.addMessageListener("CHAT_SCREEN_LISTENER", ...); + CometChat.addMessageListener("NOTIFICATION_LISTENER", ...); + + // Bad: Same ID + CometChat.addMessageListener("LISTENER", ...); + CometChat.addMessageListener("LISTENER", ...); // Overwrites first! + ``` + + + + Remove listeners when components unmount to prevent memory leaks. + + ```javascript + // React example + useEffect(() => { + CometChat.addMessageListener("MSG_LISTENER", listener); + + return () => { + CometChat.removeMessageListener("MSG_LISTENER"); + }; + }, []); + ``` + + + + Subscribe to all events your UI needs to stay synchronized. + + ```javascript + // For a chat screen, handle: + // - New messages (onTextMessageReceived, onMediaMessageReceived) + // - Typing indicators (onTypingStarted, onTypingEnded) + // - Read receipts (onMessagesRead) + // - Edits/deletes (onMessageEdited, onMessageDeleted) + ``` + + + +## Next Steps + + + + Monitor WebSocket connection state + + + Handle authentication events + + diff --git a/sdk/javascript/authentication-overview.mdx b/sdk/javascript/authentication-overview.mdx index 1df05717..35136182 100644 --- a/sdk/javascript/authentication-overview.mdx +++ b/sdk/javascript/authentication-overview.mdx @@ -1,197 +1,701 @@ --- title: "Authentication" sidebarTitle: "Overview" +description: "Authenticate users with CometChat using Auth Keys or Auth Tokens" --- +{/* Agent-Friendly Quick Reference */} + +**Quick Reference** +```javascript +// Development: Login with Auth Key (NOT for production) +await CometChat.login("USER_UID", "AUTH_KEY"); -## Create User +// Production: Login with Auth Token (generated server-side) +await CometChat.login("AUTH_TOKEN_FROM_SERVER"); -Before you log in a user, you must add the user to CometChat. +// Check if already logged in +const user = await CometChat.getLoggedinUser(); +if (user) console.log("Already logged in:", user.getName()); -1. **For proof of concept/MVPs**: Create the user using the [CometChat Dashboard](https://app.cometchat.com). -2. **For production apps**: Use the CometChat [Create User API](https://api-explorer.cometchat.com/reference/creates-user) to create the user when your user signs up in your app. +// Logout +await CometChat.logout(); +``` - +**Decision:** +- Building/testing? → Use Auth Key with test users (`cometchat-uid-1` to `cometchat-uid-5`) +- Going to production? → Generate Auth Tokens server-side via REST API + -We have setup 5 users for testing having UIDs: `cometchat-uid-1`, `cometchat-uid-2`, `cometchat-uid-3`, `cometchat-uid-4` and `cometchat-uid-5`. +CometChat requires users to be authenticated before they can send or receive messages. This guide covers the authentication flow and best practices for both development and production environments. + +**CometChat does not handle user management.** You manage user registration and login in your app. Once a user logs into your app, you programmatically log them into CometChat. -Once initialization is successful, you will need to log the user into CometChat using the `login()` method. +## Authentication Flow + +```mermaid +sequenceDiagram + participant User + participant YourApp + participant YourServer + participant CometChat + + User->>YourApp: Signs up / Logs in + YourApp->>YourServer: Authenticate user + YourServer->>CometChat: Create user (if new) + YourServer->>CometChat: Get Auth Token + YourServer->>YourApp: Return Auth Token + YourApp->>CometChat: Login with Auth Token + CometChat->>YourApp: User session established +``` -We recommend you call the CometChat login method once your user logs into your app. The `login()` method needs to be called only once. +## Choose Your Authentication Method + + + + Simple setup for prototyping and testing. The Auth Key is used directly in client code. + + **Use for:** POC, development, testing + + + Secure authentication where tokens are generated server-side. Auth Key never exposed to clients. + + **Use for:** Production applications + + - +--- + +## Create a User -The CometChat SDK maintains the session of the logged-in user within the SDK. Thus you do not need to call the login method for every session. You can use the CometChat.getLoggedinUser() method to check if there is any existing session in the SDK. This method should return the details of the logged-in user. If this method returns null, it implies there is no session present within the SDK and you need to log the user into CometChat. +Before logging in, users must exist in CometChat. + + + For testing, create users manually in the [CometChat Dashboard](https://app.cometchat.com) under **Users**. + + + We provide 5 test users: `cometchat-uid-1` through `cometchat-uid-5` + + + + For production, create users via the [Create User API](https://api-explorer.cometchat.com/reference/creates-user) when users sign up in your app. + + + Create users directly from the client (development only): + + ```javascript + const authKey = "YOUR_AUTH_KEY"; + const uid = "user1"; + const name = "Kevin"; + + const user = new CometChat.User(uid); + user.setName(name); + + CometChat.createUser(user, authKey).then( + (user) => console.log("User created:", user), + (error) => console.log("Error:", error) + ); + ``` + + + + +**UID Requirements:** Alphanumeric characters, underscores, and hyphens only. No spaces, punctuation, or special characters. -## Login using Auth Key +--- -This straightforward authentication method is ideal for proof-of-concept (POC) development or during the early stages of application development. For production environments, however, we strongly recommend using an [AuthToken](#login-using-auth-token) instead of an Auth Key to ensure enhanced security. +## Login with Auth Key - - -```js -var UID = "UID"; -var authKey = "AUTH_KEY"; + +**Development Only:** Auth Key login exposes your key in client code. Use [Auth Token](#login-with-auth-token) for production. + -CometChat.getLoggedinUser().then( - (user) => { - if (!user) { - CometChat.login(UID, authKey).then( - (user) => { - console.log("Login Successful:", { user }); - }, - (error) => { - console.log("Login failed with exception:", { error }); +The simplest way to authenticate during development: + + + + ```javascript + const UID = "cometchat-uid-1"; + const authKey = "YOUR_AUTH_KEY"; + + // Check if already logged in + CometChat.getLoggedinUser().then( + (user) => { + if (!user) { + // Not logged in, proceed with login + CometChat.login(UID, authKey).then( + (user) => { + console.log("Login successful:", user); + }, + (error) => { + console.log("Login failed:", error); + } + ); + } else { + console.log("Already logged in:", user); + } + }, + (error) => { + console.log("Error:", error); + } + ); + ``` + + + ```typescript + const UID: string = "cometchat-uid-1"; + const authKey: string = "YOUR_AUTH_KEY"; + + CometChat.getLoggedinUser().then( + (user: CometChat.User | null) => { + if (!user) { + CometChat.login(UID, authKey).then( + (user: CometChat.User) => { + console.log("Login successful:", user); + }, + (error: CometChat.CometChatException) => { + console.log("Login failed:", error); + } + ); + } else { + console.log("Already logged in:", user); } - ); + }, + (error: CometChat.CometChatException) => { + console.log("Error:", error); + } + ); + ``` + + + ```javascript + const UID = "cometchat-uid-1"; + const authKey = "YOUR_AUTH_KEY"; + + async function loginWithAuthKey() { + try { + // Check if already logged in + let user = await CometChat.getLoggedinUser(); + + if (user) { + console.log("Already logged in:", user.getName()); + return user; + } + + // Login + user = await CometChat.login(UID, authKey); + console.log("Login successful:", user.getName()); + return user; + } catch (error) { + console.error("Login failed:", error); + throw error; + } } - }, - (error) => { - console.log("Something went wrong", error); - } -); -``` - + loginWithAuthKey(); + ``` + + - -```typescript -var UID: string = "cometchat-uid-1", - authKey: string = "AUTH_KEY"; +| Parameter | Description | +|-----------|-------------| +| `UID` | The unique identifier of the user to log in | +| `authKey` | Your CometChat Auth Key from the dashboard | -CometChat.getLoggedinUser().then( - (user: CometChat.User) => { - if (!user) { - CometChat.login(UID, authKey).then( - (user: CometChat.User) => { - console.log("Login Successful:", { user }); - }, - (error: CometChat.CometChatException) => { - console.log("Login failed with exception:", { error }); +--- + +## Login with Auth Token + + +**Recommended for Production:** Auth Tokens are generated server-side, keeping your Auth Key secure. + + +### How It Works + + + + Create the user in CometChat via [REST API](https://api-explorer.cometchat.com/reference/creates-user) + + + Call the [Create Auth Token API](https://api-explorer.cometchat.com/reference/create-authtoken) from your server + + + Your server returns the Auth Token to your client app + + + Use the token to log in via the SDK + + + +### Client-Side Login + + + + ```javascript + const authToken = "AUTH_TOKEN_FROM_YOUR_SERVER"; + + CometChat.getLoggedinUser().then( + (user) => { + if (!user) { + CometChat.login(authToken).then( + (user) => { + console.log("Login successful:", user); + }, + (error) => { + console.log("Login failed:", error); + } + ); + } else { + console.log("Already logged in:", user); + } + }, + (error) => { + console.log("Error:", error); + } + ); + ``` + + + ```typescript + const authToken: string = "AUTH_TOKEN_FROM_YOUR_SERVER"; + + CometChat.getLoggedinUser().then( + (user: CometChat.User | null) => { + if (!user) { + CometChat.login(authToken).then( + (user: CometChat.User) => { + console.log("Login successful:", user); + }, + (error: CometChat.CometChatException) => { + console.log("Login failed:", error); + } + ); + } else { + console.log("Already logged in:", user); + } + }, + (error: CometChat.CometChatException) => { + console.log("Error:", error); + } + ); + ``` + + + ```javascript + async function loginWithAuthToken(authToken) { + try { + // Check if already logged in + let user = await CometChat.getLoggedinUser(); + + if (user) { + console.log("Already logged in:", user.getName()); + return user; } - ); - } - }, - (error: CometChat.CometChatException) => { - console.log("Some Error Occured", { error }); - } -); -``` - + // Login with token + user = await CometChat.login(authToken); + console.log("Login successful:", user.getName()); + return user; + } catch (error) { + console.error("Login failed:", error); + throw error; + } + } + // Get token from your server and login + async function authenticateUser(userId) { + // 1. Get auth token from your backend + const response = await fetch(`/api/cometchat/token/${userId}`); + const { authToken } = await response.json(); + + // 2. Login to CometChat + return loginWithAuthToken(authToken); + } + ``` + -| Parameters | Description | -| ---------- | ------------------------------------------------ | -| UID | The UID of the user that you would like to login | -| authKey | CometChat Auth Key | +| Parameter | Description | +|-----------|-------------| +| `authToken` | The Auth Token generated by your server | -After the user logs in, their information is returned in the `User` object on `Promise` resolved. - -## Login using Auth Token +--- -This advanced authentication procedure does not use the Auth Key directly in your client code thus ensuring safety. +## Check Login Status -1. [Create a User](https://api-explorer.cometchat.com/reference/creates-user) via the CometChat API when the user signs up in your app. -2. [Create an Auth Token](https://api-explorer.cometchat.com/reference/create-authtoken) via the CometChat API for the new user and save the token in your database. -3. Load the Auth Token in your client and pass it to the `login()` method. +The SDK maintains the user session. Check if a user is already logged in before calling `login()`: -```js -var authToken = "AUTH_TOKEN"; - +```javascript CometChat.getLoggedinUser().then( (user) => { - if (!user) { - CometChat.login(authToken).then( - (user) => { - console.log("Login Successful:", { user }); - }, - (error) => { - console.log("Login failed with exception:", { error }); - } - ); + if (user) { + console.log("User is logged in:", user.getName()); + } else { + console.log("No user logged in"); + // Proceed with login } }, (error) => { - console.log("Something went wrong", error); + console.log("Error checking login status:", error); } ); ``` - - - -```typescript -var authToken: string = "AUTH_TOKEN"; - -CometChat.getLoggedinUser().then( - (user: CometChat.User) => { - if (!user) { - CometChat.login(authToken).then( - (user: CometChat.User) => { - console.log("Login Successful:", { user }); - }, - (error: CometChat.CometChatException) => { - console.log("Login failed with exception:", { error }); - } - ); + +```javascript +async function checkLoginStatus() { + try { + const user = await CometChat.getLoggedinUser(); + if (user) { + console.log("User is logged in:", user.getName()); + return user; + } else { + console.log("No user logged in"); + return null; } - }, - (error: CometChat.CometChatException) => { - console.log("Some Error Occured", { error }); + } catch (error) { + console.log("Error checking login status:", error); + throw error; } -); +} ``` - - -| Parameter | Description | -| --------- | ---------------------------------------------- | -| authToken | Auth Token of the user you would like to login | + +You only need to call `login()` once. The SDK persists the session, so users remain logged in across page refreshes until you call `logout()`. + -After the user logs in, their information is returned in the `User` object on the `Promise` resolved. +--- ## Logout -You can use the `logout()` method to log out the user from CometChat. We suggest you call this method once your user has been successfully logged out from your app. +Log out the user when they sign out of your app: + + + + ```javascript + CometChat.logout().then( + () => { + console.log("Logout successful"); + }, + (error) => { + console.log("Logout failed:", error); + } + ); + ``` + + + ```typescript + CometChat.logout().then( + () => { + console.log("Logout successful"); + }, + (error: CometChat.CometChatException) => { + console.log("Logout failed:", error); + } + ); + ``` + + + ```javascript + async function logout() { + try { + await CometChat.logout(); + console.log("Logout successful"); + // Redirect to login page or update UI + } catch (error) { + console.error("Logout failed:", error); + } + } + ``` + + + + +Always call `CometChat.logout()` when users sign out of your app. This clears the local session and stops real-time event delivery. + + +--- + +## Server-Side Token Generation + +Here's how to generate Auth Tokens on your backend: + + + + ```javascript + // server.js + const express = require("express"); + const fetch = require("node-fetch"); + + const app = express(); + + const APP_ID = process.env.COMETCHAT_APP_ID; + const REGION = process.env.COMETCHAT_REGION; + const API_KEY = process.env.COMETCHAT_API_KEY; // REST API Key + + // Generate auth token for a user + app.post("/api/cometchat/token/:uid", async (req, res) => { + const { uid } = req.params; + + try { + const response = await fetch( + `https://${APP_ID}.api-${REGION}.cometchat.io/v3/users/${uid}/auth_tokens`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "apiKey": API_KEY + } + } + ); + + const data = await response.json(); + + if (data.data?.authToken) { + res.json({ authToken: data.data.authToken }); + } else { + res.status(400).json({ error: "Failed to generate token" }); + } + } catch (error) { + res.status(500).json({ error: error.message }); + } + }); + + // Create user and generate token + app.post("/api/cometchat/users", async (req, res) => { + const { uid, name, avatar } = req.body; + + try { + // Create user + await fetch( + `https://${APP_ID}.api-${REGION}.cometchat.io/v3/users`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "apiKey": API_KEY + }, + body: JSON.stringify({ uid, name, avatar }) + } + ); + + // Generate token + const tokenResponse = await fetch( + `https://${APP_ID}.api-${REGION}.cometchat.io/v3/users/${uid}/auth_tokens`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "apiKey": API_KEY + } + } + ); + + const tokenData = await tokenResponse.json(); + res.json({ authToken: tokenData.data.authToken }); + } catch (error) { + res.status(500).json({ error: error.message }); + } + }); + + app.listen(3000); + ``` + + + ```python + # server.py + from flask import Flask, jsonify, request + import requests + import os + + app = Flask(__name__) + + APP_ID = os.environ.get("COMETCHAT_APP_ID") + REGION = os.environ.get("COMETCHAT_REGION") + API_KEY = os.environ.get("COMETCHAT_API_KEY") + + BASE_URL = f"https://{APP_ID}.api-{REGION}.cometchat.io/v3" + + @app.route("/api/cometchat/token/", methods=["POST"]) + def generate_token(uid): + response = requests.post( + f"{BASE_URL}/users/{uid}/auth_tokens", + headers={ + "Content-Type": "application/json", + "apiKey": API_KEY + } + ) + + data = response.json() + if "data" in data and "authToken" in data["data"]: + return jsonify({"authToken": data["data"]["authToken"]}) + return jsonify({"error": "Failed to generate token"}), 400 + + if __name__ == "__main__": + app.run(port=3000) + ``` + + + +--- + +## User Object + +On successful login, you receive a `User` object with the following properties: + +| Property | Type | Description | +|----------|------|-------------| +| `uid` | string | Unique identifier | +| `name` | string | Display name | +| `avatar` | string | Profile picture URL | +| `status` | string | `online` or `offline` | +| `role` | string | User role for access control | +| `metadata` | object | Custom data | +| `lastActiveAt` | number | Unix timestamp of last activity | + +Access user properties: -```js -CometChat.logout().then( - () => { - console.log("Logout completed successfully"); - }, - (error) => { - console.log("Logout failed with exception:", { error }); +```javascript +CometChat.login(UID, authKey).then((user) => { + console.log("UID:", user.getUid()); + console.log("Name:", user.getName()); + console.log("Avatar:", user.getAvatar()); + console.log("Status:", user.getStatus()); +}); +``` + + +```javascript +async function loginAndGetUserInfo(UID, authKey) { + try { + const user = await CometChat.login(UID, authKey); + console.log("UID:", user.getUid()); + console.log("Name:", user.getName()); + console.log("Avatar:", user.getAvatar()); + console.log("Status:", user.getStatus()); + return user; + } catch (error) { + console.log("Login failed:", error); + throw error; } -); +} ``` - + - -```typescript -CometChat.logout().then( - (loggedOut: Object) => { - console.log("Logout completed successfully"); - }, - (error: CometChat.CometChatException) => { - console.log("Logout failed with exception:", { error }); - } +--- + +## Listen for Login Events + +Monitor authentication state changes across devices: + +```javascript +const listenerID = "AUTH_LISTENER"; + +CometChat.addLoginListener( + listenerID, + new CometChat.LoginListener({ + loginSuccess: (user) => { + console.log("User logged in:", user); + }, + logoutSuccess: () => { + console.log("User logged out"); + }, + }) ); + +// Remove listener when no longer needed +CometChat.removeLoginListener(listenerID); ``` - +Learn more about [Login Listeners](/sdk/javascript/login-listener). - +--- + +## Best Practices + + + + Before calling `login()`, use `getLoggedinUser()` to check if a session exists. This prevents unnecessary API calls and potential errors. + + + Never expose your Auth Key in production client code. Generate Auth Tokens server-side and pass them to your client. + + + Auth Tokens can expire. Implement token refresh logic in your app to generate new tokens when needed. + + + Call `CometChat.logout()` when users log out of your app to properly clean up the CometChat session. + + + +--- + +## Troubleshooting + + + + The UID you're trying to login with hasn't been created in CometChat. + + **Solutions:** + - Use test users: `cometchat-uid-1` through `cometchat-uid-5` + - Create the user first via REST API or SDK + - Check for typos in the UID + + + **Causes:** + - Using REST API Key instead of Auth Key + - Auth Key has extra spaces + - Auth Key is from a different app + + **Solution:** Copy the Auth Key directly from Dashboard → API & Auth Keys + + + Auth Tokens have an expiration time (default: 15 minutes). + + **Solutions:** + - Generate a new token from your server + - Increase token expiration in Dashboard settings + - Implement token refresh logic in your app + + + **Causes:** + - Message listeners not registered + - WebSocket connection not established + + **Solutions:** + - Register listeners after successful login + - Check `autoEstablishSocketConnection(true)` in app settings + - Add a connection listener to debug + + + +--- + +## Next Steps + + + + Start sending text, media, and custom messages + + + Create, update, and manage users + + + Handle real-time and historical messages + + + Understand users, groups, and messages + + diff --git a/sdk/javascript/block-users.mdx b/sdk/javascript/block-users.mdx index 738e07ab..26c4da84 100644 --- a/sdk/javascript/block-users.mdx +++ b/sdk/javascript/block-users.mdx @@ -1,226 +1,431 @@ --- title: "Block Users" +sidebarTitle: "Block Users" +description: "Block and unblock users to control communication" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Block users +await CometChat.blockUsers(["user1", "user2"]); -## Block Users +// Unblock users +await CometChat.unblockUsers(["user1"]); + +// Fetch blocked users list +const blockedRequest = new CometChat.BlockedUsersRequestBuilder() + .setLimit(30) + .setDirection(CometChat.BlockedUsersRequest.directions.BLOCKED_BY_ME) + .build(); +const blockedUsers = await blockedRequest.fetchNext(); + +// Check block status on user object +const user = await CometChat.getUser("user_uid"); +const blockedByMe = user.getBlockedByMe(); +const hasBlockedMe = user.getHasBlockedMe(); +``` + + +Blocking users prevents all communication between the logged-in user and the blocked user. Messages, calls, and other interactions are completely blocked in both directions. + + +**Availability**: SDK, API, UI Kits -*In other words, as a logged-in user, how do I block a user from sending me messages?* +Blocking is bidirectional - neither party can communicate with the other once blocked. + -You can block users using the `blockUsers()` method. Once any user is blocked, all the communication to and from the respective user will be completely blocked. You can block multiple users in a single operation. The `blockUsers()` method takes a `Array` as a parameter which holds the list of `UID's` to be blocked. +--- + +## Block Users + +Block one or more users by their UIDs: - + ```javascript -var usersList = ["UID1", "UID2", "UID3"]; +const usersList = ["UID1", "UID2", "UID3"]; CometChat.blockUsers(usersList).then( -list => { - console.log("users list blocked", { list }); -}, error => { - console.log("Blocking user fails with error", error); -} + (result) => { + console.log("Block result:", result); + // { UID1: "success", UID2: "success", UID3: "success" } + }, + (error) => console.log("Failed to block:", error) ); ``` - - ```typescript -var usersList: String[] = ["UID1", "UID2", "UID3"]; +const usersList: string[] = ["UID1", "UID2", "UID3"]; CometChat.blockUsers(usersList).then( - (list: Object) => { - console.log("users list blocked", { list }); - }, (error: CometChat.CometChatException) => { - console.log("Blocking user fails with error", error); + (result: Object) => { + console.log("Block result:", result); + }, + (error: CometChat.CometChatException) => { + console.log("Failed to block:", error); } ); ``` - + +```javascript +async function blockUser(uid) { + try { + const result = await CometChat.blockUsers([uid]); + console.log("User blocked:", result); + return result; + } catch (error) { + console.error("Failed to block:", error); + throw error; + } +} + +async function blockMultipleUsers(uids) { + try { + const result = await CometChat.blockUsers(uids); + console.log("Users blocked:", result); + return result; + } catch (error) { + console.error("Failed to block:", error); + throw error; + } +} +// Usage +await blockUser("user123"); +await blockMultipleUsers(["user1", "user2", "user3"]); +``` + -It returns a Array which contains `UID's` as the keys and "success" or "fail" as the value based on if the block operation for the `UID` was successful or not. +Returns an object with UIDs as keys and `"success"` or `"fail"` as values. -## Unblock Users +--- -*In other words, as a logged-in user, how do I unblock a user I previously blocked?* +## Unblock Users -You can unblock the already blocked users using the `unblockUsers()` method. You can unblock multiple users in a single operation. The `unblockUsers()` method takes a `Array` as a parameter which holds the list of `UID's` to be unblocked. +Unblock previously blocked users: - + ```javascript -var usersList = ["UID1", "UID2", "UID3"]; +const usersList = ["UID1", "UID2", "UID3"]; CometChat.unblockUsers(usersList).then( -list => { - console.log("users list unblocked", { list }); -}, error => { - console.log("unblocking user fails with error", error); -} + (result) => { + console.log("Unblock result:", result); + // { UID1: "success", UID2: "success", UID3: "success" } + }, + (error) => console.log("Failed to unblock:", error) ); ``` - - ```typescript -var usersList: String[] = ["UID1", "UID2", "UID3"]; +const usersList: string[] = ["UID1", "UID2", "UID3"]; CometChat.unblockUsers(usersList).then( - (list: Object) => { - console.log("users list blocked", { list }); - }, (error: CometChat.CometChatException) => { - console.log("Blocking user fails with error", error); + (result: Object) => { + console.log("Unblock result:", result); + }, + (error: CometChat.CometChatException) => { + console.log("Failed to unblock:", error); } -); +); ``` - + +```javascript +async function unblockUser(uid) { + try { + const result = await CometChat.unblockUsers([uid]); + console.log("User unblocked:", result); + return result; + } catch (error) { + console.error("Failed to unblock:", error); + throw error; + } +} +// Usage +await unblockUser("user123"); +``` + -It returns a Array which contains `UID's` as the keys and `success` or `fail` as the value based on if the unblock operation for the `UID` was successful or not. - -## Get List of Blocked Users - -*In other words, as a logged-in user, how do I get a list of all users I've blocked?* - -In order to fetch the list of blocked users, you can use the `BlockedUsersRequest` class. To use this class i.e to create an object of the `BlockedUsersRequest class`, you need to use the `BlockedUsersRequestBuilder` class. The `BlockedUsersRequestBuilder` class allows you to set the parameters based on which the blocked users are to be fetched. - -The `BlockedUsersRequestBuilder` class allows you to set the below parameters: +--- -### Set Limit +## Get Blocked Users List -This method sets the limit i.e. the number of blocked users that should be fetched in a single iteration. +Fetch the list of blocked users using `BlockedUsersRequestBuilder`: - + ```javascript -let limit = 30; -let blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() - .setLimit(limit) - .build(); -``` +const limit = 30; - - - -```typescript -let limit: number = 30; -let blockedUsersRequest: CometChat.BlockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() +const blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() .setLimit(limit) .build(); -``` +blockedUsersRequest.fetchNext().then( + (userList) => console.log("Blocked users:", userList), + (error) => console.log("Failed to fetch:", error) +); +``` + +```typescript +const limit: number = 30; - - -### Set Search Keyword - -This method allows you to set the search string based on which the blocked users are to be fetched. +const blockedUsersRequest: CometChat.BlockedUsersRequest = + new CometChat.BlockedUsersRequestBuilder() + .setLimit(limit) + .build(); - - -```javascript -let limit = 30; -let searchKeyword = "super"; -let blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); +blockedUsersRequest.fetchNext().then( + (userList: CometChat.User[]) => console.log("Blocked users:", userList), + (error: CometChat.CometChatException) => console.log("Failed:", error) +); ``` - + +```javascript +async function fetchBlockedUsers(limit = 30) { + try { + const blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() + .setLimit(limit) + .build(); + + const userList = await blockedUsersRequest.fetchNext(); + console.log("Blocked users:", userList); + return userList; + } catch (error) { + console.error("Failed to fetch blocked users:", error); + throw error; + } +} - -```typescript -let limit: number = 30; -let searchKeyword: string = "super"; -let blockedUsersRequest: CometChat.BlockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); +// Usage +const blockedUsers = await fetchBlockedUsers(); ``` - - -### Set Direction -* CometChat.BlockedUsersRequest.directions.BLOCKED\_BY\_ME - This will ensure that the list of blocked users only contains the users blocked by the logged in user. -* CometChat.BlockedUsersRequest.directions.HAS\_BLOCKED\_ME - This will ensure that the list of blocked users only contains the users that have blocked the logged in user. -* CometChat.BlockedUsersRequest.directions.BOTH - This will make sure the list of users includes both the above cases. This is the default value for the direction variable if it is not set. +### Builder Options + +| Method | Description | +|--------|-------------| +| `setLimit(limit)` | Number of users to fetch per request (max 100) | +| `setSearchKeyword(keyword)` | Search blocked users by name | +| `setDirection(direction)` | Filter by block direction | + +### Filter by Direction - - ```javascript -let limit = 30; -let blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() - .setLimit(limit) +const blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() + .setLimit(30) .setDirection(CometChat.BlockedUsersRequest.directions.BLOCKED_BY_ME) .build(); ``` - +| Direction | Description | +|-----------|-------------| +| `BLOCKED_BY_ME` | Users you have blocked | +| `HAS_BLOCKED_ME` | Users who have blocked you | +| `BOTH` | Both directions (default) | - -```typescript -let limit: number = 30; -let blockedUsersRequest: CometChat.BlockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() - .setLimit(limit) - .setDirection(CometChat.BlockedUsersRequest.directions.BLOCKED_BY_ME) +### Search Blocked Users + + + +```javascript +const blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() + .setLimit(30) + .setSearchKeyword("john") .build(); -``` +blockedUsersRequest.fetchNext().then( + (userList) => console.log("Search results:", userList), + (error) => console.log("Failed:", error) +); +``` + +```javascript +async function searchBlockedUsers(keyword) { + try { + const blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() + .setLimit(30) + .setSearchKeyword(keyword) + .build(); + + const userList = await blockedUsersRequest.fetchNext(); + console.log("Search results:", userList); + return userList; + } catch (error) { + console.error("Failed to search blocked users:", error); + throw error; + } +} +// Usage +const results = await searchBlockedUsers("john"); +``` + -Finally, once all the parameters are set to the builder class, you need to call the build() method to get the object of the `BlockedUsersRequest` class. +--- -Once you have the object of the `BlockedUsersRequest` class, you need to call the `fetchNext()` method. Calling this method will return a list of `User` objects containing n number of blocked users where N is the limit set in the builder class. +## Check Block Status + +When you have a user object, check the block relationship: - - ```javascript -var limit = 30; -var blockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() - .setLimit(limit) - .build(); -blockedUsersRequest.fetchNext().then( -userList => { - console.log("Blocked user list received:", userList); -}, error => { - console.log("Blocked user list fetching failed with error:", error); +const user = await CometChat.getUser("user1"); + +// Check if you blocked this user +const blockedByMe = user.getBlockedByMe(); + +// Check if this user blocked you +const hasBlockedMe = user.getHasBlockedMe(); + +if (blockedByMe) { + console.log("You have blocked this user"); +} + +if (hasBlockedMe) { + console.log("This user has blocked you"); } -); ``` - +--- - -```typescript -let limit: number = 30; -let blockedUsersRequest: CometChat.BlockedUsersRequest = new CometChat.BlockedUsersRequestBuilder() - .setLimit(limit) - .build(); +## Implementation Example -blockedUsersRequest.fetchNext().then( - (userList: CometChat.User[]) => { - console.log("Blocked user list received:", userList); - }, (error: CometChat.CometChatException) => { - console.log("Blocked user list fetching failed with error:", error); +```javascript +class BlockManager { + constructor() { + this.blockedUsers = new Set(); } -); + + async loadBlockedUsers() { + const request = new CometChat.BlockedUsersRequestBuilder() + .setLimit(100) + .setDirection(CometChat.BlockedUsersRequest.directions.BLOCKED_BY_ME) + .build(); + + try { + const users = await request.fetchNext(); + users.forEach((user) => this.blockedUsers.add(user.getUid())); + } catch (error) { + console.log("Failed to load blocked users:", error); + } + } + + isBlocked(uid) { + return this.blockedUsers.has(uid); + } + + async blockUser(uid) { + try { + await CometChat.blockUsers([uid]); + this.blockedUsers.add(uid); + console.log("User blocked:", uid); + } catch (error) { + console.log("Failed to block:", error); + } + } + + async unblockUser(uid) { + try { + await CometChat.unblockUsers([uid]); + this.blockedUsers.delete(uid); + console.log("User unblocked:", uid); + } catch (error) { + console.log("Failed to unblock:", error); + } + } + + async toggleBlock(uid) { + if (this.isBlocked(uid)) { + await this.unblockUser(uid); + } else { + await this.blockUser(uid); + } + } +} + +// Usage +const blockManager = new BlockManager(); +await blockManager.loadBlockedUsers(); + +// Check if user is blocked +if (blockManager.isBlocked("user123")) { + console.log("User is blocked"); +} + +// Toggle block status +await blockManager.toggleBlock("user123"); ``` - +--- - +## What Happens When Blocked + +When a user is blocked: + +| Feature | Behavior | +|---------|----------| +| Messages | Cannot send or receive messages | +| Calls | Cannot initiate or receive calls | +| Typing Indicators | Not sent or received | +| Read Receipts | Not sent or received | +| Presence | Online status not visible | +| Conversations | Existing conversations remain but are inactive | + + +Blocking is immediate. Any pending messages or calls will fail once the block is in place. + + +--- + +## Best Practices + + + + - Show clear feedback when blocking/unblocking + - Provide confirmation before blocking + - Allow users to view and manage their block list + - Hide blocked users from search results and user lists + + + - Handle cases where block/unblock fails + - Refresh block list periodically + - Cache block status locally for quick checks + + + +--- + +## Next Steps + + + + Create and update users + + + Fetch and search users + + + Track online/offline status + + + Send and receive messages + + diff --git a/sdk/javascript/call-logs.mdx b/sdk/javascript/call-logs.mdx index 74f2b87a..2a236880 100644 --- a/sdk/javascript/call-logs.mdx +++ b/sdk/javascript/call-logs.mdx @@ -1,96 +1,425 @@ --- title: "Call Logs" +description: "Retrieve and display call history including duration, participants, and recordings" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Fetch call logs +const loggedInUser = await CometChat.getLoggedinUser(); +const callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(30) + .setAuthToken(loggedInUser.getAuthToken()) + .setCallCategory("call") // "call" or "meet" + .build(); +const callLogs = await callLogRequest.fetchNext(); -## Overview +// Filter options +.setCallType("video") // "video" or "audio" +.setCallStatus("missed") // "ongoing", "busy", "rejected", "cancelled", "ended", "missed" +.setCallDirection("incoming") // "incoming" or "outgoing" +.setHasRecording(true) +.setUid("user_uid") +.setGuid("group_guid") + +// Get specific call details +const details = await CometChatCalls.getCallDetails(sessionId, authToken); +``` + -CometChat's Web Call SDK provides a comprehensive way to integrate call logs into your application, enhancing your user experience by allowing users to effortlessly keep track of their communication history. Call logs provide crucial information such as call duration, participants, and more. + +**Available via**: SDK | REST API | Dashboard + -This feature not only allows users to review their past interactions but it also serves as an effective tool to revisit important conversation details. With the flexibility of fetching call logs, filtering them according to specific parameters, and obtaining detailed information of individual calls, application developers can use this feature to build a more robust and interactive communication framework. +Access comprehensive call history to display past calls, track communication patterns, and retrieve call recordings. -In the following sections, we will guide you through the process of working with call logs, offering a deeper insight into how to optimally use this feature in your Web application. +## Overview + +Call logs provide detailed information about past calls including: +- Call duration and timestamps +- Participants involved +- Call type (audio/video) +- Call status (completed, missed, rejected) +- Recording availability ## Fetching Call Logs -To fetch all call logs in your 23b application, you should use the `CallLogRequestBuilder`, This builder allows you to customize the call logs fetching process according to your needs. +Use `CallLogRequestBuilder` to fetch call logs with various filters: + + ```javascript -let callLogRequestBuilder = new CometChatCalls.CallLogRequestBuilder() - .setLimit(30) - .setAuthToken(loggedInUser.getAuthToken()) - .setCallCategory("call") - .build() -``` - -`CallLogRequestBuilder` has the following settings available. - -| Setting | Description | -| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | -| `setLimit(limit: number)` | Specifies the number of call logs to fetch. | -| `setCallType(callType: 'video' or 'audio')` | Sets the type of calls to fetch (call or meet). | -| `setCallStatus(callStatus: 'ongoing' or 'busy' or 'rejected' or 'cancelled' or 'ended' or 'missed')` | Sets the status of calls to fetch (initiated, ongoing, etc.) | -| `setHasRecording(hasRecording: boolean)` | Sets whether to fetch calls that have recordings. | -| `setCallCategory(callCategory: 'call' or 'meet')` | Sets the category of calls to fetch (call or meet). | -| `setCallDirection(callDirection: 'incoming' or 'outgoing')` | Sets the direction of calls to fetch (incoming or outgoing) | -| `setUid(uid: string)` | Sets the UID of the user whose call logs to fetch. | -| `setGuid(guid: string)` | Sets the GUID of the user whose call logs to fetch. | -| `setAuthToken(authToken: string)` | Sets the Auth token of the logged-in user. | +const loggedInUser = await CometChat.getLoggedinUser(); -### Fetch Next +const callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(30) + .setAuthToken(loggedInUser.getAuthToken()) + .setCallCategory("call") + .build(); -The**`fetchNext()`**method retrieves the next set of call logs. +callLogRequest.fetchNext().then( + (callLogs) => { + console.log("Call logs:", callLogs); + }, + (error) => { + console.log("Failed to fetch call logs:", error); + } +); +``` + + +```typescript +const loggedInUser = await CometChat.getLoggedinUser(); +const callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(30) + .setAuthToken(loggedInUser.getAuthToken()) + .setCallCategory("call") + .build(); + +callLogRequest.fetchNext().then( + (callLogs: any[]) => { + console.log("Call logs:", callLogs); + }, + (error: any) => { + console.log("Failed to fetch call logs:", error); + } +); +``` + + ```javascript -let callLogRequestBuilder = new CometChatCalls.CallLogRequestBuilder() - .setLimit(30) - .setAuthToken(loggedInUser.getAuthToken()) - .setCallCategory("call") - .build() +const fetchCallLogs = async () => { + try { + const loggedInUser = await CometChat.getLoggedinUser(); -callLogRequestBuilder.fetchNext() - .then(callLogHistory => { - console.log(callLogHistory); - }) - .catch(err => { - console.log(err); - }); + const callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(30) + .setAuthToken(loggedInUser.getAuthToken()) + .setCallCategory("call") + .build(); + + const callLogs = await callLogRequest.fetchNext(); + console.log("Call logs:", callLogs); + } catch (error) { + console.log("Failed to fetch call logs:", error); + } +}; ``` + + -### Fetch Previous +## Builder Options -The**`fetchPrevious()`**method retrieves the previous set of call logs. +| Method | Description | +|--------|-------------| +| `setLimit(number)` | Number of call logs to fetch per request | +| `setAuthToken(string)` | Auth token of the logged-in user (required) | +| `setCallCategory(string)` | Filter by category: `"call"` or `"meet"` | +| `setCallType(string)` | Filter by type: `"video"` or `"audio"` | +| `setCallStatus(string)` | Filter by status: `"ongoing"`, `"busy"`, `"rejected"`, `"cancelled"`, `"ended"`, `"missed"` | +| `setCallDirection(string)` | Filter by direction: `"incoming"` or `"outgoing"` | +| `setHasRecording(boolean)` | Filter calls that have recordings | +| `setUid(string)` | Filter by specific user UID | +| `setGuid(string)` | Filter by specific group GUID | +### Filter Examples + + + +```javascript +const callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(30) + .setAuthToken(authToken) + .setCallStatus("missed") + .build(); +``` + + ```javascript -let callLogRequestBuilder = new CometChatCalls.CallLogRequestBuilder() - .setLimit(30) - .setAuthToken(loggedInUser.getAuthToken()) - .setCallCategory("call") - .build() +const callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(30) + .setAuthToken(authToken) + .setCallType("video") + .build(); +``` + + +```javascript +const callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(30) + .setAuthToken(authToken) + .setHasRecording(true) + .build(); +``` + + +```javascript +const callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(30) + .setAuthToken(authToken) + .setUid("user_123") + .build(); +``` + + + +## Pagination + +### Fetch Next + +Retrieve the next batch of call logs: -callLogRequestBuilder.fetchPrevious() - .then(callLogHistory => { - console.log(callLogHistory); - }) - .catch(err => { - console.log(err); - }); + + +```javascript +callLogRequest.fetchNext().then( + (callLogs) => { + console.log("Next batch:", callLogs); + // Append to existing list + }, + (error) => { + console.log("Error:", error); + } +); +``` + + +```typescript +callLogRequest.fetchNext().then( + (callLogs: any[]) => { + console.log("Next batch:", callLogs); + }, + (error: any) => { + console.log("Error:", error); + } +); ``` + + + +### Fetch Previous + +Retrieve the previous batch of call logs: + + + +```javascript +callLogRequest.fetchPrevious().then( + (callLogs) => { + console.log("Previous batch:", callLogs); + // Prepend to existing list + }, + (error) => { + console.log("Error:", error); + } +); +``` + + +```typescript +callLogRequest.fetchPrevious().then( + (callLogs: any[]) => { + console.log("Previous batch:", callLogs); + }, + (error: any) => { + console.log("Error:", error); + } +); +``` + + ## Get Call Details -To retrieve the specific details of a call, use the**`getCallDetails()`**method. This method requires the Auth token of the logged-in user and the session ID along with a callback listener. +Retrieve detailed information about a specific call session: + + + +```javascript +const sessionId = "SESSION_ID"; +const authToken = loggedInUser.getAuthToken(); + +CometChatCalls.getCallDetails(sessionId, authToken).then( + (callLogs) => { + console.log("Call details:", callLogs); + // Access participants, duration, recordings, etc. + }, + (error) => { + console.log("Failed to get call details:", error); + } +); +``` + + +```typescript +const sessionId: string = "SESSION_ID"; +const authToken: string = loggedInUser.getAuthToken(); + +CometChatCalls.getCallDetails(sessionId, authToken).then( + (callLogs: any[]) => { + console.log("Call details:", callLogs); + }, + (error: any) => { + console.log("Failed to get call details:", error); + } +); +``` + + +```javascript +const getCallDetails = async () => { + try { + const loggedInUser = await CometChat.getLoggedinUser(); + const sessionId = "SESSION_ID"; + const authToken = loggedInUser.getAuthToken(); + + const callDetails = await CometChatCalls.getCallDetails(sessionId, authToken); + console.log("Call details:", callDetails); + } catch (error) { + console.log("Failed to get call details:", error); + } +}; +``` + + + +## Call Log Properties +Each call log object contains: + +| Property | Description | +|----------|-------------| +| `sessionId` | Unique identifier for the call session | +| `initiator` | User who initiated the call | +| `receiver` | User or group that received the call | +| `callType` | Type of call (`audio` or `video`) | +| `callStatus` | Final status of the call | +| `callDirection` | Direction (`incoming` or `outgoing`) | +| `startedAt` | Timestamp when call started | +| `endedAt` | Timestamp when call ended | +| `duration` | Call duration in seconds | +| `hasRecording` | Whether the call has a recording | +| `participants` | List of participants in the call | + +## Complete Example + + + ```javascript -var sessionID = "SESSION_ID"; -CometChatCalls.getCallDetails(sessionID, authToken) -.then((callLogs: Array) => { - console.log(callLogs); - }) - .catch(err => { - console.log(err); - }); +class CallLogManager { + constructor() { + this.callLogRequest = null; + this.callLogs = []; + } + + async initialize() { + const loggedInUser = await CometChat.getLoggedinUser(); + + this.callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(20) + .setAuthToken(loggedInUser.getAuthToken()) + .setCallCategory("call") + .build(); + } + + async loadMore() { + try { + const logs = await this.callLogRequest.fetchNext(); + this.callLogs = [...this.callLogs, ...logs]; + return logs; + } catch (error) { + console.error("Failed to load call logs:", error); + return []; + } + } + + async getCallDetails(sessionId) { + const loggedInUser = await CometChat.getLoggedinUser(); + try { + return await CometChatCalls.getCallDetails( + sessionId, + loggedInUser.getAuthToken() + ); + } catch (error) { + console.error("Failed to get call details:", error); + return null; + } + } + + formatDuration(seconds) { + const mins = Math.floor(seconds / 60); + const secs = seconds % 60; + return `${mins}:${secs.toString().padStart(2, "0")}`; + } +} + +// Usage +const callLogManager = new CallLogManager(); +await callLogManager.initialize(); +const logs = await callLogManager.loadMore(); ``` + + +```typescript +class CallLogManager { + private callLogRequest: any = null; + private callLogs: any[] = []; + + async initialize(): Promise { + const loggedInUser = await CometChat.getLoggedinUser(); + + this.callLogRequest = new CometChatCalls.CallLogRequestBuilder() + .setLimit(20) + .setAuthToken(loggedInUser.getAuthToken()) + .setCallCategory("call") + .build(); + } + + async loadMore(): Promise { + try { + const logs = await this.callLogRequest.fetchNext(); + this.callLogs = [...this.callLogs, ...logs]; + return logs; + } catch (error) { + console.error("Failed to load call logs:", error); + return []; + } + } + + async getCallDetails(sessionId: string): Promise { + const loggedInUser = await CometChat.getLoggedinUser(); + try { + return await CometChatCalls.getCallDetails( + sessionId, + loggedInUser.getAuthToken() + ); + } catch (error) { + console.error("Failed to get call details:", error); + return null; + } + } + + formatDuration(seconds: number): string { + const mins = Math.floor(seconds / 60); + const secs = seconds % 60; + return `${mins}:${secs.toString().padStart(2, "0")}`; + } +} +``` + + + +## Next Steps -Note: Replace**`"SESSION_ID"`**with the ID of the session you are interested in. + + + Record calls for playback and compliance + + + Implement complete calling with notifications + + diff --git a/sdk/javascript/calling-overview.mdx b/sdk/javascript/calling-overview.mdx index 18bc0ea6..d16f3cb5 100644 --- a/sdk/javascript/calling-overview.mdx +++ b/sdk/javascript/calling-overview.mdx @@ -1,98 +1,641 @@ --- title: "Calling" sidebarTitle: "Overview" +description: "Add voice and video calling to your JavaScript application" --- -## Overview +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** -CometChat provides voice and video calling capabilities for your web application. This guide helps you choose the right implementation approach based on your use case. +```javascript +// Install: npm install @cometchat/calls-sdk-javascript -## Prerequisites +// Initialize Calls SDK (after Chat SDK init) +const callSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(APP_ID) + .setRegion(REGION) + .build(); +await CometChatCalls.init(callSettings); + +// Initiate a call +const call = new CometChat.Call( + "receiver_uid", + CometChat.CALL_TYPE.VIDEO, // or AUDIO + CometChat.RECEIVER_TYPE.USER // or GROUP +); +const outgoingCall = await CometChat.initiateCall(call); + +// Accept incoming call +const acceptedCall = await CometChat.acceptCall(sessionId); + +// Reject/Cancel call +await CometChat.rejectCall(sessionId, CometChat.CALL_STATUS.REJECTED); -1. CometChat SDK installed and configured. See the [Setup](/sdk/javascript/setup) guide. -2. CometChat Calls SDK added to your project: +// End call +CometChatCalls.endSession(); +await CometChat.endCall(sessionId); -```bash -npm install @cometchat/calls-sdk-javascript +// Listen for calls +CometChat.addCallListener("CALL_LISTENER", new CometChat.CallListener({ + onIncomingCallReceived: (call) => { /* show incoming UI */ }, + onOutgoingCallAccepted: (call) => { /* start session */ }, + onOutgoingCallRejected: (call) => { /* hide call UI */ }, + onIncomingCallCancelled: (call) => { /* hide incoming UI */ } +})); ``` + -For detailed setup instructions, see the [Calls SDK Setup](/sdk/javascript/calling-setup) guide. +CometChat provides real-time voice and video calling capabilities for your web application. Build 1:1 calls, group calls, screen sharing, and more. -## Choose Your Implementation + +**Available via:** SDK | [UI Kits](/ui-kit/react/overview) + + +--- -CometChat offers three approaches to implement calling: +## How Calling Works + +CometChat calling uses two SDKs working together: + +```mermaid +graph LR + subgraph "Chat SDK" + A[Call Signaling] + B[Call Events] + C[Call Logs] + end + + subgraph "Calls SDK" + D[Media Handling] + E[Video/Audio Streams] + F[Screen Sharing] + end + + A --> D + B --> E +``` + +| SDK | Purpose | Required | +|-----|---------|----------| +| **Chat SDK** | Call signaling (initiate, accept, reject, end) | Yes | +| **Calls SDK** | Media handling (audio, video, screen share) | Yes | + + +The Chat SDK handles the "phone ringing" part, while the Calls SDK handles the actual audio/video streams. + + +--- + +## Prerequisites + + + + Complete the [Setup Guide](/sdk/javascript/setup-sdk) first. + + + + + ```bash + npm install @cometchat/calls-sdk-javascript + ``` + + + ```bash + yarn add @cometchat/calls-sdk-javascript + ``` + + + ```bash + pnpm add @cometchat/calls-sdk-javascript + ``` + + + ```html + + ``` + + + + + Initialize after the Chat SDK is ready: + + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; + import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + + // After CometChat.init() succeeds + const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(APP_ID) + .setRegion(REGION) + .build(); + + CometChatCalls.init(callAppSettings).then( + () => console.log("Calls SDK initialized"), + (error) => console.log("Calls SDK init failed:", error) + ); + ``` + + + +For detailed setup, see the [Calls SDK Setup Guide](/sdk/javascript/calling-setup). + +--- + +## Choose Your Implementation - - Complete calling flow with incoming/outgoing call UI, accept/reject functionality, and call notifications. + + **Complete calling experience** + + Incoming/outgoing call UI, accept/reject, push notifications. Best for most apps. - - Direct call session management. Use with Ringing flow or for custom call initiation logic. + + **Custom call initiation** + + Start calls directly without ringing. Good for scheduled calls or custom UI. - - Calls SDK only implementation without the Chat SDK dependency. + + **Calls SDK only** + + No Chat SDK dependency. Use your own auth system. -### Ringing +### Which Should I Use? + +| Use Case | Recommended Approach | +|----------|---------------------| +| Standard app with chat + calling | [Ringing Flow](/sdk/javascript/default-call) | +| Video conferencing / scheduled calls | [Direct Call](/sdk/javascript/direct-call) | +| Calling without chat features | [Standalone](/sdk/javascript/standalone-calling) | +| Custom call UI with own notifications | [Direct Call](/sdk/javascript/direct-call) | -Use this when you need a complete calling experience with: -- Incoming and outgoing call UI -- Call accept/reject/cancel functionality -- Call notifications via push notifications -- Integration with CometChat messaging +--- + +## Quick Start: Ringing Flow + +Here's a complete example of implementing voice/video calls with the ringing flow: + + + + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; + + // Initiate a video call to a user + async function startCall(receiverUID, callType = CometChat.CALL_TYPE.VIDEO) { + const call = new CometChat.Call( + receiverUID, + callType, + CometChat.RECEIVER_TYPE.USER + ); + + try { + const outgoingCall = await CometChat.initiateCall(call); + console.log("Call initiated:", outgoingCall); + // Show outgoing call UI + return outgoingCall; + } catch (error) { + console.error("Call initiation failed:", error); + throw error; + } + } + + // Start a video call + startCall("user123", CometChat.CALL_TYPE.VIDEO); -**Flow:** Initiate call → Receiver gets notified → Accept/Reject → Start session + // Start an audio call + startCall("user123", CometChat.CALL_TYPE.AUDIO); + ``` + + + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; -[Get started with Ringing →](/sdk/javascript/default-call) + // Listen for incoming calls + const listenerID = "CALL_LISTENER"; -### Call Session + CometChat.addCallListener( + listenerID, + new CometChat.CallListener({ + onIncomingCallReceived: (call) => { + console.log("Incoming call from:", call.getSender().getName()); + // Show incoming call UI with accept/reject buttons + showIncomingCallUI(call); + }, + onOutgoingCallAccepted: (call) => { + console.log("Call accepted, starting session..."); + // Start the call session + startCallSession(call); + }, + onOutgoingCallRejected: (call) => { + console.log("Call rejected"); + // Hide call UI + }, + onIncomingCallCancelled: (call) => { + console.log("Incoming call cancelled"); + // Hide incoming call UI + }, + onCallEndedMessageReceived: (call) => { + console.log("Call ended"); + // Clean up call UI + } + }) + ); + ``` + + + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; -Use this when you need to: -- Start a call session after the Ringing flow completes -- Implement custom call initiation logic with your own UI -- Join participants to a shared session using a session ID + // Accept an incoming call + async function acceptCall(call) { + try { + const acceptedCall = await CometChat.acceptCall(call.getSessionId()); + console.log("Call accepted:", acceptedCall); + // Start the call session + startCallSession(acceptedCall); + } catch (error) { + console.error("Accept failed:", error); + } + } -**Flow:** Generate token → Start session → Manage call → End session + // Reject an incoming call + async function rejectCall(call, status = CometChat.CALL_STATUS.REJECTED) { + try { + await CometChat.rejectCall(call.getSessionId(), status); + console.log("Call rejected"); + } catch (error) { + console.error("Reject failed:", error); + } + } -[Get started with Call Session →](/sdk/javascript/direct-call) + // Cancel an outgoing call + async function cancelCall(call) { + try { + await CometChat.rejectCall( + call.getSessionId(), + CometChat.CALL_STATUS.CANCELLED + ); + console.log("Call cancelled"); + } catch (error) { + console.error("Cancel failed:", error); + } + } + ``` + + + ```javascript + import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + + // Start the actual call session + async function startCallSession(call) { + // Generate call token + const sessionId = call.getSessionId(); + const authToken = await getCallToken(sessionId); // See below + + const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIsAudioOnlyCall(call.getType() === "audio") + .setCallListener( + new CometChatCalls.OngoingCallListener({ + onCallEnded: () => { + console.log("Call ended"); + // Clean up UI + }, + onCallEndButtonPressed: () => { + console.log("End button pressed"); + endCall(sessionId); + }, + onUserJoined: (user) => { + console.log("User joined:", user.getName()); + }, + onUserLeft: (user) => { + console.log("User left:", user.getName()); + }, + onError: (error) => { + console.error("Call error:", error); + } + }) + ) + .build(); + + // Start the call in a container element + CometChatCalls.startSession( + authToken, + callSettings, + document.getElementById("call-container") + ); + } + + // Generate call token + async function getCallToken(sessionId) { + const loggedInUser = await CometChat.getLoggedinUser(); + const authToken = loggedInUser.getAuthToken(); + + return CometChatCalls.generateToken(sessionId, authToken); + } + ``` + + + +--- -### Standalone Calling +## Call Types + +| Type | Constant | Description | +|------|----------|-------------| +| Audio | `CometChat.CALL_TYPE.AUDIO` | Voice-only call | +| Video | `CometChat.CALL_TYPE.VIDEO` | Video call with camera | + +| Receiver Type | Constant | Description | +|---------------|----------|-------------| +| User | `CometChat.RECEIVER_TYPE.USER` | 1:1 call | +| Group | `CometChat.RECEIVER_TYPE.GROUP` | Group call | + +--- + +## Group Calls + +Initiate a call to a group: + +```javascript +const groupCall = new CometChat.Call( + "group-guid", + CometChat.CALL_TYPE.VIDEO, + CometChat.RECEIVER_TYPE.GROUP +); + +CometChat.initiateCall(groupCall).then( + (call) => console.log("Group call initiated:", call), + (error) => console.log("Failed:", error) +); +``` + + +In group calls, all online members receive the incoming call notification. The call continues as long as at least one participant remains. + + +--- -Use this when you want: -- Calling functionality without the Chat SDK -- Your own user authentication system -- Minimal SDK footprint +## Call Status Constants -**Flow:** Get auth token via REST API → Generate call token → Start session +| Status | Constant | Description | +|--------|----------|-------------| +| Initiated | `CometChat.CALL_STATUS.INITIATED` | Call started, waiting for response | +| Ongoing | `CometChat.CALL_STATUS.ONGOING` | Call in progress | +| Unanswered | `CometChat.CALL_STATUS.UNANSWERED` | No answer (timeout) | +| Rejected | `CometChat.CALL_STATUS.REJECTED` | Receiver rejected | +| Busy | `CometChat.CALL_STATUS.BUSY` | Receiver is on another call | +| Cancelled | `CometChat.CALL_STATUS.CANCELLED` | Caller cancelled | +| Ended | `CometChat.CALL_STATUS.ENDED` | Call ended normally | -[Get started with Standalone Calling →](/sdk/javascript/standalone-calling) +--- ## Features + + Share your screen or application windows during calls. + - Record audio and video calls for playback, compliance, or archival purposes. + Record calls for playback, compliance, or training. - Apply blur or custom image backgrounds during video calls. + Blur or replace backgrounds during video calls. - - Share your screen or specific application windows during calls. - - - Customize the video call UI layout, participant tiles, and visual appearance. + + Customize video layout, tiles, and appearance. - Style the calling UI with custom CSS to match your application's design. + Style the calling UI to match your app. - Enable presentation capabilities with spotlight on the active speaker. + Spotlight the active speaker in group calls. - Retrieve and display call history including duration, participants, and status. + Retrieve call history with duration and status. - Configure automatic call termination when participants are inactive. + Auto-end calls when participants are inactive. + + + +--- + +## Call Listener Events + +| Event | Description | +|-------|-------------| +| `onIncomingCallReceived` | Someone is calling you | +| `onOutgoingCallAccepted` | Your call was accepted | +| `onOutgoingCallRejected` | Your call was rejected | +| `onIncomingCallCancelled` | Caller cancelled before you answered | +| `onCallEndedMessageReceived` | Call ended | + +```javascript +CometChat.addCallListener( + "CALL_LISTENER", + new CometChat.CallListener({ + onIncomingCallReceived: (call) => { + // Show incoming call UI + }, + onOutgoingCallAccepted: (call) => { + // Start call session + }, + onOutgoingCallRejected: (call) => { + // Show "call rejected" message + }, + onIncomingCallCancelled: (call) => { + // Hide incoming call UI + }, + onCallEndedMessageReceived: (call) => { + // Clean up call UI + } + }) +); +``` + +--- + +## End a Call + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +async function endCall(sessionId) { + try { + // End the call session + CometChatCalls.endSession(); + + // Notify CometChat + await CometChat.endCall(sessionId); + console.log("Call ended successfully"); + } catch (error) { + console.error("End call failed:", error); + } +} +``` + +--- + +## React Implementation Example + +```jsx +import { useEffect, useState, useCallback } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +export function useCall() { + const [incomingCall, setIncomingCall] = useState(null); + const [activeCall, setActiveCall] = useState(null); + + useEffect(() => { + const listenerID = "CALL_LISTENER"; + + CometChat.addCallListener( + listenerID, + new CometChat.CallListener({ + onIncomingCallReceived: (call) => { + setIncomingCall(call); + }, + onOutgoingCallAccepted: (call) => { + setActiveCall(call); + setIncomingCall(null); + }, + onOutgoingCallRejected: () => { + setActiveCall(null); + }, + onIncomingCallCancelled: () => { + setIncomingCall(null); + }, + onCallEndedMessageReceived: () => { + setActiveCall(null); + setIncomingCall(null); + } + }) + ); + + return () => { + CometChat.removeCallListener(listenerID); + }; + }, []); + + const initiateCall = useCallback(async (receiverUID, callType) => { + const call = new CometChat.Call( + receiverUID, + callType, + CometChat.RECEIVER_TYPE.USER + ); + const outgoingCall = await CometChat.initiateCall(call); + setActiveCall(outgoingCall); + return outgoingCall; + }, []); + + const acceptCall = useCallback(async () => { + if (!incomingCall) return; + const call = await CometChat.acceptCall(incomingCall.getSessionId()); + setActiveCall(call); + setIncomingCall(null); + return call; + }, [incomingCall]); + + const rejectCall = useCallback(async () => { + if (!incomingCall) return; + await CometChat.rejectCall( + incomingCall.getSessionId(), + CometChat.CALL_STATUS.REJECTED + ); + setIncomingCall(null); + }, [incomingCall]); + + const endCall = useCallback(async () => { + if (!activeCall) return; + CometChatCalls.endSession(); + await CometChat.endCall(activeCall.getSessionId()); + setActiveCall(null); + }, [activeCall]); + + return { + incomingCall, + activeCall, + initiateCall, + acceptCall, + rejectCall, + endCall + }; +} +``` + +--- + +## Best Practices + + + + Request camera and microphone permissions before initiating calls. Handle permission denied gracefully. + + ```javascript + async function checkPermissions() { + try { + await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); + return true; + } catch (error) { + console.error("Permission denied:", error); + return false; + } + } + ``` + + + Always remove call listeners when components unmount to prevent memory leaks and duplicate events. + + + Implement reconnection logic and show appropriate UI when network quality degrades. + + + Test calling on different browsers and devices. WebRTC behavior can vary. + + + +--- + +## Troubleshooting + + + + - Verify both Chat SDK and Calls SDK are initialized + - Check that both users are logged in + - Ensure call listeners are registered before initiating calls + + + - Check browser permissions for camera/microphone + - Verify the call type matches expected media (audio vs video) + - Test with `navigator.mediaDevices.getUserMedia()` directly + + + - Ensure `startSession()` is called after call is accepted + - Verify the auth token is valid + - Check for errors in the call listener + + + +--- + +## Next Steps + + + + Implement complete calling with incoming/outgoing UI + + + Start calls without the ringing flow + + + Detailed Calls SDK configuration + + + Record calls for playback diff --git a/sdk/javascript/calling-setup.mdx b/sdk/javascript/calling-setup.mdx index 7cd07247..c74bbc6c 100644 --- a/sdk/javascript/calling-setup.mdx +++ b/sdk/javascript/calling-setup.mdx @@ -1,117 +1,281 @@ --- -title: "Setup" +title: "Calls SDK Setup" +sidebarTitle: "Setup" +description: "Install and initialize the CometChat Calls SDK for voice and video calling" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Install: npm install @cometchat/calls-sdk-javascript -## Get your Application Keys +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +// Initialize Calls SDK (after Chat SDK init) +const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(APP_ID) + .setRegion(REGION) + .build(); +await CometChatCalls.init(callAppSettings); + +// For dedicated deployments, add: .setHost("https://your-custom-url.cometchat.io") +``` + -[Signup for CometChat](https://app.cometchat.com) and then: +Set up the CometChat Calls SDK to add voice and video calling capabilities to your web application. -1. Create a new app -2. Head over to the **Credentials** section and note the **App ID, Auth Key** & **Region** +## Prerequisites -## Add the CometChatCalls Dependency +Before you begin: +1. [Create a CometChat account](https://app.cometchat.com) and app +2. Note your **App ID**, **Auth Key**, and **Region** from the Dashboard credentials section +3. Complete the [Chat SDK Setup](/sdk/javascript/setup-sdk) (unless using [Standalone Calling](/sdk/javascript/standalone-calling)) -Install the package as NPM module: +## Installation ```bash npm install @cometchat/calls-sdk-javascript ``` - - ```bash yarn add @cometchat/calls-sdk-javascript ``` - - + +```bash +pnpm add @cometchat/calls-sdk-javascript +``` + -Then, import the `CometChatCalls` class wherever you want to use `CometChatCalls`. +## Import + +Import the `CometChatCalls` class in your application: -```js +```javascript import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; ``` - - ```typescript import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; ``` - - -### Initialize CometChatCalls +## Initialize -The `init()` method initialises the settings required for `CometChatCalls`. The `init()` method takes a single paramater, that is the instance of `CallAppSettings` class. - -The `CallAppSettingsBuilder` class allows you to configure three settings: - -1. **appID:** You CometChat App ID -2. **region**: The region where your app was created -3. **host:** This method takes the client URL as input and uses this client URL instead of the default client URL. This can be used in case of dedicated deployment of CometChat. - -You need to call init() before calling any other method from `CometChatCalls`. We suggest you call the init() method on app startup, preferably in the index.js file. +Initialize the Calls SDK before using any calling features. Call `init()` on app startup, typically in your main entry file. -```js -let appID = "APP_ID"; -let region = "REGION"; +```javascript +const appId = "YOUR_APP_ID"; +const region = "YOUR_REGION"; // e.g., "us", "eu" -const callAppSetting = new CometChatCalls.CallAppSettingsBuilder() - .setAppId(appID) +const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(appId) .setRegion(region) .build(); -CometChatCalls.init(callAppSetting).then( +CometChatCalls.init(callAppSettings).then( () => { - console.log("CometChatCalls initialization completed successfully"); + console.log("CometChatCalls initialized successfully"); }, (error) => { - console.log("CometChatCalls initialization failed with error:", error); + console.log("CometChatCalls initialization failed:", error); } ); ``` - - ```typescript -let appID = "APP_ID"; -let region = "REGION"; +const appId: string = "YOUR_APP_ID"; +const region: string = "YOUR_REGION"; -const callAppSetting = new CometChatCalls.CallAppSettingsBuilder() - .setAppId(appID) +const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(appId) .setRegion(region) .build(); -CometChatCalls.init(callAppSetting).then( - () => { - console.log("CometChatCalls initialization completed successfully"); +CometChatCalls.init(callAppSettings).then( + (): void => { + console.log("CometChatCalls initialized successfully"); }, - (error) => { - console.log("CometChatCalls initialization failed with error:", error); + (error: any): void => { + console.log("CometChatCalls initialization failed:", error); } ); ``` - + +```javascript +const initCallsSDK = async () => { + try { + const appId = "YOUR_APP_ID"; + const region = "YOUR_REGION"; // e.g., "us", "eu" + + const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(appId) + .setRegion(region) + .build(); + + await CometChatCalls.init(callAppSettings); + console.log("CometChatCalls initialized successfully"); + } catch (error) { + console.log("CometChatCalls initialization failed:", error); + } +}; +``` + + + + +Replace `YOUR_APP_ID` and `YOUR_REGION` with your actual CometChat credentials from the Dashboard. + + +## Configuration Options + +The `CallAppSettingsBuilder` provides these configuration methods: + +| Method | Description | Required | +|--------|-------------|----------| +| `setAppId(appId)` | Your CometChat App ID | Yes | +| `setRegion(region)` | Region where your app was created (`us`, `eu`, etc.) | Yes | +| `setHost(host)` | Custom client URL for dedicated deployments | No | +### Dedicated Deployment + +For dedicated CometChat deployments, use `setHost()` to specify your custom URL: + + + +```javascript +const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(appId) + .setRegion(region) + .setHost("https://your-custom-url.cometchat.io") + .build(); +``` + + +```typescript +const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(appId) + .setRegion(region) + .setHost("https://your-custom-url.cometchat.io") + .build(); +``` + -Make sure you replace the `APP_ID` with your CometChat **App ID** and `REGION` with your **App Region** in the above code. +## Complete Setup Example + +Here's a complete initialization flow with both Chat and Calls SDKs: + + + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +const appId = "YOUR_APP_ID"; +const region = "YOUR_REGION"; + +async function initializeCometChat() { + try { + // Initialize Chat SDK + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init(appId, appSettings); + console.log("Chat SDK initialized"); + + // Initialize Calls SDK + const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(appId) + .setRegion(region) + .build(); + + await CometChatCalls.init(callAppSettings); + console.log("Calls SDK initialized"); + + return true; + } catch (error) { + console.error("Initialization failed:", error); + return false; + } +} + +// Call on app startup +initializeCometChat(); +``` + + +```typescript +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +const appId: string = "YOUR_APP_ID"; +const region: string = "YOUR_REGION"; + +async function initializeCometChat(): Promise { + try { + // Initialize Chat SDK + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init(appId, appSettings); + console.log("Chat SDK initialized"); + + // Initialize Calls SDK + const callAppSettings = new CometChatCalls.CallAppSettingsBuilder() + .setAppId(appId) + .setRegion(region) + .build(); + + await CometChatCalls.init(callAppSettings); + console.log("Calls SDK initialized"); + + return true; + } catch (error) { + console.error("Initialization failed:", error); + return false; + } +} + +// Call on app startup +initializeCometChat(); +``` + + -| Parameter | Description | -| ----------------- | ---------------------------------------- | -| `callAppSettings` | An object of the `CallAppSettings` class | +## Next Steps + + + + Complete calling flow with incoming/outgoing UI + + + Direct call session management + + + Calls without Chat SDK dependency + + + Choose the right implementation approach + + diff --git a/sdk/javascript/connection-status.mdx b/sdk/javascript/connection-status.mdx index 7c67128b..cef072fe 100644 --- a/sdk/javascript/connection-status.mdx +++ b/sdk/javascript/connection-status.mdx @@ -1,95 +1,209 @@ --- title: "Connection Status" +sidebarTitle: "Connection Status" +description: "Monitor WebSocket connection status in real-time" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Get current connection status +const status = CometChat.getConnectionStatus(); +// Returns: "connecting", "connected", or "disconnected" + +// Listen for connection changes +CometChat.addConnectionListener("CONNECTION_LISTENER", new CometChat.ConnectionListener({ + onConnected: () => console.log("Connected"), + inConnecting: () => console.log("Connecting..."), + onDisconnected: () => console.log("Disconnected") +})); + +// Remove listener +CometChat.removeConnectionListener("CONNECTION_LISTENER"); + +// SDK auto-reconnects when connection is lost +``` + + +Track the connection status to CometChat servers to handle network changes gracefully. + + +**Availability**: SDK + +The SDK automatically reconnects when the connection is lost. + -CometChat SDK provides you with a mechanism to get real-time status of the connection to CometChat web-socket servers. +--- -Connection Status provides you with the below 3 methods to get the status of the connection to CometChat web-socket servers: +## Connection States -| Delegate Method | Information | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| connecting | This method is triggered when CometChat SDK is trying to establish a connection to the web-socket server. | -| connected | This method is called when CometChat SDK has successfully established a connection and now is connected. | -| disconnected | This method is called when the CometChat SDK gets disconnected due to any issue while maintaining the connection like network fluctuations, etc. | +| State | Description | +|-------|-------------| +| `connecting` | SDK is attempting to connect | +| `connected` | Connection established and active | +| `disconnected` | Connection lost (SDK will auto-reconnect) | -Once the connection is broken, the disconnected callback is triggered, the SDK automatically tries to establish the connection again, thus going into the connecting state and triggering the `connecting` method. Once the attempt to connect is successful, the `connected` method is triggered thus letting the developer know that the connection is established and is active. +--- -To receive real-time connection status, you need to register `ConnectionListener` wherever you wish to receive the real-time status. You can use the `addConnectionListener()` method to do so. +## Listen for Connection Changes - + ```javascript -let listenerID = "UNIQUE_LISTENER_ID"; +const listenerID = "CONNECTION_LISTENER"; + CometChat.addConnectionListener( listenerID, new CometChat.ConnectionListener({ onConnected: () => { - console.log("ConnectionListener => On Connected"); + console.log("Connected to CometChat"); + // Resume normal operations }, inConnecting: () => { - console.log("ConnectionListener => In connecting"); + console.log("Connecting..."); + // Show connecting indicator }, onDisconnected: () => { - console.log("ConnectionListener => On Disconnected"); - }, + console.log("Disconnected from CometChat"); + // Show offline indicator + } }) ); ``` - - ```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +const listenerID: string = "CONNECTION_LISTENER"; + CometChat.addConnectionListener( listenerID, new CometChat.ConnectionListener({ onConnected: () => { - console.log("ConnectionListener => On Connected"); + console.log("Connected to CometChat"); }, inConnecting: () => { - console.log("ConnectionListener => In connecting"); + console.log("Connecting..."); }, onDisconnected: () => { - console.log("ConnectionListener => On Disconnected"); - }, + console.log("Disconnected from CometChat"); + } }) ); ``` - - - +### Remove Listener -We recommend you to add the Connection Listener in your method on app startup, preferably in the index.js file. Once you have successfully initialized CometChat. +```javascript +CometChat.removeConnectionListener("CONNECTION_LISTENER"); +``` - +--- -You can also get the current connection status by using `getConnectionStatus` property provided by CometChat SDK +## Get Current Status + +Check the current connection status at any time: - - ```javascript -var connectionStatus = CometChat.getConnectionStatus(); +const status = CometChat.getConnectionStatus(); +console.log("Current status:", status); +// Returns: "connecting", "connected", or "disconnected" ``` - +--- - -```typescript -var connectionStatus: string = CometChat.getConnectionStatus(); +## Implementation Example + +```javascript +class ConnectionManager { + constructor() { + this.status = "disconnected"; + this.listeners = []; + } + + initialize() { + CometChat.addConnectionListener( + "connection-manager", + new CometChat.ConnectionListener({ + onConnected: () => this.handleConnected(), + inConnecting: () => this.handleConnecting(), + onDisconnected: () => this.handleDisconnected() + }) + ); + } + + handleConnected() { + this.status = "connected"; + this.notifyListeners(); + // Hide offline banner, enable send button + } + + handleConnecting() { + this.status = "connecting"; + this.notifyListeners(); + // Show "Reconnecting..." indicator + } + + handleDisconnected() { + this.status = "disconnected"; + this.notifyListeners(); + // Show offline banner, disable send button + } + + onStatusChange(callback) { + this.listeners.push(callback); + } + + notifyListeners() { + this.listeners.forEach((cb) => cb(this.status)); + } + + isConnected() { + return this.status === "connected"; + } + + cleanup() { + CometChat.removeConnectionListener("connection-manager"); + } +} + +// Usage +const connectionManager = new ConnectionManager(); +connectionManager.initialize(); + +connectionManager.onStatusChange((status) => { + updateConnectionUI(status); +}); ``` - +--- - +## Best Practices + + + + Add the connection listener after initializing CometChat, preferably in your app's entry point. + + + Show clear visual feedback when disconnected (e.g., banner, disabled send button). + + + Consider queuing messages when disconnected and sending them when reconnected. + + + +--- -The `CometChat.getConnectionStatus` method will return either of the below 3 values: +## Next Steps -1. connecting -2. connected -3. disconnected + + + Manual WebSocket control + + + SDK configuration options + + diff --git a/sdk/javascript/create-group.mdx b/sdk/javascript/create-group.mdx index 29eed3de..457e02ce 100644 --- a/sdk/javascript/create-group.mdx +++ b/sdk/javascript/create-group.mdx @@ -1,173 +1,316 @@ --- -title: "Create A Group" +title: "Create a Group" +sidebarTitle: "Create Group" +description: "Create public, private, or password-protected groups" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Create a public group +const group = new CometChat.Group("guid", "Group Name", CometChat.GROUP_TYPE.PUBLIC); +const createdGroup = await CometChat.createGroup(group); + +// Create a password-protected group +const group = new CometChat.Group("guid", "Name", CometChat.GROUP_TYPE.PASSWORD, "password"); +await CometChat.createGroup(group); + +// Create a private group (invite-only) +const group = new CometChat.Group("guid", "Name", CometChat.GROUP_TYPE.PRIVATE); +await CometChat.createGroup(group); + +// Create group with initial members +const members = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.ADMIN), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT) +]; +await CometChat.createGroupWithMembers(group, members, []); -## Create a Group - -*In other words, as a logged-in user, how do I create a public, private or password-protected group?* +// Group types: PUBLIC | PASSWORD | PRIVATE +// Member scopes: ADMIN | MODERATOR | PARTICIPANT +``` + -You can create a group using `createGroup()` method. This method takes a `Group` object as input. +Create groups to enable multi-user conversations. Groups can be public (anyone can join), password-protected, or private (invite-only). -To create an object of `Group` class, you can use either of the below two constructors: + +**Availability**: SDK, API, UI Kits + -1. `new Group(String GUID, String name, String groupType, String password)` -2. `new Group(String GUID, String name, String groupType, String password, String icon, String description)` +--- -The `groupType` needs to be either of the below 3 values: +## Group Types -1.`CometChat.GROUP_TYPE.PUBLIC` +| Type | Description | +|------|-------------| +| `PUBLIC` | Anyone can join without approval | +| `PASSWORD` | Requires password to join | +| `PRIVATE` | Invite-only, not visible in group list | -2.`CometChat.GROUP_TYPE.PASSWORD` +--- -3.`CometChat.GROUP_TYPE.PRIVATE` +## Create a Group - + ```javascript -var GUID = "GUID"; -var groupName = "Hello Group!"; -var groupType = CometChat.GROUP_TYPE.PUBLIC; -var password = ""; +const GUID = "group-123"; +const groupName = "Team Chat"; +const groupType = CometChat.GROUP_TYPE.PUBLIC; -var group = new CometChat.Group(GUID, groupName, groupType, password); +const group = new CometChat.Group(GUID, groupName, groupType); CometChat.createGroup(group).then( - group => { - console.log("Group created successfully:", group); - }, error => { - console.log("Group creation failed with exception:", error); - } + (group) => console.log("Group created:", group), + (error) => console.log("Failed:", error) ); ``` - + +```javascript +const GUID = "group-123"; +const groupName = "Private Team"; +const groupType = CometChat.GROUP_TYPE.PASSWORD; +const password = "secret123"; - -```typescript -var GUID: string = "GUID"; -var groupName: string = "Hello Group!"; -var groupType: string = CometChat.GROUP_TYPE.PUBLIC; -var password: string = ""; - -var group: CometChat.Group = new CometChat.Group(GUID, groupName, groupType, password); +const group = new CometChat.Group(GUID, groupName, groupType, password); CometChat.createGroup(group).then( - (group: CometChat.Group) => { - console.log("Group created successfully:", group); - }, (error: CometChat.CometChatException) => { - console.log("Group creation failed with exception:", error); - } + (group) => console.log("Group created:", group), + (error) => console.log("Failed:", error) ); ``` - + +```javascript +const GUID = "group-123"; +const groupName = "Executive Team"; +const groupType = CometChat.GROUP_TYPE.PRIVATE; - +const group = new CometChat.Group(GUID, groupName, groupType); -The createGroup() method takes the following parameters: +CometChat.createGroup(group).then( + (group) => console.log("Group created:", group), + (error) => console.log("Failed:", error) +); +``` + + +```javascript +async function createGroup(guid, name, type, password = "") { + const group = new CometChat.Group(guid, name, type, password); + + try { + const createdGroup = await CometChat.createGroup(group); + console.log("Group created:", createdGroup.getName()); + return createdGroup; + } catch (error) { + console.error("Failed to create group:", error); + throw error; + } +} -| Parameter | Description | -| --------- | ---------------------------- | -| `group` | An instance of `Group` class | +// Create a public group +await createGroup("team-123", "Team Chat", CometChat.GROUP_TYPE.PUBLIC); -After successful creation of the group, you will receive an instance of `Group` class which contains all the information about the particular group. +// Create a password-protected group +await createGroup("vip-room", "VIP Room", CometChat.GROUP_TYPE.PASSWORD, "secret"); - +// Create a private group +await createGroup("exec-team", "Executive Team", CometChat.GROUP_TYPE.PRIVATE); +``` + + -GUID can be alphanumeric with underscore and hyphen. Spaces, punctuation and other special characters are not allowed. + +**GUID Requirements**: Alphanumeric characters, underscores, and hyphens only. No spaces, punctuation, or special characters. + - -## Add members while creating a group +--- -You can create a group and add members at the same time using the `createGroupWithMembers()` method. This method takes the `Group` Object, Array of `Group Member` Object to be added & Array of `UIDs` to be banned. +## Create with Full Properties -To create an object of `Group` class, you can use either of the below two constructors: +```javascript +const GUID = "group-123"; +const groupName = "Engineering Team"; +const groupType = CometChat.GROUP_TYPE.PUBLIC; +const password = ""; +const icon = "https://example.com/group-icon.png"; +const description = "Engineering team discussions"; + +const group = new CometChat.Group( + GUID, + groupName, + groupType, + password, + icon, + description +); -1. `new Group(String GUID, String name, String groupType, String password)` -2. `new Group(String GUID, String name, String groupType, String password, String icon, String description)` +// Set additional properties +group.setMetadata({ department: "Engineering", project: "Alpha" }); +group.setTags(["engineering", "development"]); -The `groupType` needs to be either of the below 3 values: +CometChat.createGroup(group).then( + (group) => console.log("Group created:", group), + (error) => console.log("Failed:", error) +); +``` -1. `CometChat.GROUP_TYPE.PUBLIC` -2. `CometChat.GROUP_TYPE.PASSWORD` -3. `CometChat.GROUP_TYPE.PRIVATE` +--- -To create an object of `Group Member` class, you can use the below constructor: +## Create Group with Members -* new CometChat.GroupMember(String UID, String scope) +Create a group and add members in a single operation: -```js -let GUID = "cometchat-guid-11"; -let UID = "cometchat-uid-1"; -let groupName = "Hello Group!"; -let groupType = CometChat.GROUP_TYPE.PUBLIC; - -let group = new CometChat.Group(GUID, groupName, groupType); -let members = [ -new CometChat.GroupMember(UID, CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT) +```javascript +const GUID = "group-123"; +const groupName = "Project Team"; +const groupType = CometChat.GROUP_TYPE.PUBLIC; + +const group = new CometChat.Group(GUID, groupName, groupType); + +// Members to add +const members = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.ADMIN), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.MODERATOR), + new CometChat.GroupMember("user3", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT) ]; -let banMembers = ["cometchat-uid-2"]; + +// Users to ban +const banMembers = ["user4", "user5"]; CometChat.createGroupWithMembers(group, members, banMembers).then( - response => { - console.log("Group created successfully", response); - }, error => { - console.log("Some error occured while creating group", error) - } + (response) => { + console.log("Group:", response.group); + console.log("Member results:", response.members); + // { user1: "success", user2: "success", user3: "success" } + }, + (error) => console.log("Failed:", error) ); ``` - - ```typescript -let GUID: string = "cometchat-guid-11"; -let UID: string = "cometchat-uid-1"; -let groupName: string = "Hello Group!"; -let groupType: string = CometChat.GROUP_TYPE.PUBLIC; - -let group: CometChat.Group = new CometChat.Group(GUID, groupName, groupType); -let members: Array = [ -new CometChat.GroupMember(UID, CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT) +const GUID: string = "group-123"; +const groupName: string = "Project Team"; +const groupType: string = CometChat.GROUP_TYPE.PUBLIC; + +const group: CometChat.Group = new CometChat.Group(GUID, groupName, groupType); + +const members: CometChat.GroupMember[] = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.ADMIN), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT) ]; -let banMembers: Array = ["cometchat-uid-2"]; + +const banMembers: string[] = ["user4"]; CometChat.createGroupWithMembers(group, members, banMembers).then( (response: Object) => { - console.log("Group created successfully", response); - }, (error: CometChat.CometChatException) => { - console.log("Some error occured while creating group", error) - } + console.log("Group created:", response); + }, + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - -This method returns an Object which has two keys: `group` & `members` . The group key has the Group Object which contains all the information of the group which is created. The members key has the `UID` of the users and the value will either be `success` or an `error` message describing why the operation to add/ban the user failed. - -## Group Class - -| Field | Editable | Information | -| ------------ | --------------------------------------------------------------- | ------------------------------------------------------------------------- | -| guid | Needs to be specified at group creation. Cannot be edited later | A unique identifier for a group | -| name | Yes | Name of the group | -| type | No | Type of the group: Can be 1. Public 2. Password 3. Private | -| password | No | Password for the group in case the group is of type password. | -| icon | Yes | An URL to group icon | -| description | Yes | Description about the group | -| owner | Yes | UID of the owner of the group. | -| metadata | Yes | Additional data for the group as JSON | -| createdAt | No | The unix timestamp of the time the group was created | -| updatedAt | No | The unix timestamp of the time the group was last updated | -| hasJoined | No | A boolean to determine if the logged in user is a member of the group. | -| joinedAt | No | The unix timestamp of the time the logged in user joined the group. | -| scope | Yes | Scope of the logged in user. Can be: 1. Admin 2. Moderator 3. Participant | -| membersCount | No | The number of members in the groups | -| tags | Yes | A list of tags to identify specific groups. | +### Member Scopes + +| Scope | Description | +|-------|-------------| +| `ADMIN` | Full control over group settings and members | +| `MODERATOR` | Can manage members but not group settings | +| `PARTICIPANT` | Regular member, can send/receive messages | + +--- + +## Group Properties Reference + +| Property | Editable | Description | +|----------|----------|-------------| +| `guid` | Create only | Unique identifier | +| `name` | Yes | Display name | +| `type` | No | PUBLIC, PASSWORD, or PRIVATE | +| `password` | No | Password for PASSWORD type groups | +| `icon` | Yes | URL to group icon | +| `description` | Yes | Group description | +| `owner` | Yes | UID of group owner | +| `metadata` | Yes | Custom JSON data | +| `createdAt` | No | Creation timestamp | +| `updatedAt` | No | Last update timestamp | +| `hasJoined` | No | If logged-in user is a member | +| `joinedAt` | No | When user joined | +| `scope` | Yes | User's scope in group | +| `membersCount` | No | Number of members | +| `tags` | Yes | Tags for categorization | + +--- + +## Real-Time Group Events + +Listen for group creation events: + +```javascript +const listenerID = "GROUP_LISTENER"; + +CometChat.addGroupListener( + listenerID, + new CometChat.GroupListener({ + onGroupMemberJoined: (message, joinedUser, joinedGroup) => { + console.log("User joined:", joinedUser.getName()); + }, + onGroupMemberLeft: (message, leftUser, leftGroup) => { + console.log("User left:", leftUser.getName()); + } + }) +); + +// Remove listener when done +CometChat.removeGroupListener(listenerID); +``` + +--- + +## Best Practices + + + + - Use meaningful GUIDs that relate to your app's data model + - Consider prefixing GUIDs by type (e.g., "team-123", "project-456") + - Keep GUIDs consistent with your backend identifiers + + + - Use PUBLIC for open communities + - Use PASSWORD for semi-private groups + - Use PRIVATE for invite-only groups (support teams, executive chats) + + + - Add the creator as ADMIN automatically + - Consider adding relevant users during creation to avoid multiple API calls + + + +--- + +## Next Steps + + + + Join existing groups + + + Modify group settings + + + Manage group members + + + Fetch group lists + + diff --git a/sdk/javascript/custom-css.mdx b/sdk/javascript/custom-css.mdx index 56698ccf..c0df2bda 100644 --- a/sdk/javascript/custom-css.mdx +++ b/sdk/javascript/custom-css.mdx @@ -1,135 +1,229 @@ --- title: "Custom CSS" +description: "Style the calling UI with custom CSS to match your application's design" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```css +/* Key CSS classes for call UI customization */ +.cc-main-container { } /* Outer container */ +.cc-video-container { } /* Video stream container */ +.cc-bottom-buttons-container { } /* Button bar */ +.cc-name-label { } /* Participant name */ + +/* Button classes */ +.cc-audio-icon-container { } /* Mute button */ +.cc-audio-icon-container-muted { } /* Muted state */ +.cc-video-icon-container { } /* Video button */ +.cc-end-call-icon-container { } /* End call button */ +``` + + +Customize the appearance of the call screen using CSS classes to match your application's branding and design system. + +## Overview + +CometChat's calling UI exposes CSS classes that you can override to customize colors, sizes, positions, and other visual properties. -Passing custom CSS allows you to personalize and enhance the user interface of the call screen. + +Only use CSS classes documented here. Using undocumented classes may cause unexpected UI issues in future updates. + ## Common CSS Classes -There are a few common classes used for different modes in the call screen +These classes are available across all call modes (Default, Tile, Spotlight): -1. **cc-main-container** - The outermost component of the calling component is represented by a white border in the screenshots above, indicating that it acts as a container for other components. +| Class | Description | +|-------|-------------| +| `.cc-main-container` | Outermost container wrapping the entire call UI | +| `.cc-bottom-buttons-container` | Container for action buttons at the bottom | +| `.cc-name-label` | Participant name label overlay | +| `.cc-video-container` | Individual video stream container | -2. **cc-bottom-buttons-container** - The container located at the very bottom of the interface houses various action buttons, such as the mute/unmute audio and video, end call, settings icon, and participants icon, among others. It is represented by the red border in above screenshot. +## Button Classes -3. **cc-name-label** - This class is passed in user name text container in all modes. It is represented by green border in the above screenshots. +### Container Classes -4. **cc-video-container** - This class is passed to the video container in all modes. It is represented by orange border in the above screenshots. +| Class | Description | +|-------|-------------| +| `.cc-bottom-buttons-container` | Container for all bottom buttons | +| `.cc-bottom-buttons-icon-container` | Individual button wrapper | -## Bottom Buttons +### Individual Button Classes -1. **cc-bottom-buttons-container** - This is the container of all the buttons in calling. -2. **cc-bottom-buttons-icon-container** - This is the div of every button in the button bar. +| Class | Description | +|-------|-------------| +| `.cc-audio-icon-container` | Mute/unmute audio button | +| `.cc-audio-icon-container-muted` | Audio button when muted | +| `.cc-video-icon-container` | Pause/resume video button | +| `.cc-video-icon-container-muted` | Video button when paused | +| `.cc-screen-share-icon-container` | Screen share button | +| `.cc-switch-video-icon-container` | Switch camera button | +| `.cc-end-call-icon-container` | End call button | -### Individual bottom buttons CSS classes +## Basic Example + + + +```css +/* Main container border */ +.cc-main-container { + border: 2px solid #333; + border-radius: 12px; +} -* `cc-audio-icon-container` -* `cc-audio-icon-container-muted` -* `cc-video-icon-container` -* `cc-video-icon-container-muted` -* `cc-screen-share-icon-container` -* `cc-switch-video-icon-container` -* `cc-end-call-icon-container` +/* Video container styling */ +.cc-video-container { + border-radius: 8px; + overflow: hidden; +} -### **Example** +/* Name label styling */ +.cc-name-label { + background-color: rgba(0, 0, 0, 0.6) !important; + border-radius: 4px; + padding: 4px 8px; +} + +/* Button container */ +.cc-bottom-buttons-container { + background-color: rgba(0, 0, 0, 0.8) !important; + border-radius: 12px; + padding: 12px 24px; +} +``` + + + +## Button Styling Example + +Customize button colors and states: ```css -.cc-end-call-icon-container { - background-color: green; +/* All buttons - base size */ +.cc-bottom-buttons-icon-container { + height: 48px !important; + width: 48px !important; + border-radius: 50% !important; } + +/* Audio button - active state */ .cc-audio-icon-container { - background-color: blue; -} -.cc-video-icon-container { - background-color: blue; + background-color: #0073ff !important; } + +/* Audio button - muted state */ .cc-audio-icon-container-muted { - background-color: orange; + background-color: #ff4444 !important; } -.cc-video-icon-container-muted { - background-color: orange; + +/* Video button - active state */ +.cc-video-icon-container { + background-color: #0073ff !important; } -.cc-switch-video-icon-container { - background-color: blue; + +/* Video button - muted state */ +.cc-video-icon-container-muted { + background-color: #ff4444 !important; } + +/* Screen share button */ .cc-screen-share-icon-container { - background-color: blue; -} -.cc-main-container { - border: 2px dotted white; -} -.cc-video-container { - border: 2px dotted orange; + background-color: #0073ff !important; } -.cc-bottom-buttons-container { - border: 2px dotted red; + +/* End call button - make it stand out */ +.cc-end-call-icon-container { + background-color: #ff0000 !important; + margin-left: 24px !important; } -.cc-name-label { - border: 2px dotted green; + +/* Button spacing */ +.cc-bottom-buttons.cc-bottom-buttons-container { + gap: 16px !important; } ``` - - -The above example results in the below output:- +## Mode-Specific Styling + +The call UI supports different layout modes. Here's how they look with custom styling: + +### Default Mode -**Mode: `DEFAULT`** +Grid layout showing all participants equally: -**Mode: `TILE`** +### Tile Mode + +Tiled layout with flexible arrangement: -**Mode: `SPOTLIGHT`** +### Spotlight Mode + +Focus on active speaker with thumbnails: +## Complete Branding Example + ```css +/* Brand colors */ +:root { + --brand-primary: #0073ff; + --brand-danger: #ff4444; + --brand-dark: rgba(0, 0, 0, 0.8); +} + +/* Button sizing */ .cc-bottom-buttons-icon-container { height: 50px !important; width: 50px !important; } -.cc-audio-icon-container { - background-color: #0073ff !important; - border-radius: 4px !important; -} - -.cc-video-icon-container { - background-color: #0073ff !important; +/* Active state buttons */ +.cc-audio-icon-container, +.cc-video-icon-container, +.cc-screen-share-icon-container { + background-color: var(--brand-primary) !important; border-radius: 4px !important; } -.cc-screen-share-icon-container { - background-color: #0073ff !important; - border-radius: 4px !important; +/* Muted state buttons */ +.cc-audio-icon-container-muted, +.cc-video-icon-container-muted { + background-color: orange !important; } +/* End call button */ .cc-end-call-icon-container { - background-color: #ab0090 !important; + background-color: var(--brand-danger) !important; border-radius: 4px !important; margin-left: 50px !important; } +/* Button container spacing */ .cc-bottom-buttons.cc-bottom-buttons-container { gap: 25px !important; } +/* Video placeholder pattern */ .side-bar-main-user-video video { background-color: black !important; background-image: repeating-conic-gradient( @@ -140,33 +234,52 @@ The above example results in the below output:- background-size: 20px 20px !important; } +/* Name label */ .cc-name-label { - background-color: #0073ff !important; + background-color: var(--brand-primary) !important; } +/* Other options spacing */ .bottom-buttons-other-options { gap: 20px !important; } ``` - - -The above example results in the below output:- +Result: -### Guidelines for Customizing the Grid Layout - -* **CSS Classes:** - - * Please ensure that you only apply CSS classes specified in this documentation. Introducing CSS classes not covered here may cause unexpected UI issues. - -* **Grid Container Resizing:** - - * Avoid resizing the grid container. Altering the grid container’s dimensions can negatively impact the grid layout, leading to undesirable visual distortions. - -By following these recommendations, you can maintain a stable and visually consistent grid layout. +## Best Practices + + + + CometChat's styles have specificity. Use `!important` only when necessary to override default styles. + + + + Avoid changing the grid container's dimensions as it can break the layout algorithm. + + + + Test your CSS changes in Default, Tile, and Spotlight modes to ensure consistency. + + + + Define brand colors as CSS variables for easier maintenance and consistency. + + + +## Next Steps + + + + Customize video container settings + + + Add blur or custom backgrounds + + diff --git a/sdk/javascript/default-call.mdx b/sdk/javascript/default-call.mdx index 180de4d7..a66cf750 100644 --- a/sdk/javascript/default-call.mdx +++ b/sdk/javascript/default-call.mdx @@ -2,6 +2,40 @@ title: "Ringing" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Initiate a call +const call = new CometChat.Call(receiverID, CometChat.CALL_TYPE.VIDEO, CometChat.RECEIVER_TYPE.USER); +const outgoingCall = await CometChat.initiateCall(call); + +// Listen for call events +CometChat.addCallListener("CALL_LISTENER", new CometChat.CallListener({ + onIncomingCallReceived: (call) => { /* show incoming UI */ }, + onOutgoingCallAccepted: (call) => { /* start session */ }, + onOutgoingCallRejected: (call) => { /* dismiss UI */ }, + onIncomingCallCancelled: (call) => { /* dismiss UI */ } +})); + +// Accept call +await CometChat.acceptCall(sessionId); + +// Reject call +await CometChat.rejectCall(sessionId, CometChat.CALL_STATUS.REJECTED); + +// Cancel outgoing call +await CometChat.rejectCall(sessionId, CometChat.CALL_STATUS.CANCELLED); + +// After accept: generate token and start session (see Call Session guide) +``` + + + +**Available via**: SDK | UI Kits + + ## Overview This section explains how to implement a complete calling workflow with ringing functionality, including incoming/outgoing call UI, call acceptance, rejection, and cancellation. Previously known as **Default Calling**. @@ -64,7 +98,7 @@ CometChat.initiateCall(call).then( ); ``` - + ```typescript const receiverID: string = "UID"; const callType: string = CometChat.CALL_TYPE.VIDEO; @@ -82,22 +116,24 @@ CometChat.initiateCall(call).then( ); ``` - -```typescript -const receiverID: string = "GUID"; -const callType: string = CometChat.CALL_TYPE.VIDEO; -const receiverType: string = CometChat.RECEIVER_TYPE.GROUP; - -const call: CometChat.Call = new CometChat.Call(receiverID, callType, receiverType); - -CometChat.initiateCall(call).then( - (outgoingCall: CometChat.Call) => { + +```javascript +const initiateCall = async () => { + try { + const receiverID = "UID"; + const callType = CometChat.CALL_TYPE.VIDEO; + const receiverType = CometChat.RECEIVER_TYPE.USER; + + const call = new CometChat.Call(receiverID, callType, receiverType); + const outgoingCall = await CometChat.initiateCall(call); + console.log("Call initiated:", outgoingCall); - }, - (error: CometChat.CometChatException) => { + // Show outgoing call UI + // Store outgoingCall.getSessionId() for later use + } catch (error) { console.log("Call initiation failed:", error); } -); +}; ``` @@ -227,6 +263,22 @@ CometChat.acceptCall(sessionId).then( ); ``` + +```javascript +const acceptIncomingCall = async (incomingCall) => { + try { + const sessionId = incomingCall.getSessionId(); + const call = await CometChat.acceptCall(sessionId); + + console.log("Call accepted:", call); + // Call accepted, now start the call session + // Generate token and call startSession() + } catch (error) { + console.log("Accept call failed:", error); + } +}; +``` + ## Reject Call @@ -265,6 +317,22 @@ CometChat.rejectCall(sessionId, status).then( ); ``` + +```javascript +const rejectIncomingCall = async (incomingCall) => { + try { + const sessionId = incomingCall.getSessionId(); + const status = CometChat.CALL_STATUS.REJECTED; + + const call = await CometChat.rejectCall(sessionId, status); + console.log("Call rejected:", call); + // Dismiss incoming call UI + } catch (error) { + console.log("Reject call failed:", error); + } +}; +``` + ## Cancel Call @@ -303,6 +371,22 @@ CometChat.rejectCall(sessionId, status).then( ); ``` + +```javascript +const cancelOutgoingCall = async (outgoingCall) => { + try { + const sessionId = outgoingCall.getSessionId(); + const status = CometChat.CALL_STATUS.CANCELLED; + + const call = await CometChat.rejectCall(sessionId, status); + console.log("Call cancelled:", call); + // Dismiss outgoing call UI + } catch (error) { + console.log("Cancel call failed:", error); + } +}; +``` + ## Start Call Session diff --git a/sdk/javascript/delete-conversation.mdx b/sdk/javascript/delete-conversation.mdx index b91669f6..71801572 100644 --- a/sdk/javascript/delete-conversation.mdx +++ b/sdk/javascript/delete-conversation.mdx @@ -1,81 +1,130 @@ --- -title: "Delete A Conversation" +title: "Delete a Conversation" +sidebarTitle: "Delete Conversation" +description: "Remove a conversation from the logged-in user's conversation list" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Delete user conversation +await CometChat.deleteConversation("user_uid", "user"); + +// Delete group conversation +await CometChat.deleteConversation("group_guid", "group"); + +// Note: Only removes from YOUR list, not other participants +// Messages are still accessible if you receive new ones +``` + + +Delete a conversation to remove it from the user's conversation list. This only affects the logged-in user's view. -In case you want to delete a conversation, you can use the `deleteConversation()` method. + +**Availability**: SDK, API, UI Kits -This method takes two parameters. The unique id (UID/GUID) of the conversation to be deleted & the type (user/group) of conversation to be deleted. +Deleting a conversation only removes it for the logged-in user, not for other participants. + + +--- + +## Delete a Conversation - + ```javascript -let UID = "UID"; -let type = "user"; +const UID = "user1"; +const type = "user"; + CometChat.deleteConversation(UID, type).then( - deletedConversation => { - console.log(deletedConversation); - }, error => { - console.log('error while deleting a conversation', error); - } -); + (response) => console.log("Conversation deleted:", response), + (error) => console.log("Failed to delete:", error) +); ``` - - - + ```javascript -let GUID = "GUID"; -let type = "group"; +const GUID = "group-123"; +const type = "group"; + CometChat.deleteConversation(GUID, type).then( - deletedConversation => { - console.log(deletedConversation); - }, error => { - console.log('error while deleting a conversation', error); - } + (response) => console.log("Conversation deleted:", response), + (error) => console.log("Failed to delete:", error) ); ``` - - - + ```typescript -let UID: string = "UID"; -let type: string = "user"; +const UID: string = "user1"; +const type: string = "user"; + CometChat.deleteConversation(UID, type).then( - (deletedConversation: string) => { - console.log(deletedConversation); - }, (error: CometChat.CometChatException) => { - console.log('error while deleting a conversation', error); - } -); + (response: string) => console.log("Conversation deleted:", response), + (error: CometChat.CometChatException) => console.log("Failed:", error) +); ``` - - - -```typescript -let GUID: string = "GUID"; -let type: string = "group"; -CometChat.deleteConversation(GUID, type).then( - (deletedConversation: string) => { - console.log(deletedConversation); - }, (error: CometChat.CometChatException) => { - console.log('error while deleting a conversation', error); + +```javascript +const deleteConversation = async () => { + try { + const UID = "user1"; + const type = "user"; // or "group" for group conversations + + const response = await CometChat.deleteConversation(UID, type); + console.log("Conversation deleted:", response); + } catch (error) { + console.log("Failed to delete:", error); } -); +}; ``` - - -This method deletes the conversation only for the logged-in user. To delete a conversation for all the users of the conversation, please refer to our REST API documentation [here](https://api-explorer.cometchat.com/reference/resets-user-conversation). +| Parameter | Description | +|-----------|-------------| +| `conversationWith` | UID of user or GUID of group | +| `conversationType` | `"user"` or `"group"` | + +--- + +## What Gets Deleted + +| Deleted | Not Deleted | +|---------|-------------| +| Conversation from your list | Messages (still accessible) | +| Unread count | Other users' conversations | +| Last message preview | Group membership | + + +If you receive a new message from the deleted conversation, it will reappear in your conversation list. + + +--- + +## Delete for All Users + +To delete a conversation for all participants, use the REST API: + +```bash +curl -X DELETE "https://api-{region}.cometchat.io/v3/users/{uid}/conversation" \ + -H "apiKey: YOUR_API_KEY" \ + -H "Content-Type: application/json" +``` + +[View REST API Documentation →](https://api-explorer.cometchat.com/reference/resets-user-conversation) + +--- -The `deleteConversation()` method takes the following parameters: +## Next Steps -| Parameter | Description | Required | -| ---------------- | --------------------------------------------------------------------------------- | -------- | -| conversationWith | `UID` of the user or `GUID` of the group whose conversation you want to delete. | YES | -| conversationType | The type of conversation you want to delete . It can be either `user` or `group`. | YES | + + + Fetch conversation list + + + Delete individual messages + + diff --git a/sdk/javascript/delete-group.mdx b/sdk/javascript/delete-group.mdx index 54bcf413..7e20f309 100644 --- a/sdk/javascript/delete-group.mdx +++ b/sdk/javascript/delete-group.mdx @@ -1,48 +1,118 @@ --- -title: "Delete A Group" +title: "Delete a Group" +sidebarTitle: "Delete Group" +description: "Permanently delete a group (admin only)" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Delete a group (admin only) +await CometChat.deleteGroup("group_guid"); -## Delete a Group +// Check if user is admin first +const group = await CometChat.getGroup("group_guid"); +if (group.getScope() === CometChat.GROUP_MEMBER_SCOPE.ADMIN) { + await CometChat.deleteGroup("group_guid"); +} + +// Warning: Deletion is permanent - all messages and data are lost +``` + -To delete a group you need to use the `deleteGroup()` method. The user must be an `Admin` of the group they are trying to delete. + +**Available via**: SDK | REST API | Dashboard + + +Delete a group to permanently remove it and all its data. + + +**Admin Only**: Only group admins can delete groups. + +Deletion is permanent - all messages and member data will be lost. + + +--- + +## Delete a Group - + ```javascript -var GUID = "GUID"; +const GUID = "group-123"; CometChat.deleteGroup(GUID).then( -response => { - console.log("Groups deleted successfully:", response); -}, error => { - console.log("Group delete failed with exception:", error); -} + (response) => console.log("Group deleted:", response), + (error) => console.log("Failed to delete:", error) ); ``` - - ```typescript -var GUID: string = "GUID"; +const GUID: string = "group-123"; CometChat.deleteGroup(GUID).then( - (response: boolean) => { - console.log("Group deleted successfully:", response); - }, (error: CometChat.CometChatException) => { - console.log("Group delete failed with exception:", error); - } + (response: boolean) => console.log("Group deleted:", response), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - + +```javascript +const deleteGroup = async () => { + try { + const GUID = "group-123"; + const response = await CometChat.deleteGroup(GUID); + console.log("Group deleted:", response); + } catch (error) { + console.log("Failed to delete:", error); + } +}; +``` + -The `deleteGroup()` method takes the following parameters: +--- + +## Check Admin Status + +Before attempting to delete, verify the user is an admin: + +```javascript +const group = await CometChat.getGroup("group-123"); + +if (group.getScope() === CometChat.GROUP_MEMBER_SCOPE.ADMIN) { + // User can delete the group + await CometChat.deleteGroup("group-123"); +} else { + console.log("Only admins can delete groups"); +} +``` + +--- + +## Best Practices + + + + Always show a confirmation dialog before deleting a group to prevent accidental deletion. + + + Consider exporting important messages before deletion if needed for compliance or records. + + + +--- + +## Next Steps -| Parameter | Description | -| --------- | ---------------------------------------------- | -| `GUID` | The GUID of the group you would like to delete | + + + Create a new group + + + Modify group settings + + diff --git a/sdk/javascript/delete-message.mdx b/sdk/javascript/delete-message.mdx index d84b0761..b9dec4a9 100644 --- a/sdk/javascript/delete-message.mdx +++ b/sdk/javascript/delete-message.mdx @@ -1,120 +1,328 @@ --- -title: "Delete A Message" +title: "Delete a Message" +description: "Remove messages from conversations" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Delete a message +const message = await CometChat.deleteMessage(messageId); +console.log("Deleted at:", message.getDeletedAt()); + +// Listen for delete events +CometChat.addMessageListener("DELETE_LISTENER", new CometChat.MessageListener({ + onMessageDeleted: (message) => { + console.log("Deleted:", message.getId()); + console.log("Deleted by:", message.getDeletedBy()); + } +})); -While [deleting a message](/sdk/javascript/delete-message#delete-a-message) is straightforward, receiving events for deleted messages with CometChat has two parts: +// Hide deleted messages when fetching +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(uid) + .hideDeletedMessages(true) + .build(); -1. Adding a listener to receive [real-time message deletes](/sdk/javascript/delete-message#real-time-message-delete-events) when your app is running. -2. Calling a method to retrieve [missed message deletes](/sdk/javascript/delete-message#missed-message-delete-events) when your app was not running. +// Check if message was deleted +if (message.getDeletedAt()) { + // Show "This message was deleted" placeholder +} +``` + -## Delete a Message +CometChat allows users to delete messages from conversations. This guide covers deleting messages and handling delete events. -*In other words, as a sender, how do I delete a message?* + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + + +--- + +## Delete a Message -In case you have to delete a message, you can use the `deleteMessage()` method. This method takes the message ID of the message to be deleted. +Use `deleteMessage()` with the message ID to remove a message: - + + ```javascript + const messageId = 123; + + CometChat.deleteMessage(messageId).then( + (message) => { + console.log("Message deleted:", message); + console.log("Deleted at:", message.getDeletedAt()); + console.log("Deleted by:", message.getDeletedBy()); + }, + (error) => { + console.log("Error:", error); + } + ); + ``` + + + ```typescript + const messageId: number = 123; + + CometChat.deleteMessage(messageId).then( + (message: CometChat.BaseMessage) => { + console.log("Message deleted:", message); + }, + (error: CometChat.CometChatException) => { + console.log("Error:", error); + } + ); + ``` + + + ```javascript + async function deleteMessage(messageId) { + try { + const message = await CometChat.deleteMessage(messageId); + console.log("Message deleted at:", message.getDeletedAt()); + return message; + } catch (error) { + console.error("Delete failed:", error); + throw error; + } + } + + // Usage + await deleteMessage(123); + ``` + + + +The returned message object includes `deletedAt` and `deletedBy` fields to identify deleted messages. + +--- + +## Delete Permissions + +| User Role | Conversation Type | Can Delete | +|-----------|------------------|------------| +| Message Sender | One-on-One | Own messages | +| Message Sender | Group | Own messages | +| Group Admin | Group | All messages | +| Group Moderator | Group | All messages | + +--- + +## Real-Time Delete Events + +Listen for message deletions while your app is running: + ```javascript -let messageId = "ID_OF_THE_MESSAGE_YOU_WANT_TO_DELETE"; +const listenerID = "DELETE_LISTENER"; -CometChat.deleteMessage(messageId).then( -message => { - console.log("Message deleted", message); -}, error => { - console.log("Message delete failed with error:", error); -} -); +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageDeleted: (message) => { + console.log("Message deleted:", message); + console.log("Deleted at:", message.getDeletedAt()); + console.log("Deleted by:", message.getDeletedBy()); + + // Update your UI + removeOrMarkDeletedInUI(message); + } + }) +); ``` - +### Deleted Message Properties + +| Property | Method | Description | +|----------|--------|-------------| +| Deleted At | `getDeletedAt()` | Timestamp when deleted | +| Deleted By | `getDeletedBy()` | UID of user who deleted | + +--- + +## Missed Delete Events - -```typescript -let messageId: number = 1; +When fetching message history, deleted messages include `deletedAt` and `deletedBy` fields: -CometChat.deleteMessage(messageId).then( - (message: CometChat.BaseMessage) => { - console.log("Message deleted", message); - }, (error: CometChat.CometChatException) => { - console.log("Message delete failed with error:", error); + + +```javascript +messagesRequest.fetchPrevious().then((messages) => { + messages.forEach((message) => { + if (message.getDeletedAt()) { + console.log("This message was deleted"); + // Show "This message was deleted" placeholder + } else { + // Display message normally + } + }); +}); +``` + + +```javascript +async function fetchAndCheckDeleted() { + try { + const messages = await messagesRequest.fetchPrevious(); + messages.forEach((message) => { + if (message.getDeletedAt()) { + console.log("This message was deleted"); + } else { + // Display message normally + } + }); + return messages; + } catch (error) { + console.log("Error:", error); + throw error; } -); +} ``` - - -Once the message is deleted, In the `onSuccess()` callback, you get an object of the `BaseMessage` class, with the `deletedAt` field set with the timestamp of the time the message was deleted. Also, the `deletedBy` field is set. These two fields can be used to identify if the message is deleted while iterating through a list of messages. +Additionally, an `Action` message is created when a message is deleted: -By default, CometChat allows certain roles to delete a message. +| Field | Value | +|-------|-------| +| `action` | `"deleted"` | +| `actionOn` | Deleted message object | +| `actionBy` | User who deleted | +| `actionFor` | Receiver (User/Group) | -| User Role | Conversation Type | Deletion Capabilities | -| --------------- | ----------------------- | ------------------------------ | -| Message Sender | One-on-One Conversation | Messages they have sent. | -| Message Sender | Group Conversation | Messages they have sent. | -| Group Admin | Group Conversation | All the messages in the group. | -| Group Moderator | Group Conversation | All the messages in the group. | +--- -## Real-time Message Delete Events +## Hide Deleted Messages -*In other words, as a recipient, how do I know when someone deletes a message when my app is running?* +To exclude deleted messages from history, use the filter: -In order to receive real-time events for a message being deleted, you need to override the `onMessageDeleted()` method of the `MessageListener` class. + + +```javascript +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(UID) + .setLimit(30) + .hideDeletedMessages(true) + .build(); + +messagesRequest.fetchPrevious().then((messages) => { + // Only non-deleted messages returned +}); +``` + + +```javascript +async function fetchWithoutDeleted(UID) { + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(UID) + .setLimit(30) + .hideDeletedMessages(true) + .build(); + + try { + const messages = await messagesRequest.fetchPrevious(); + // Only non-deleted messages returned + return messages; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +--- + +## Example: Delete Message UI - + ```javascript -let listenerID = "UNIQUE_LISTENER_ID"; +function deleteMessage(messageId) { + return CometChat.deleteMessage(messageId).then( + (message) => { + // Option 1: Remove from UI + removeMessageFromUI(messageId); + + // Option 2: Show "deleted" placeholder + markMessageAsDeleted(messageId); + + return message; + }, + (error) => { + console.error("Delete failed:", error); + throw error; + } + ); +} -CometChat.addMessageListener( -listenerID, -new CometChat.MessageListener({ - onMessageDeleted: message => { - console.log("Deleted Message", message); +// Check if message is deleted when rendering +function renderMessage(message) { + if (message.getDeletedAt()) { + return "
This message was deleted
"; } -}) -); + return `
${message.getText()}
`; +} ``` -
+ +```javascript +async function deleteMessage(messageId) { + try { + const message = await CometChat.deleteMessage(messageId); + + // Option 1: Remove from UI + removeMessageFromUI(messageId); + + // Option 2: Show "deleted" placeholder + markMessageAsDeleted(messageId); + + return message; + } catch (error) { + console.error("Delete failed:", error); + throw error; + } +} - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +// Check if message is deleted when rendering +function renderMessage(message) { + if (message.getDeletedAt()) { + return "
This message was deleted
"; + } + return `
${message.getText()}
`; +} -CometChat.addMessageListener( - listenerID, - new CometChat.MessageListener({ - onMessageDeleted: (message: CometChat.BaseMessage) => { - console.log("Deleted Message", message); - } - }) -); +// Usage +await deleteMessage(123); ``` -
-
-## Missed Message Delete Events - -*In other words, as a recipient, how do I know if someone deleted a message when my app was not running?* +--- -When you retrieve the list of previous messages, for the messages that were deleted, the `deletedAt` and the `deletedBy` fields will be set. Also, for example, of the total number of messages for a conversation are 100, and the message with message ID 50 was deleted. Now the message with id 50 will have the `deletedAt` and the `deletedBy` fields set whenever it is pulled from the history. Also, the 101st message will be an Actionc message informing you that the message with id 50 has been deleted. +## Soft Delete vs Hard Delete -For the message deleted event, in the `Action` object received, the following fields can help you get the relevant information- +CometChat uses **soft delete** by default: +- Message remains in the database +- `deletedAt` and `deletedBy` fields are set +- Message can still be retrieved in history (unless filtered) -1. `action` - `deleted` -2. `actionOn` - Updated message object which was deleted. -3. `actionBy` - User object containing the details of the user who has deleted the message. -4. `actionFor` - User/group object having the details of the receiver to which the message was sent. +This allows you to: +- Show "This message was deleted" placeholders +- Maintain conversation context +- Comply with data retention requirements - +--- -In order to edit or delete a message you need to be either the sender of the message or the admin/moderator of the group in which the message was sent. +## Next Steps - + + + Allow users to edit sent messages + + + Clear entire conversation history + + diff --git a/sdk/javascript/delivery-read-receipts.mdx b/sdk/javascript/delivery-read-receipts.mdx index 464e319f..7d94a0df 100644 --- a/sdk/javascript/delivery-read-receipts.mdx +++ b/sdk/javascript/delivery-read-receipts.mdx @@ -1,793 +1,447 @@ --- title: "Delivery & Read Receipts" +description: "Track when messages are delivered and read" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Mark single message as delivered/read +CometChat.markAsDelivered(message); +CometChat.markAsRead(message); -## Mark Messages as Delivered - -*In other words, as a recipient, how do I inform the sender that I've received a message?* - -You can mark the messages for a particular conversation as read using the `markAsDelivered()` method. This method takes the below parameters as input: - -| Parameter | Information | -| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `messageId` | The ID of the message above which all the messages for a particular conversation are to be marked as read. | -| `receiverId` | In case of one to one conversation message's sender `UID` will be the receipt's receiver Id. In case of group conversation message's receiver Id will be the receipt's receiver Id. | -| `receiverType` | Type of the receiver. Could be either of the two values( user or group). | -| `senderId` | The `UID` of the sender of the message. | +// Mark entire conversation +await CometChat.markConversationAsDelivered("user_uid", "user"); +await CometChat.markConversationAsRead("user_uid", "user"); -Messages for both user & group conversations can be marked as read using this method. +// Mark as unread (requires Enhanced Messaging Status) +await CometChat.markMessageAsUnread(message); -Ideally, you would like to mark all the messages as delivered for any conversation when the user opens the chat window for that conversation. This includes two scenarios: +// Listen for receipts +CometChat.addMessageListener("RECEIPT_LISTENER", new CometChat.MessageListener({ + onMessagesDelivered: (receipt) => updateStatus(receipt.getMessageId(), "delivered"), + onMessagesRead: (receipt) => updateStatus(receipt.getMessageId(), "read") +})); -1. **When the list of messages for the conversation is fetched**: In this case you need to obtain the last message in the list of messages and pass the message ID of that message to the markAsDelivered() method. -2. **When the user is on the chat window and a real-time message is received:** In this case you need to obtain the message ID of the message and pass it to the markAsDelivered() method. +// Check message status +const deliveredAt = message.getDeliveredAt(); +const readAt = message.getReadAt(); - - -```javascript -var messageId = "MESSAGE_ID"; -var receiverId = "MESSAGE_RECEIVER_UID"; -var receiverType = "user"; -var senderId = "MESSAGE_SENDER_UID"; -CometChat.markAsDelivered(messageId, receiverId, receiverType, senderId); -``` - - - - -```javascript -var messageId = "MESSAGE_ID"; -var receiverId = "MESSAGE_RECEIVER_GUID"; -var receiverType = "group"; -var senderId = "MESSAGE_SENDER_UID"; -CometChat.markAsDelivered(messageId, receiverId, receiverType, senderId); +// Get receipt history for a message +const receipts = await CometChat.getMessageReceipts(messageId); ``` + -
+Message receipts let you show delivery and read status (✓ sent, ✓✓ delivered, ✓✓ read) in your chat UI. - -```typescript -var messageId: string = "MESSAGE_ID"; -var receiverId: string = "MESSAGE_RECEIVER_UID"; -var receiverType: string = "user"; -var senderId: string = "MESSAGE_SENDER_UID"; -CometChat.markAsDelivered(messageId, receiverId, receiverType, senderId); -``` + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + - +--- - -```typescript -var messageId: string = "MESSAGE_ID"; -var receiverId: string = "MESSAGE_RECEIVER_GUID"; -var receiverType: string = "group"; -var senderId: string = "MESSAGE_SENDER_UID"; -CometChat.markAsDelivered(messageId, receiverId, receiverType, senderId); -``` +## Mark Messages as Delivered - +Inform the sender that you've received their message: + + + ```javascript + // Simplest approach - pass the message directly + CometChat.markAsDelivered(message); + ``` + + + ```javascript + const messageId = message.getId(); + const receiverId = message.getSender().getUid(); // For user messages + const receiverType = "user"; + const senderId = message.getSender().getUid(); + + CometChat.markAsDelivered(messageId, receiverId, receiverType, senderId); + ``` + -This method will mark all the messages before the messageId specified, for the conversation with receiverId and receiverType(user/group) as delivered. - -In case you would like to be notified of an error if the receipts fail to go through you can use `.then(successCallback, failureCallback)` of the `markAsDelivered` method. - - - -```javascript -CometChat.markAsDelivered( - message.getId(), - message.getSender().getUid(), - "user", - message.getSender().getUid() -).then( - () => { - console.log("mark as delivered success."); - }, - (error) => { - console.log( - "An error occurred when marking the message as delivered.", - error - ); - } -); -``` +### When to Mark as Delivered - +1. **When fetching messages**: Mark the last message as delivered +2. **When receiving real-time messages**: Mark each incoming message - ```javascript -CometChat.markAsDelivered( - message.getId(), - message.getReceiverUid(), - "group", - message.getSender().getUid() -).then( - () => { - console.log("mark as delivered success."); - }, - (error) => { - console.log( - "An error occurred when marking the message as delivered.", - error - ); +// After fetching message history +messagesRequest.fetchPrevious().then((messages) => { + if (messages.length > 0) { + const lastMessage = messages[messages.length - 1]; + CometChat.markAsDelivered(lastMessage); } -); -``` - - +}); - -```typescript -var messageId: string = "MESSAGE_ID"; -var receiverId: string = "MESSAGE_SENDER_UID"; -var receiverType: string = "user"; -var senderId: string = "MESSAGE_SENDER_UID"; -CometChat.markAsDelivered(messageId, receiverId, receiverType, senderId).then( - () => { - console.log("mark as delivered success."); - }, - (error: CometChat.CometChatException) => { - console.log( - "An error occurred when marking the message as delivered.", - error - ); - } -); +// In real-time listener +onTextMessageReceived: (message) => { + CometChat.markAsDelivered(message); + displayMessage(message); +} ``` - +--- - -```typescript -var messageId: string = "MESSAGE_ID"; -var receiverId: string = "MESSAGE_RECEIVER_GUID"; -var receiverType: string = "group"; -var senderId: string = "MESSAGE_SENDER_UID"; -CometChat.markAsDelivered(messageId, receiverId, receiverType, senderId).then( - () => { - console.log("mark as delivered success."); - }, - (error: CometChat.CometChatException) => { - console.log( - "An error occurred when marking the message as delivered.", - error - ); - } -); -``` +## Mark Messages as Read - +Inform the sender that you've seen their message: + + + ```javascript + CometChat.markAsRead(message); + ``` + + + ```javascript + const messageId = message.getId(); + const receiverId = message.getSender().getUid(); + const receiverType = "user"; + const senderId = message.getSender().getUid(); + + CometChat.markAsRead(messageId, receiverId, receiverType, senderId); + ``` + -Another option the CometChat SDK provides is to pass the entire message object to the markAsDelivered() method. - - - -```javascript -CometChat.markAsDelivered(message); -``` +### When to Mark as Read - +- When the user views/scrolls to a message +- When the chat window is in focus +- When opening a conversation - -```typescript -let message: CometChat.BaseMessage; -CometChat.markAsDelivered(message); +```javascript +// Mark as read when user views the conversation +function onConversationOpened(conversation) { + const lastMessage = conversation.getLastMessage(); + if (lastMessage) { + CometChat.markAsRead(lastMessage); + } +} ``` - +--- - +## Mark Entire Conversation -In case you would like to be notified of an error if the receipts fail to go through you can use `.then(successCallback, failureCallback)` of the `markAsDelivered` method. +Mark all messages in a conversation at once: - -```javascript -CometChat.markAsDelivered(message).then( - () => { - console.log("mark as delivered success."); - }, - (error) => { - console.log( - "An error occurred when marking the message as delivered.", - error + + ```javascript + const conversationWith = "user_uid"; // or group_guid + const conversationType = "user"; // or "group" + + CometChat.markConversationAsDelivered(conversationWith, conversationType).then( + () => console.log("Conversation marked as delivered"), + (error) => console.log("Error:", error) ); - } -); -``` - - - - -```typescript -let message: CometChat.BaseMessage; -CometChat.markAsDelivered(message).then( - () => { - console.log("mark as delivered success."); - }, - (error: CometChat.CometChatException) => { - console.log( - "An error occurred when marking the message as delivered.", - error + ``` + + + ```javascript + const conversationWith = "user_uid"; + const conversationType = "user"; + + CometChat.markConversationAsRead(conversationWith, conversationType).then( + () => console.log("Conversation marked as read"), + (error) => console.log("Error:", error) ); - } -); -``` - - - + ``` + + + ```javascript + const markConversation = async () => { + try { + const conversationWith = "user_uid"; // or group_guid + const conversationType = "user"; // or "group" + + // Mark as delivered + await CometChat.markConversationAsDelivered(conversationWith, conversationType); + console.log("Conversation marked as delivered"); + + // Or mark as read + await CometChat.markConversationAsRead(conversationWith, conversationType); + console.log("Conversation marked as read"); + } catch (error) { + console.log("Error:", error); + } + }; + ``` + -## Mark Conversation as Delivered - -You can mark an entire conversation as delivered for a user or group using the `markConversationAsDelivered()` method. This method takes the below parameters as input: +--- -| Parameter | Information | -| ------------------ | ------------------------------------------------------------------------------ | -| `conversationWith` | The ID of the user (UID) or group (GUID) for the conversation. | -| `conversationType` | Type of the conversation. Could be either `user` or `group`. | +## Mark as Unread -This method will mark all messages in the conversation as delivered. +Mark a message as unread to revisit later: - + ```javascript -var conversationWith = "USER_UID"; -var conversationType = "user"; - -CometChat.markConversationAsDelivered(conversationWith, conversationType).then( - (response) => { - console.log("Conversation marked as delivered", response); +CometChat.markMessageAsUnread(message).then( + (conversation) => { + console.log("Marked as unread"); + console.log("Unread count:", conversation.getUnreadMessageCount()); }, - (error) => { - console.log("Error marking conversation as delivered", error); - } + (error) => console.log("Error:", error) ); ``` - - + ```javascript -var conversationWith = "GROUP_GUID"; -var conversationType = "group"; - -CometChat.markConversationAsDelivered(conversationWith, conversationType).then( - (response) => { - console.log("Conversation marked as delivered", response); - }, - (error) => { - console.log("Error marking conversation as delivered", error); +async function markAsUnread(message) { + try { + const conversation = await CometChat.markMessageAsUnread(message); + console.log("Marked as unread"); + console.log("Unread count:", conversation.getUnreadMessageCount()); + return conversation; + } catch (error) { + console.log("Error:", error); + throw error; } -); -``` - - - -```typescript -var conversationWith: string = "USER_UID"; -var conversationType: string = "user"; - -CometChat.markConversationAsDelivered(conversationWith, conversationType).then( - (response: string) => { - console.log("Conversation marked as delivered", response); - }, - (error: CometChat.CometChatException) => { - console.log("Error marking conversation as delivered", error); - } -); -``` - - - -```typescript -var conversationWith: string = "GROUP_GUID"; -var conversationType: string = "group"; - -CometChat.markConversationAsDelivered(conversationWith, conversationType).then( - (response: string) => { - console.log("Conversation marked as delivered", response); - }, - (error: CometChat.CometChatException) => { - console.log("Error marking conversation as delivered", error); - } -); -``` - - - -## Mark Messages as Read - -*In other words, as a recipient, how do I inform the sender I've read a message?* - -You can mark the messages for a particular conversation as read using the `markAsRead()` method. This method takes the below parameters as input: - -| Parameter | Information | -| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `messageId` | The ID of the message above which all the messages for a particular conversation are to be marked as read. | -| `receiverId` | In case of one to one conversation message's sender `UID` will be the receipt's receiver Id. In case of group conversation message's receiver Id will be the receipt's receiver Id | -| `receiverType` | Type of the receiver. Could be either of the two values( user or group) | -| `senderId` | The `UID` of the sender of the message. | - -Messages for both user and group conversations can be marked as read using this method. - -Ideally, you would like to mark all the messages as read for any conversation when the user opens the chat window for that conversation. This includes two scenarios: - -1. **When the list of messages for the conversation is fetched**: In this case you need to obtain the last message in the list of messages and pass the message ID of that message to the markAsRead() method. -2. **When the user is on the chat window and a real-time message is received:** In this case you need to obtain the message ID of the message and pass it to the markAsRead() method - - - -```javascript -var messageId = "MESSAGE_ID"; -var receiverId = "MESSAGE_SENDER_UID"; -var receiverType = "user"; -var senderId = "MESSAGE_SENDER_UID"; -CometChat.markAsRead(messageId, receiverId, receiverType, senderId); -``` - - - - -```javascript -var receiverId = "MESSAGE_RECEIVER_GUID"; -var receiverType = "group"; -var senderId = "MESSAGE_SENDER_UID"; -CometChat.markAsRead(messageId, receiverId, receiverType, senderId); +} ``` - - - -```typescript -var messageId: string = "MESSAGE_ID"; -var receiverId: string = "MESSAGE_SENDER_UID"; -var receiverType: string = "user"; -var senderId: string = "MESSAGE_SENDER_UID"; -CometChat.markAsRead(messageId, receiverId, receiverType, senderId); -``` - - - - -```typescript -var messageId: string = "MESSAGE_ID"; -var receiverId: string = "MESSAGE_RECEIVER_GUID"; -var receiverType: string = "group"; -var senderId: string = "MESSAGE_SENDER_UID"; -CometChat.markAsRead(messageId, receiverId, receiverType, senderId); -``` - - - -This method will mark all the messages before the messageId specified, for the conversation with receiverId and receiverType(user/group) as read. - -In case you would like to be notified of an error if the receipts fail to go through you can use `.then(successCallback, failureCallback)` of the `markAsDelivered` method. - - - -```javascript -CometChat.markAsRead( - message.getId(), - message.getSender().getUid(), - "user", - message.getSender().getUid() -).then( - () => { - console.log("mark as read success."); - }, - (error) => { - console.log("An error occurred when marking the message as read.", error); - } -); -``` - - - - -```javascript -CometChat.markAsRead( - message.getId(), - message.getReceiverUid(), - "group", - message.getSender().getUid() -).then( - () => { - console.log("mark as read success."); - }, - (error) => { - console.log("An error occurred when marking the message as read.", error); - } -); -``` - - - - -```typescript -var messageId: string = "MESSAGE_ID"; -var receiverId: string = "MESSAGE_SENDER_UID"; -var receiverType: string = "user"; -var senderId: string = "MESSAGE_SENDER_UID"; -CometChat.markAsRead(messageId, receiverId, receiverType, senderId).then( - () => { - console.log("mark as read success."); - }, - (error: CometChat.CometChatException) => { - console.log("An error occurred when marking the message as read.", error); - } -); -``` - - + +You can only mark messages from other users as unread, not your own messages. + - -```typescript -var messageId: string = "MESSAGE_ID"; -var receiverId: string = "MESSAGE_RECEIVER_GUID"; -var receiverType: string = "group"; -var senderId: string = "MESSAGE_SENDER_UID"; -CometChat.markAsRead(messageId, receiverId, receiverType, senderId).then( - () => { - console.log("mark as read success."); - }, - (error: CometChat.CometChatException) => { - console.log("An error occurred when marking the message as read.", error); - } -); -``` + +**Mark as Unread** requires the **Enhanced Messaging Status** feature to be enabled for your app. + - +--- - +## Receive Receipt Events -Another option the CometChat SDK provides is to pass the entire message object to the markAsRead() method. +Listen for delivery and read receipts in real-time: - - ```javascript -CometChat.markAsRead(message); -``` - - - - -```typescript -let message: CometChat.BaseMessage; -CometChat.markAsRead(message); -``` - - - - - -In case you would like to be notified of an error if the receipts fail to go through you can use `.then(successCallback, failureCallback)` of the `markAsDelivered` method. +const listenerID = "RECEIPT_LISTENER"; - - -```javascript -CometChat.markAsRead(message).then( - () => { - console.log("mark as read success."); - }, - (error) => { - console.log("An error occurred when marking the message as read.", error); - } +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + // One-on-one and group messages + onMessagesDelivered: (messageReceipt) => { + console.log("Message delivered:", messageReceipt); + updateMessageStatus(messageReceipt.getMessageId(), "delivered"); + }, + onMessagesRead: (messageReceipt) => { + console.log("Message read:", messageReceipt); + updateMessageStatus(messageReceipt.getMessageId(), "read"); + }, + + // Group messages only - when ALL members have received/read + onMessagesDeliveredToAll: (messageReceipt) => { + console.log("Delivered to all group members"); + }, + onMessagesReadByAll: (messageReceipt) => { + console.log("Read by all group members"); + } + }) ); ``` - + +`onMessagesDeliveredToAll` and `onMessagesReadByAll` require the **Enhanced Messaging Status** feature. + - -```typescript -let message: CometChat.BaseMessage; -CometChat.markAsRead(message).then( - () => { - console.log("mark as read success."); - }, - (error: CometChat.CometChatException) => { - console.log("An error occurred when marking the message as read.", error); - } -); -``` +--- - +## MessageReceipt Properties - +| Property | Method | Description | +|----------|--------|-------------| +| Message ID | `getMessageId()` | ID of the message | +| Sender | `getSender()` | User who sent the receipt | +| Receiver ID | `getReceiverId()` | UID or GUID | +| Receiver Type | `getReceiverType()` | `user` or `group` | +| Receipt Type | `getReceiptType()` | `delivered` or `read` | +| Delivered At | `getDeliveredAt()` | Delivery timestamp | +| Read At | `getReadAt()` | Read timestamp | -## Mark Conversation as Read +--- -You can mark an entire conversation as read for a user or group using the `markConversationAsRead()` method. This method takes the below parameters as input: +## Get Receipt History -| Parameter | Information | -| ------------------ | ------------------------------------------------------------------------------ | -| `conversationWith` | The ID of the user (UID) or group (GUID) for the conversation. | -| `conversationType` | Type of the conversation. Could be either `user` or `group`. | - -This method will mark all messages in the conversation as read. +Fetch delivery/read status for a specific message (useful for group messages): - + ```javascript -var conversationWith = "USER_UID"; -var conversationType = "user"; +const messageId = 123; -CometChat.markConversationAsRead(conversationWith, conversationType).then( - (response) => { - console.log("Conversation marked as read", response); +CometChat.getMessageReceipts(messageId).then( + (receipts) => { + receipts.forEach((receipt) => { + console.log( + receipt.getSender().getName(), + receipt.getReceiptType(), + "at", + receipt.getReadAt() || receipt.getDeliveredAt() + ); + }); }, - (error) => { - console.log("Error marking conversation as read", error); - } + (error) => console.log("Error:", error) ); ``` - - + ```javascript -var conversationWith = "GROUP_GUID"; -var conversationType = "group"; - -CometChat.markConversationAsRead(conversationWith, conversationType).then( - (response) => { - console.log("Conversation marked as read", response); - }, - (error) => { - console.log("Error marking conversation as read", error); +async function getReceiptHistory(messageId) { + try { + const receipts = await CometChat.getMessageReceipts(messageId); + receipts.forEach((receipt) => { + console.log( + receipt.getSender().getName(), + receipt.getReceiptType(), + "at", + receipt.getReadAt() || receipt.getDeliveredAt() + ); + }); + return receipts; + } catch (error) { + console.log("Error:", error); + throw error; } -); -``` - - - -```typescript -var conversationWith: string = "USER_UID"; -var conversationType: string = "user"; - -CometChat.markConversationAsRead(conversationWith, conversationType).then( - (response: string) => { - console.log("Conversation marked as read", response); - }, - (error: CometChat.CometChatException) => { - console.log("Error marking conversation as read", error); - } -); -``` - - - -```typescript -var conversationWith: string = "GROUP_GUID"; -var conversationType: string = "group"; - -CometChat.markConversationAsRead(conversationWith, conversationType).then( - (response: string) => { - console.log("Conversation marked as read", response); - }, - (error: CometChat.CometChatException) => { - console.log("Error marking conversation as read", error); - } -); +} ``` -## Mark Messages as Unread - -The Mark messages as Unread feature allows users to designate specific messages or conversations as unread, even if they have been previously viewed. - -This feature is valuable for users who want to revisit and respond to important messages or conversations later, ensuring they don't forget or overlook them. - -In other words, how I can mark a message as unread? - -You can mark the messages for a particular conversation as unread using the `markMessageAsUnread()` method. This method takes the below parameters as input: +--- -| Parameter | Information | -| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| message | To mark a message as unread, pass a non-null `BaseMessage` instance to the `markMessageAsUnread()` function. All messages below that message in the conversation will contribute to the unread messages count. Example: When User B sends User A a total of 10 messages, and User A invokes the `markMessageAsUnread()` method on the fifth message, all messages located below the fifth message within the conversation list will be designated as unread. This results in a notification indicating there are 5 unread messages in the conversation list. | +## Check Message Status - -You cannot mark your own messages as unread. This method only works for messages received from other users. - +When fetching messages, check their delivery/read status: - + ```javascript -CometChat.markMessageAsUnread(message); -``` - - - - -```typescript -let message: CometChat.BaseMessage; -CometChat.markMessageAsUnread(message); -``` - - - - - -In case you would like to be notified of an error if the receipts fail to go through you can use `.then(successCallback, failureCallback).` On success, this method returns an updated `Conversation` object with the updated unread message count and other conversation data. - - - +messagesRequest.fetchPrevious().then((messages) => { + messages.forEach((message) => { + const deliveredAt = message.getDeliveredAt(); + const readAt = message.getReadAt(); + + if (readAt) { + console.log("Read at:", readAt); + } else if (deliveredAt) { + console.log("Delivered at:", deliveredAt); + } else { + console.log("Sent"); + } + }); +}); +``` + + ```javascript -CometChat.markMessageAsUnread(message).then( - (conversation) => { - console.log("mark messages as unread success.", conversation); - console.log("Unread message count:", conversation.getUnreadMessageCount()); - }, - (error) => { - console.log("An error occurred when marking the message as unread.", error); +async function checkMessageStatuses() { + try { + const messages = await messagesRequest.fetchPrevious(); + + messages.forEach((message) => { + const deliveredAt = message.getDeliveredAt(); + const readAt = message.getReadAt(); + + if (readAt) { + console.log("Read at:", readAt); + } else if (deliveredAt) { + console.log("Delivered at:", deliveredAt); + } else { + console.log("Sent"); + } + }); + + return messages; + } catch (error) { + console.log("Error:", error); + throw error; } -); +} ``` - - - -```typescript -let message: CometChat.BaseMessage; -CometChat.markMessageAsUnread(message).then( - (conversation: CometChat.Conversation) => { - console.log("mark messages as unread success.", conversation); - console.log("Unread message count:", conversation.getUnreadMessageCount()); - }, - (error: CometChat.CometChatException) => { - console.log("An error occurred when marking the message as unread.", error); - } -); -``` - - - -Receive Delivery & Read Receipts - -*In other words, as a recipient, how do I know when a message I sent has been delivered or read by someone?* - -### Real-time events - -1. `onMessagesDelivered()` - This event is triggered when a message is delivered to a user. -2. `onMessagesRead()` - This event is triggered when a message is read by a user. -3. `onMessagesDeliveredToAll()` - This event is triggered when a group message is delivered to all members of the group. This event is only for Group conversations. -4. `onMessagesReadByAll()` - This event is triggered when a group message is read by all members of the group. This event is only for Group conversations. - - - -```javascript -let listenerId = "UNIQUE_LISTENER_ID"; - -CometChat.addMessageListener( - "listenerId", - new CometChat.MessageListener({ - onMessagesDelivered: (messageReceipt) => { - console.log("Message is delivered to a user: ", { messageReceipt }); - }, - onMessagesRead: (messageReceipt) => { - console.log("Message is read by a user: ", { messageReceipt }); - }, - /** This event is only for Group Conversation. */ - onMessagesDeliveredToAll: (messageReceipt) => { - console.log("Message delivered to all members of group: ", { - messageReceipt, - }); - }, - /** This event is only for Group Conversation. */ - onMessagesReadByAll: (messageReceipt) => { - console.log("Message read by all members of group: ", { messageReceipt }); - }, - }) -); -``` - - - - -```typescript -let listenerId: string = "UNIQUE_LISTENER_ID"; - -CometChat.addMessageListener( - listenerId, - new CometChat.MessageListener({ - onMessagesDelivered: (messageReceipt: CometChat.MessageReceipt) => { - console.log("Message is delivered to a user: ", { messageReceipt }); - }, - onMessagesRead: (messageReceipt: CometChat.MessageReceipt) => { - console.log("Message is read by a user: ", { messageReceipt }); - }, - /** This event is only for Group Conversation. */ - onMessagesDeliveredToAll: (messageReceipt: CometChat.MessageReceipt) => { - console.log("Message delivered to all members of group: ", { - messageReceipt, - }); - }, - /** This event is only for Group Conversation. */ - onMessagesReadByAll: (messageReceipt: CometChat.MessageReceipt) => { - console.log("Message read by all members of group: ", { messageReceipt }); - }, - }) -); -``` - - - - - -You will receive events in the form of `MessageReceipt` objects. The message receipt contains the below parameters: - -| Parameter | Information | -| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `messageId` | The Id of the message prior to which all the messages for that particular conversation have been marked as read. | -| `sender` | User object containing the details of the user who has marked the message as read. System User for `deliveredToAll` & `readByAll` events. | -| `receiverId` | Id of the receiver whose conversation has been marked as read. | -| `receiverType` | type of the receiver (user/group) | -| `receiptType` | Type of the receipt (read/delivered) | -| `deliveredAt` | The timestamp of the time when the message was delivered. This will only be present if the receiptType is delivered. | -| `readAt` | The timestamp of the time when the message was read. This will only be present when the receiptType is read. | - -### Missed Receipts - -You will receive message receipts when you load offline messages. While fetching messages in bulk, the message object will have two fields i.e. `deliveredAt` and `readAt` which hold the timestamp for the time the message was delivered and read respectively. Using these two variables, the delivery and read status for a message can be obtained. - -However, for a group message, if you wish to fetch the `deliveredAt` and `readAt` fields of individual member of the group you can use the below-described method. - -### Receipt History for a Single Message +--- -To fetch the message receipts, you can use the `getMessageReceipts()` method. +## Implementation Example - - ```javascript -let messageId = msgId; -CometChat.getMessageReceipts(messageId).then( - (receipts) => { - console.log("Message details fetched:", receipts); - }, - (error) => { - console.log("Error in getting messag details ", error); +// Message status component +function getMessageStatus(message) { + // Only show status for sent messages (not received) + if (message.getSender().getUid() !== loggedInUser.getUid()) { + return null; } -); -``` - + const readAt = message.getReadAt(); + const deliveredAt = message.getDeliveredAt(); - -```typescript -let messageId: number = 1; -CometChat.getMessageReceipts(messageId).then( - (receipts: CometChat.MessageReceipt[]) => { - console.log("Message details fetched:", receipts); - }, - (error: CometChat.CometChatException) => { - console.log("Error in getting messag details ", error); + if (readAt) { + return { icon: "✓✓", color: "blue", label: "Read" }; + } else if (deliveredAt) { + return { icon: "✓✓", color: "gray", label: "Delivered" }; + } else { + return { icon: "✓", color: "gray", label: "Sent" }; } -); +} + +// Update status when receipt received +function updateMessageStatus(messageId, status) { + const messageElement = document.querySelector(`[data-message-id="${messageId}"]`); + if (messageElement) { + const statusElement = messageElement.querySelector(".status"); + if (status === "read") { + statusElement.innerHTML = "✓✓"; + statusElement.style.color = "blue"; + } else if (status === "delivered") { + statusElement.innerHTML = "✓✓"; + statusElement.style.color = "gray"; + } + } +} ``` - - - - -You will receive a list of `MessageReceipt` objects. +--- - +## Best Practices + + + + Mark messages as delivered as soon as they're received, even before displaying them. + + + Only mark messages as read when the user actually sees them (chat window in focus, message scrolled into view). + + + When opening a conversation, mark the last message as read rather than marking each message individually. + + + Messages fetched from history will have `deliveredAt` and `readAt` fields already set. + + -The following features will be available only if the **Enhanced Messaging Status** feature is enabled for your app. +--- -* `onMessagesDeliveredToAll` event, -* `onMessagesReadByAll` event, -* `deliveredAt` field in a group message, -* `readAt` field in a group message. -* `markMessageAsUnread` method. +## Next Steps - + + + Show when users are typing + + + Handle incoming messages + + diff --git a/sdk/javascript/direct-call.mdx b/sdk/javascript/direct-call.mdx index 0bedb023..318cff1b 100644 --- a/sdk/javascript/direct-call.mdx +++ b/sdk/javascript/direct-call.mdx @@ -2,6 +2,41 @@ title: "Call Session" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Generate call token +const loggedInUser = await CometChat.getLoggedinUser(); +const callToken = await CometChatCalls.generateToken(sessionId, loggedInUser.getAuthToken()); + +// Start call session +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIsAudioOnlyCall(false) + .setCallListener(new CometChatCalls.OngoingCallListener({ + onCallEnded: () => { CometChatCalls.endSession(); }, + onCallEndButtonPressed: () => { CometChatCalls.endSession(); }, + onUserJoined: (user) => console.log("Joined:", user), + onUserLeft: (user) => console.log("Left:", user) + })) + .build(); +CometChatCalls.startSession(callToken, callSettings, document.getElementById("call-container")); + +// Control methods during call +CometChatCalls.muteAudio(true/false); +CometChatCalls.pauseVideo(true/false); +CometChatCalls.startScreenShare(); +CometChatCalls.stopScreenShare(); +CometChatCalls.endSession(); +``` + + + +**Available via**: SDK | UI Kits + + ## Overview This section demonstrates how to start a call session in a web application. Previously known as **Direct Calling**. @@ -57,6 +92,23 @@ CometChatCalls.generateToken(sessionId, authToken).then( ); ``` + +```javascript +const generateCallToken = async () => { + try { + const loggedInUser = await CometChat.getLoggedinUser(); + const authToken = loggedInUser.getAuthToken(); + const sessionId = "SESSION_ID"; // Random or from Call object in ringing flow + + const callToken = await CometChatCalls.generateToken(sessionId, authToken); + console.log("Call token generated:", callToken.token); + // Use callToken to start the session + } catch (error) { + console.log("Token generation failed:", error); + } +}; +``` + | Parameter | Description | diff --git a/sdk/javascript/edit-message.mdx b/sdk/javascript/edit-message.mdx index 8b91b4ae..89784598 100644 --- a/sdk/javascript/edit-message.mdx +++ b/sdk/javascript/edit-message.mdx @@ -1,177 +1,277 @@ --- -title: "Edit A Message" +title: "Edit a Message" +description: "Allow users to edit sent messages" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Edit a text message +const editedMessage = new CometChat.TextMessage( + receiverID, + "Updated text", + CometChat.RECEIVER_TYPE.USER +); +editedMessage.setId(originalMessageId); // Required! +const message = await CometChat.editMessage(editedMessage); + +// Listen for edit events +CometChat.addMessageListener("EDIT_LISTENER", new CometChat.MessageListener({ + onMessageEdited: (message) => { + console.log("Edited:", message.getText()); + console.log("Edited at:", message.getEditedAt()); + console.log("Edited by:", message.getEditedBy()); + } +})); -While [editing a message](/sdk/javascript/edit-message#edit-a-message) is straightforward, receiving events for edited messages with CometChat has two parts: - -1. Adding a listener to receive [real-time message edits](/sdk/javascript/edit-message#real-time-message-edit-events) when your app is running -2. Calling a method to retrieve [missed message edits](/sdk/javascript/edit-message#missed-message-edit-events) when your app was not running +// Check if message was edited +if (message.getEditedAt()) { + console.log("Message was edited"); +} +``` + -## Edit a Message +CometChat allows users to edit their sent messages. This guide covers editing messages and handling edit events. -*In other words, as a sender, how do I edit a message?* + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + -In order to edit a message, you can use the `editMessage()` method. This method takes an object of the `BaseMessage` class. At the moment, you are only allowed to edit `TextMessage` and `CustomMessage`. Thus, the `BaseMessage` object must either be a Text or a Custom Message. +--- -### Add/Update Tags +## Edit a Message -While editing a message, you can update the tags associated with the Message. You can use the `setTags()` method to do so. The tags added while editing a message will replace the tags set when the message was sent. +Use `editMessage()` to modify a previously sent message. Currently, only `TextMessage` and `CustomMessage` can be edited. - -```javascript -let tags = ["pinnedMessage"]; + + ```javascript + const receiverID = "user_uid"; + const messageText = "Updated message text"; + const receiverType = CometChat.RECEIVER_TYPE.USER; + const messageId = 123; // ID of message to edit + + const textMessage = new CometChat.TextMessage( + receiverID, + messageText, + receiverType + ); + textMessage.setId(messageId); + + CometChat.editMessage(textMessage).then( + (message) => { + console.log("Message edited:", message); + console.log("Edited at:", message.getEditedAt()); + console.log("Edited by:", message.getEditedBy()); + }, + (error) => { + console.log("Error:", error); + } + ); + ``` + + + ```typescript + const receiverID: string = "user_uid"; + const messageText: string = "Updated message text"; + const receiverType: string = CometChat.RECEIVER_TYPE.USER; + const messageId: number = 123; + + const textMessage: CometChat.TextMessage = new CometChat.TextMessage( + receiverID, + messageText, + receiverType + ); + textMessage.setId(messageId); + + CometChat.editMessage(textMessage).then( + (message: CometChat.TextMessage) => { + console.log("Message edited:", message); + }, + (error: CometChat.CometChatException) => { + console.log("Error:", error); + } + ); + ``` + + + ```javascript + async function editMessage(originalMessage, newText) { + const editedMessage = new CometChat.TextMessage( + originalMessage.getReceiverId(), + newText, + originalMessage.getReceiverType() + ); + editedMessage.setId(originalMessage.getId()); + + try { + const message = await CometChat.editMessage(editedMessage); + console.log("Message edited:", message.getText()); + console.log("Edited at:", message.getEditedAt()); + return message; + } catch (error) { + console.error("Edit failed:", error); + throw error; + } + } + + // Usage + const updatedMessage = await editMessage(originalMessage, "New text here"); + ``` + + -textMessage.setTags(tags); -``` + +You must set the message ID using `setId()` before calling `editMessage()`. + - +### Update Tags While Editing + +You can update message tags during edit: - ```javascript -let tags = ["pinnedMessage"]; +const textMessage = new CometChat.TextMessage(receiverID, newText, receiverType); +textMessage.setId(messageId); +textMessage.setTags(["edited", "important"]); -customMessage.setTags(tags); +CometChat.editMessage(textMessage); ``` - - - -```typescript -let tags: Array = ["pinnedMessage"]; - -textMessage.setTags(tags); -``` + +Tags set during edit replace all existing tags on the message. + - +--- - -```typescript -let tags: Array = ["pinnedMessage"]; +## Edit Permissions -customMessage.setTags(tags); -``` +| User Role | Conversation Type | Can Edit | +|-----------|------------------|----------| +| Message Sender | One-on-One | Own messages | +| Message Sender | Group | Own messages | +| Group Admin | Group | All messages | +| Group Moderator | Group | All messages | - +--- - +## Real-Time Edit Events -Once the message object is ready, you can use the `editMessage()` method and pass the message object to it. +Listen for message edits while your app is running: - - ```javascript -let receiverID = "RECEIVER_UID"; -let messageText = "Hello world!"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let messageId = "MESSAGE_ID_OF_THE_MESSAGE_TO_BE_EDITED"; -let textMessage = new CometChat.TextMessage(receiverID, messageText, receiverType); - -textMessage.setId(messageId); +const listenerID = "EDIT_LISTENER"; -CometChat.editMessage(textMessage).then( -message => { - console.log("Message Edited", message); -}, error => { - console.log("Message editing failed with error:", error); -} +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageEdited: (message) => { + console.log("Message edited:", message); + console.log("New text:", message.getText()); + console.log("Edited at:", message.getEditedAt()); + console.log("Edited by:", message.getEditedBy()); + + // Update your UI + updateMessageInList(message); + } + }) ); ``` - +### Edited Message Properties - -```typescript -let receiverID: string = "RECEIVER_UID"; -let messageText: string = "Hello world!"; -let receiverType: string = CometChat.RECEIVER_TYPE.USER; -let messageId: number = 1; -let textMessage: CometChat.TextMessage = new CometChat.TextMessage(receiverID, messageText, receiverType); +| Property | Method | Description | +|----------|--------|-------------| +| Edited At | `getEditedAt()` | Timestamp when edited | +| Edited By | `getEditedBy()` | UID of user who edited | -textMessage.setId(messageId); - -CometChat.editMessage(textMessage).then( - (message: CometChat.TextMessage) => { - console.log("Message Edited", message); - }, (error: CometChat.CometChatException) => { - console.log("Message editing failed with error:", error); - } -); -``` - - - - - -The object of the edited message will be returned in the `onSuccess()` callback method of the listener. The message object will contain the `editedAt` field set with the timestamp of the time the message was edited. This will help you identify if the message was edited while iterating through the list of messages. The `editedBy` field is also set to the UID of the user who edited the message. - -By default, CometChat allows certain roles to edit a message. - -| User Role | Conversation Type | Edit Capabilities | -| --------------- | ----------------------- | -------------------------- | -| Message Sender | One-on-One Conversation | Messages they have sent. | -| Message Sender | Group Conversation | Messages they have sent. | -| Group Owner | Group Conversation | All messages in the group. | -| Group Moderator | Group Conversation | All messages in the group. | - -## Real-time Message Edit Events +--- -*In other words, as a recipient, how do I know when someone has edited their message when my app is running?* +## Missed Edit Events -In order to receive real-time events for message being edited, you need to override the `onMessageEdited()` method of the `MessageListener` class. +When fetching message history, edited messages include `editedAt` and `editedBy` fields: - + ```javascript -let listenerID = "UNIQUE_LISTENER_ID"; - -CometChat.addMessageListener( -listenerID, -new CometChat.MessageListener({ - onMessageEdited: message => { - console.log("Edited Message", message); - } -}) -); +messagesRequest.fetchPrevious().then((messages) => { + messages.forEach((message) => { + if (message.getEditedAt()) { + console.log("This message was edited at:", message.getEditedAt()); + } + }); +}); ``` - - - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; - -CometChat.addMessageListener( -listenerID, -new CometChat.MessageListener({ - onMessageEdited: (message: CometChat.BaseMessage) => { - console.log("Edited Message", message); + +```javascript +async function fetchAndCheckEdits() { + try { + const messages = await messagesRequest.fetchPrevious(); + messages.forEach((message) => { + if (message.getEditedAt()) { + console.log("This message was edited at:", message.getEditedAt()); + } + }); + return messages; + } catch (error) { + console.log("Error:", error); + throw error; } -}) -); +} ``` - - -## Missed Message Edit Events +Additionally, an `Action` message is created when a message is edited: -*In other words, as a recipient, how do I know when someone edited their message when my app was not running?* +| Field | Value | +|-------|-------| +| `action` | `"edited"` | +| `actionOn` | Updated message object | +| `actionBy` | User who edited | +| `actionFor` | Receiver (User/Group) | -When you retrieve the list of previous messages, for the message that was edited, the `editedAt` and the `editedBy` fields will be set. Also, for example, of the total number of messages for a conversation are 100, and the message with message ID 50 was edited. Now the message with id 50 will have the `editedAt` and the `editedBy` fields set whenever it is pulled from the history. Also, the 101st message will be and \[Action] message informing you that the message with id 50 has been edited. +--- -For the message edited event, in the `Action` object received, the following fields can help you get the relevant information- +## Example: Edit Message UI -1. `action` - `edited` -2. `actionOn` - Updated message object with the edited details. -3. `actionBy` - User object containing the details of the user who has edited the message. -4. `actionFor` - User/group object having the details of the receiver to which the message was sent. +```javascript +function editMessage(originalMessage, newText) { + const editedMessage = new CometChat.TextMessage( + originalMessage.getReceiverId(), + newText, + originalMessage.getReceiverType() + ); + editedMessage.setId(originalMessage.getId()); + + return CometChat.editMessage(editedMessage).then( + (message) => { + // Update local message list + updateMessageInUI(message); + return message; + }, + (error) => { + console.error("Edit failed:", error); + throw error; + } + ); +} - +// Usage +editMessage(selectedMessage, "New message text"); +``` + +--- -In order to edit a message, you need to be either the sender of the message or the admin/moderator of the group in which the message was sent. +## Next Steps - + + + Remove messages from conversations + + + Send new messages + + diff --git a/sdk/javascript/flag-message.mdx b/sdk/javascript/flag-message.mdx index 350149f5..11463d35 100644 --- a/sdk/javascript/flag-message.mdx +++ b/sdk/javascript/flag-message.mdx @@ -2,10 +2,33 @@ title: "Flag Message" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Get available flag reasons +const reasons = await CometChat.getFlagReasons(); +// Returns: [{ id: "spam", reason: "Spam" }, { id: "harassment", reason: "Harassment" }, ...] + +// Flag a message +await CometChat.flagMessage(messageId, { + reasonId: "spam", // Required: from getFlagReasons() + remark: "Optional additional context" +}); + +// Flagged messages appear in Dashboard > Moderation > Flagged Messages +``` + + ## Overview Flagging messages allows users to report inappropriate content to moderators or administrators. When a message is flagged, it appears in the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Flagged Messages** for review. + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | Dashboard + + For a complete understanding of how flagged messages are reviewed and managed, see the [Flagged Messages](/moderation/flagged-messages) documentation. @@ -72,6 +95,20 @@ Before flagging a message, retrieve the list of available flag reasons configure ); ``` + + ```javascript + const getFlagReasons = async () => { + try { + const reasons = await CometChat.getFlagReasons(); + console.log("Flag reasons retrieved:", reasons); + // reasons is an array of { id, reason } objects + // Use these to populate your report dialog UI + } catch (error) { + console.log("Failed to get flag reasons:", error); + } + }; + ``` + ### Response @@ -130,6 +167,24 @@ To flag a message, use the `flagMessage()` method with the message ID and a payl ); ``` + + ```javascript + const flagMessage = async () => { + try { + const messageId = "MESSAGE_ID_TO_FLAG"; + const payload = { + reasonId: "spam", // Required: ID from getFlagReasons() + remark: "This message contains promotional content" // Optional + }; + + const response = await CometChat.flagMessage(messageId, payload); + console.log("Message flagged successfully:", response); + } catch (error) { + console.log("Message flagging failed:", error); + } + }; + ``` + ### Parameters @@ -218,3 +273,15 @@ if (result.success) { showToast("Message reported successfully"); } ``` + + +## Next Steps + + + + Automate content moderation with AI + + + Remove messages from conversations + + diff --git a/sdk/javascript/group-add-members.mdx b/sdk/javascript/group-add-members.mdx index 98170bf0..4433b1db 100644 --- a/sdk/javascript/group-add-members.mdx +++ b/sdk/javascript/group-add-members.mdx @@ -1,135 +1,184 @@ --- -title: "Add Members To A Group" +title: "Add Members to a Group" +sidebarTitle: "Add Members" +description: "Add new members to an existing group" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Add members with different scopes +const members = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.MODERATOR), + new CometChat.GroupMember("user3", CometChat.GROUP_MEMBER_SCOPE.ADMIN) +]; +const banMembers = []; // Optional: UIDs to ban +await CometChat.addMembersToGroup("group_guid", members, banMembers); + +// Listen for member added events +CometChat.addGroupListener("LISTENER", new CometChat.GroupListener({ + onMemberAddedToGroup: (msg, userAdded, userAddedBy, group) => { + console.log(userAddedBy.getName(), "added", userAdded.getName()); + } +})); +``` + + +Add users to a group as participants, moderators, or admins. + + +**Availability**: SDK, API, UI Kits -## Add Members to Group +Only admins and moderators can add members to a group. + -You can add members to the group using the `addMembersToGroup()` method. This method takes the below parameters: +--- -1. `GUID` - GUID of the group the members are to be added to. -2. `members` - This is a list of `GroupMember` objects. In order to add members, you need to create an object of the `GroupMember` class. The UID and the scope of the `GroupMember` are mandatory. -3. `bannedMembers` - This is the list of `UID's` that need to be banned from the Group. This can be set to `null` if there are no members to be banned. +## Add Members - + ```javascript -let GUID = "GUID"; -let UID = "UID"; -let membersList = [ - new CometChat.GroupMember(UID, CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT), +const GUID = "group-123"; + +const members = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.MODERATOR), + new CometChat.GroupMember("user3", CometChat.GROUP_MEMBER_SCOPE.ADMIN) ]; -CometChat.addMembersToGroup(GUID, membersList, []).then( +const banMembers = []; // UIDs to ban (optional) + +CometChat.addMembersToGroup(GUID, members, banMembers).then( (response) => { - console.log("response", response); + console.log("Members added:", response); + // { user1: "success", user2: "success", user3: "success" } }, - (error) => { - console.log("Something went wrong", error); - } + (error) => console.log("Failed:", error) ); ``` - - ```typescript -let GUID: string = "GUID"; -let UID: string = "UID"; -let membersList: CometChat.GroupMember[] = [ - new CometChat.GroupMember(UID, CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT), +const GUID: string = "group-123"; + +const members: CometChat.GroupMember[] = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.MODERATOR) ]; -CometChat.addMembersToGroup(GUID, membersList, []).then( - (response: Object) => { - console.log("response", response); - }, - (error: CometChat.CometChatException) => { - console.log("Something went wrong", error); - } +const banMembers: string[] = []; + +CometChat.addMembersToGroup(GUID, members, banMembers).then( + (response: Object) => console.log("Members added:", response), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - + +```javascript +const addMembers = async () => { + try { + const GUID = "group-123"; + + const members = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.MODERATOR), + new CometChat.GroupMember("user3", CometChat.GROUP_MEMBER_SCOPE.ADMIN) + ]; + + const banMembers = []; // UIDs to ban (optional) + + const response = await CometChat.addMembersToGroup(GUID, members, banMembers); + console.log("Members added:", response); + // { user1: "success", user2: "success", user3: "success" } + } catch (error) { + console.log("Failed:", error); + } +}; +``` + -It will return a Array which will contain the `UID` of the users and the value will either be `success` or an error message describing why the operation to add the user to the group. - -## Real-Time Group Member Added Events +### Member Scopes -*In other words, as a member of a group, how do I know when someone is added to the group when my app is running?* +| Scope | Description | +|-------|-------------| +| `PARTICIPANT` | Regular member | +| `MODERATOR` | Can manage participants | +| `ADMIN` | Full control | - +--- -When a group member is added by another member, this event is triggered. When a user joins a group on their own, the joined event is triggered. +## Add and Ban in One Call - +Add some users while banning others: -To receive real-time events whenever a new member is added to a group, you need to implement the `onMemberAddedToGroup()` methods of the `GroupListener` class. +```javascript +const GUID = "group-123"; -`onMemberAddedToGroup()` - This method is triggered when any user is added to the group so that the logged in user is informed of the other members added to the group. +const members = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT) +]; - - -```javascript -var listenerID = "UNIQUE_LISTENER_ID"; +const banMembers = ["user4", "user5"]; // UIDs to ban -CometChat.addGroupListener( - listenerID, - new CometChat.GroupListener({ - onMemberAddedToGroup: (message, userAdded, userAddedBy, userAddedIn) => { - console.log("User joined", { - message, - userAdded, - userAddedBy, - userAddedIn, - }); - }, - }) +CometChat.addMembersToGroup(GUID, members, banMembers).then( + (response) => console.log("Result:", response), + (error) => console.log("Failed:", error) ); ``` - +--- - -```typescript -var listenerID: string = "UNIQUE_LISTENER_ID"; +## Real-Time Member Added Events + +Listen for when members are added: + +```javascript +const listenerID = "GROUP_LISTENER"; CometChat.addGroupListener( listenerID, new CometChat.GroupListener({ - onMemberAddedToGroup: ( - message: CometChat.Action, - userAdded: CometChat.User, - userAddedBy: CometChat.User, - userAddedIn: CometChat.Group - ) => { - console.log("User joined", { - message, - userAdded, - userAddedBy, - userAddedIn, - }); - }, + onMemberAddedToGroup: (message, userAdded, userAddedBy, userAddedIn) => { + console.log(`${userAddedBy.getName()} added ${userAdded.getName()}`); + } }) ); + +// Remove listener when done +CometChat.removeGroupListener(listenerID); ``` - +--- - +## Missed Member Added Events -## Member Added to Group event in Message History +When fetching message history, member additions appear as `Action` messages: -*In other words, as a member of a group, how do I know when someone is added to the group when my app is not running?* +```javascript +messages.forEach((message) => { + if (message.getCategory() === "action" && message.getAction() === "added") { + const addedUser = message.getActionOn(); + const addedBy = message.getActionBy(); + console.log(`${addedBy.getName()} added ${addedUser.getName()}`); + } +}); +``` -When you retrieve the list of previous messages if a member has been added to any group that the logged-in user is a member of, the list of messages will contain an `Action` message. An `Action` message is a sub-class of `BaseMessage` class. +--- -For the group member added event, in the `Action` object received, the following fields can help you get the relevant information- +## Next Steps -1. `action` - `added` -2. `actionOn` - User object containing the details of the user who was added to the group -3. `actionBy` - User object containing the details of the user who added the member to the group -4. `actionFor` - Group object containing the details of the group to which the member was added + + + Remove members from a group + + + Update member permissions + + diff --git a/sdk/javascript/group-change-member-scope.mdx b/sdk/javascript/group-change-member-scope.mdx index 422ae34b..4ffb9942 100644 --- a/sdk/javascript/group-change-member-scope.mdx +++ b/sdk/javascript/group-change-member-scope.mdx @@ -1,112 +1,167 @@ --- title: "Change Member Scope" +sidebarTitle: "Change Scope" +description: "Update member permissions in a group" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Change member scope (admin only) +await CometChat.updateGroupMemberScope( + "group_guid", + "user_uid", + CometChat.GROUP_MEMBER_SCOPE.MODERATOR // ADMIN, MODERATOR, or PARTICIPANT +); + +// Scopes: ADMIN (full control) > MODERATOR (manage members) > PARTICIPANT (basic) + +// Listen for scope changes +CometChat.addGroupListener("LISTENER", new CometChat.GroupListener({ + onGroupMemberScopeChanged: (msg, user, newScope, oldScope, group) => { + console.log(user.getName(), "changed from", oldScope, "to", newScope); + } +})); +``` + + +Change a member's scope to promote or demote them within a group. -## Change Scope of a Group Member + +**Availability**: SDK, API, UI Kits -In order to change the scope of a group member, you can use the `changeGroupMemberScope()`. +Only admins can change member scopes. + + +--- + +## Member Scopes + +| Scope | Permissions | +|-------|-------------| +| `ADMIN` | Full control - manage group, members, and settings | +| `MODERATOR` | Can manage participants, kick/ban members | +| `PARTICIPANT` | Regular member - send/receive messages | + +--- + +## Change Scope - + ```javascript -let GUID = "GUID"; -let UID = "UID"; -let scope = CometChat.GROUP_MEMBER_SCOPE.ADMIN; - -CometChat.updateGroupMemberScope(GUID, UID, scope).then( -response => { - console.log("Group member scopped changed", response); -}, error => { - console.log("Group member scopped changed failed", error); -} +const GUID = "group-123"; +const UID = "user1"; +const newScope = CometChat.GROUP_MEMBER_SCOPE.MODERATOR; + +CometChat.updateGroupMemberScope(GUID, UID, newScope).then( + (response) => console.log("Scope updated:", response), + (error) => console.log("Failed:", error) ); ``` - - ```typescript -let GUID: string = "GUID"; -let UID: string = "UID"; - +const GUID: string = "group-123"; +const UID: string = "user1"; +const newScope: string = CometChat.GROUP_MEMBER_SCOPE.MODERATOR; -CometChat.updateGroupMemberScope(GUID, UID, CometChat.GroupMemberScope.Admin).then( - (response: boolean) => { - console.log("Group member scopped changed", response); - }, (error: CometChat.CometChatException) => { - console.log("Group member scopped changed failed", error); - } +CometChat.updateGroupMemberScope(GUID, UID, newScope).then( + (response: boolean) => console.log("Scope updated:", response), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - + +```javascript +const changeMemberScope = async () => { + try { + const GUID = "group-123"; + const UID = "user1"; + const newScope = CometChat.GROUP_MEMBER_SCOPE.MODERATOR; + + const response = await CometChat.updateGroupMemberScope(GUID, UID, newScope); + console.log("Scope updated:", response); + } catch (error) { + console.log("Failed:", error); + } +}; +``` + -This method takes the below parameters: +### Promote to Admin -| Parameter | Description | -| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `UID` | The UID of the member whose scope you would like to change | -| `GUID` | The GUID of the group for which the member's scope needs to be changed | -| `scope` | The updated scope of the member. This can be either of the 3 values: 1.`CometChat.SCOPE.ADMIN`2.`CometChat.SCOPE.MODERATOR` 3.`CometChat.SCOPE.PARTICIPANT` | - -The default scope of any member is `participant`. Only the **Admin** of the group can change the scope of any participant in the group. - -## Real-Time Group Member Scope Changed Events - -*In other words, as a member of a group, how do I know when someone's scope is changed when my app is running?* +```javascript +CometChat.updateGroupMemberScope( + "group-123", + "user1", + CometChat.GROUP_MEMBER_SCOPE.ADMIN +); +``` -In order to receive real-time events for the change member scope event, you will need to override the `onGroupMemberScopeChanged()` method of the `GroupListener` class +### Demote to Participant - - ```javascript -let listenerID = "UNIQUE_LISTENER_ID"; - -CometChat.addGroupListener( -listenerID, -new CometChat.GroupListener({ - onGroupMemberScopeChanged: (message, changedUser, newScope, oldScope, changedGroup) => { - console.log("User joined", {message, changedUser, newScope, oldScope, changedGroup}); - } -}) +CometChat.updateGroupMemberScope( + "group-123", + "user1", + CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT ); ``` - +--- - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +## Real-Time Scope Change Events + +Listen for scope changes: + +```javascript +const listenerID = "GROUP_LISTENER"; CometChat.addGroupListener( listenerID, new CometChat.GroupListener({ - onGroupMemberScopeChanged: (message: CometChat.Action, changedUser: CometChat.User, newScope: string, oldScope: string, changedGroup: CometChat.Group) => { - console.log("User joined", { message, changedUser, newScope, oldScope, changedGroup }); - } + onGroupMemberScopeChanged: (message, changedUser, newScope, oldScope, changedGroup) => { + console.log(`${changedUser.getName()} scope changed from ${oldScope} to ${newScope}`); + } }) ); + +// Remove listener when done +CometChat.removeGroupListener(listenerID); ``` - +--- - +## Missed Scope Change Events -## Missed Group Member Scope Changed Events +When fetching message history, scope changes appear as `Action` messages: -*In other words, as a member of a group, how do I know when someone's scope is changed when my app is not running?* +```javascript +messages.forEach((message) => { + if (message.getCategory() === "action" && message.getAction() === "scopeChanged") { + const user = message.getActionOn(); + const by = message.getActionBy(); + const oldScope = message.getOldScope(); + const newScope = message.getNewScope(); + + console.log(`${by.getName()} changed ${user.getName()} from ${oldScope} to ${newScope}`); + } +}); +``` -When you retrieve the list of previous messages if a member's scope has been changed for any group that the logged-in user is a member of, the list of messages will contain an `Action` message. An `Action` message is a sub-class of `BaseMessage` class. +--- -For the group member scope changed event, in the `Action` object received, the following fields can help you get the relevant information- +## Next Steps -1. `action` - `scopeChanged` -2. `actionOn` - User object containing the details of the user whose scope has been changed -3. `actionBy` - User object containing the details of the user who changed the scope of the member -4. `actionFor` - Group object containing the details of the group in which the member scope was changed -5. `oldScope` - The original scope of the member -6. `newScope` - The updated scope of the member + + + Transfer group ownership + + + Remove members from a group + + diff --git a/sdk/javascript/group-kick-ban-members.mdx b/sdk/javascript/group-kick-ban-members.mdx index 7433686c..6813eb72 100644 --- a/sdk/javascript/group-kick-ban-members.mdx +++ b/sdk/javascript/group-kick-ban-members.mdx @@ -1,357 +1,323 @@ --- -title: "Ban Or Kick Member From A Group" +title: "Kick & Ban Members" +sidebarTitle: "Kick/Ban Members" +description: "Remove members from a group temporarily or permanently" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Kick member (can rejoin) +await CometChat.kickGroupMember("group_guid", "user_uid"); + +// Ban member (cannot rejoin until unbanned) +await CometChat.banGroupMember("group_guid", "user_uid"); + +// Unban member +await CometChat.unbanGroupMember("group_guid", "user_uid"); + +// Get banned members list +const bannedRequest = new CometChat.BannedMembersRequestBuilder("group_guid") + .setLimit(30) + .build(); +const bannedMembers = await bannedRequest.fetchNext(); + +// Listen for kick/ban events +CometChat.addGroupListener("LISTENER", new CometChat.GroupListener({ + onGroupMemberKicked: (msg, kickedUser, kickedBy, group) => {}, + onGroupMemberBanned: (msg, bannedUser, bannedBy, group) => {}, + onGroupMemberUnbanned: (msg, unbannedUser, unbannedBy, group) => {} +})); +``` + -There are certain actions that can be performed on the group members: +Remove members from a group by kicking (temporary) or banning (permanent until unbanned). -1. Kick a member from the group -2. Ban a member from the group -3. Unban a member from the group -4. Update the scope of the member of the group + +**Availability**: SDK, API, UI Kits -All the above actions can only be performed by the **Admin** or the **Moderator** of the group. +Only admins and moderators can kick or ban members. + + +--- -## Kick a Group Member +## Kick vs Ban -The Admin or Moderator of a group can kick a member out of the group using the `kickGroupMember()` method. +| Action | Description | +|--------|-------------| +| Kick | Removes member, but they can rejoin | +| Ban | Removes member, cannot rejoin until unbanned | + +--- + +## Kick a Member + +Remove a member who can rejoin later: - + ```javascript -var GUID = "GUID"; -var UID = "UID"; +const GUID = "group-123"; +const UID = "user1"; CometChat.kickGroupMember(GUID, UID).then( -response => { - console.log("Group member kicked successfully", response); -}, error => { - console.log("Group member kicking failed with error", error); -} + (response) => console.log("Member kicked:", response), + (error) => console.log("Failed:", error) ); ``` - - ```typescript -let GUID: string = "GUID"; -let UID: string = "UID"; +const GUID: string = "group-123"; +const UID: string = "user1"; CometChat.kickGroupMember(GUID, UID).then( - (response: Object) => { - console.log("Group member kicked successfully", response); - }, (error: CometChat.CometChatException) => { - console.log("Group member kicking failed with error", error); - } + (response: Object) => console.log("Member kicked:", response), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - + +```javascript +const kickMember = async () => { + try { + const GUID = "group-123"; + const UID = "user1"; + const response = await CometChat.kickGroupMember(GUID, UID); + console.log("Member kicked:", response); + } catch (error) { + console.log("Failed:", error); + } +}; +``` + -The `kickGroupMember()` takes following parameters - -| Parameter | Description | -| --------- | ----------------------------------------------------- | -| `UID` | The UID of the user to be kicked. | -| `GUID` | The GUID of the group from which user is to be kicked | - -The kicked user will be no longer part of the group and can not perform any actions in the group, but the kicked user can rejoin the group. +--- -## Ban a Group Member +## Ban a Member -The Admin or Moderator of the group can ban a member from the group using the `banGroupMember()` method. +Permanently remove a member until unbanned: - + ```javascript -var GUID = "GUID"; -var UID = "UID"; +const GUID = "group-123"; +const UID = "user1"; CometChat.banGroupMember(GUID, UID).then( -response => { - console.log("Group member banned successfully", response); -}, error => { - console.log("Group member banning failed with error", error); -} -); + (response) => console.log("Member banned:", response), + (error) => console.log("Failed:", error) +); ``` - - ```typescript -let GUID: string = "GUID"; -let UID: string = "UID"; +const GUID: string = "group-123"; +const UID: string = "user1"; CometChat.banGroupMember(GUID, UID).then( - (response: Object) => { - console.log("Group member banned successfully", response); - }, (error: CometChat.CometChatException) => { - console.log("Group member banning failed with error", error); - } + (response: Object) => console.log("Member banned:", response), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - + +```javascript +const banMember = async () => { + try { + const GUID = "group-123"; + const UID = "user1"; + const response = await CometChat.banGroupMember(GUID, UID); + console.log("Member banned:", response); + } catch (error) { + console.log("Failed:", error); + } +}; +``` + -The `banGroupMember()` method takes the following parameters: - -| Parameter | Description | -| --------- | ------------------------------------------------------ | -| `UID` | The UID of the user to be banned. | -| `GUID` | The GUID of the group from which user is to be banned. | - -The banned user will be no longer part of the group and can not perform any actions in the group. A banned user cannot rejoin the same group without being unbanned. +--- -## Unban a Banned Group Member from a Group +## Unban a Member -Only Admin or Moderators of the group can unban a previously banned member from the group using the `unbanGroupMember()` method. +Allow a banned member to rejoin: - + ```javascript -var GUID = "GUID"; -var UID = "UID"; +const GUID = "group-123"; +const UID = "user1"; CometChat.unbanGroupMember(GUID, UID).then( -response => { - console.log("Group member unbanned successfully", response); -}, error => { - console.log("Group member unbanning failed with error", error); -} -); + (response) => console.log("Member unbanned:", response), + (error) => console.log("Failed:", error) +); ``` - - ```typescript -let GUID: string = "GUID"; -let UID: string = "UID"; +const GUID: string = "group-123"; +const UID: string = "user1"; CometChat.unbanGroupMember(GUID, UID).then( - (response: Object) => { - console.log("Group member unbanned successfully", response); - }, (error: CometChat.CometChatException) => { - console.log("Group member unbanning failed with error", error); - } + (response: Object) => console.log("Member unbanned:", response), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - + +```javascript +const unbanMember = async () => { + try { + const GUID = "group-123"; + const UID = "user1"; + const response = await CometChat.unbanGroupMember(GUID, UID); + console.log("Member unbanned:", response); + } catch (error) { + console.log("Failed:", error); + } +}; +``` + -The `unbanGroupMember()` method takes the following parameters - -| Parameter | Description | -| --------- | ---------------------------------------------------- | -| `UID` | The UID of the user to be unbanned. | -| `GUID` | The UID of the group from which user is to be banned | - -The unbanned user can now rejoin the group. - -## Get List of Banned Members for a Group - -In order to fetch the list of banned groups members for a group, you can use the `BannedGroupMembersRequest` class. To use this class i.e to create an object of the BannedGroupMembersRequest class, you need to use the `BannedGroupMembersRequestBuilder` class. The `BannedGroupMembersRequestBuilder` class allows you to set the parameters based on which the banned group members are to be fetched. - -The `BannedGroupMembersRequestBuilder` class allows you to set the below parameters: - -The `GUID` of the group for which the banned members are to be fetched must be specified in the constructor of the `GroupMembersRequestBuilder` class. +--- -### Set Limit +## Get Banned Members -This method sets the limit i.e. the number of banned members that should be fetched in a single iteration. +Fetch the list of banned members: - + ```javascript -let GUID = "GUID"; -let limit = 30; -let bannedGroupMembersRequest = new CometChat.BannedMembersRequestBuilder(GUID) - .setLimit(limit) - .build(); -``` - - +const GUID = "group-123"; +const limit = 30; - -```typescript -let GUID: string = "GUID"; -let limit: number = 30; -let bannedGroupMembersRequest: CometChat.BannedMembersRequest = new CometChat.BannedMembersRequestBuilder(GUID) +const bannedRequest = new CometChat.BannedMembersRequestBuilder(GUID) .setLimit(limit) .build(); -``` - - - - -### Set Search Keyword - -This method allows you to set the search string based on which the banned group members are to be fetched. - - - -```javascript -let GUID = "GUID"; -let limit = 30; -let searchKeyword = "super"; -let bannedGroupMembersRequest = new CometChat.BannedMembersRequestBuilder(GUID) - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); +bannedRequest.fetchNext().then( + (bannedMembers) => console.log("Banned members:", bannedMembers), + (error) => console.log("Failed:", error) +); ``` - - ```typescript -let GUID: string = "GUID"; -let limit: number = 30; -let searchKeyword: string = "super"; -let bannedGroupMembersRequest: CometChat.BannedMembersRequest = new CometChat.BannedMembersRequestBuilder(GUID) - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); -``` - - - - - -Finally, once all the parameters are set to the builder class, you need to call the build() method to get the object of the `BannedGroupMembersRequest` class. +const GUID: string = "group-123"; +const limit: number = 30; -Once you have the object of the `BannedGroupMembersRequest` class, you need to call the `fetchNext()` method. Calling this method will return a list of `GroupMember` objects containing n number of banned members where n is the limit set in the builder class. +const bannedRequest: CometChat.BannedMembersRequest = + new CometChat.BannedMembersRequestBuilder(GUID) + .setLimit(limit) + .build(); - - -```javascript -let GUID = "GUID"; -let limit = 30; -let bannedMembersRequest = new CometChat.BannedMembersRequestBuilder(GUID) - .setLimit(limit) - .build(); - -bannedMembersRequest.fetchNext().then( -bannedMembers => { - console.log("Banned Group Member list fetched successfully:", bannedMembers); -}, error => { - console.log("Banned Group Member list fetching failed with exception:", error); -} +bannedRequest.fetchNext().then( + (bannedMembers: CometChat.GroupMember[]) => console.log("Banned:", bannedMembers), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - - -```typescript -let GUID: string = "GUID"; -let limit: number = 30; -let bannedGroupMembersRequest: CometChat.BannedMembersRequest = new CometChat.BannedMembersRequestBuilder(GUID) - .setLimit(limit) - .build(); - -bannedGroupMembersRequest.fetchNext().then( - (bannedMembers: CometChat.GroupMember[]) => { - console.log("Banned Group Member list fetched successfully:", bannedMembers); - }, (error: CometChat.CometChatException) => { - console.log("Banned Group Member list fetching failed with exception:", error); + +```javascript +const getBannedMembers = async () => { + try { + const GUID = "group-123"; + const limit = 30; + + const bannedRequest = new CometChat.BannedMembersRequestBuilder(GUID) + .setLimit(limit) + .build(); + + const bannedMembers = await bannedRequest.fetchNext(); + console.log("Banned members:", bannedMembers); + } catch (error) { + console.log("Failed:", error); } -); +}; ``` - - -## Real-Time Group Member Kicked/Banned Events - -*In other words, as a member of a group, how do I know when someone is banned/kicked when my app is running?* - -In order to get real-time events for the kick/ban/unban group members you need to override the following methods of the `GroupListener` class. +### Search Banned Members -1. `onGroupMemberKicked()` - triggered when any group member has been kicked. -2. `onGroupMemberBanned()` - triggered when any group member has been banned. -3. `onGroupMemberUnbanned()` - triggered when any group member has been unbanned. - - - ```javascript -let listenerID = "UNIQUE_LISTENER_ID"; - -CometChat.addGroupListener( -listenerID, -new CometChat.GroupListener({ - onGroupMemberKicked: (message, kickedUser, kickedBy, kickedFrom) => { - console.log("User kicked", { message, kickedUser, kickedBy, kickedFrom }); - }, - onGroupMemberBanned: (message, bannedUser, bannedBy, bannedFrom) => { - console.log("User banned", { message, bannedUser, bannedBy, bannedFrom }); - }, - onGroupMemberUnbanned: (message, unbannedUser, unbannedBy,unbannedFrom) => { - console.log("User unbanned", {message, unbannedUser, unbannedBy, unbannedFrom}); - } -}) -); +const bannedRequest = new CometChat.BannedMembersRequestBuilder("group-123") + .setLimit(30) + .setSearchKeyword("john") + .build(); ``` - +--- - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +## Real-Time Events + +Listen for kick, ban, and unban events: + +```javascript +const listenerID = "GROUP_LISTENER"; CometChat.addGroupListener( listenerID, new CometChat.GroupListener({ - onGroupMemberKicked: (message: CometChat.Action, kickedUser: CometChat.User, kickedBy: CometChat.User, kickedFrom: CometChat.Group) => { - console.log("User kicked", { message, kickedUser, kickedBy, kickedFrom }); - }, - onGroupMemberBanned: (message: CometChat.Action, bannedUser: CometChat.User, bannedBy: CometChat.User, bannedFrom: CometChat.Group) => { - console.log("User banned", { message, bannedUser, bannedBy, bannedFrom }); - }, - onGroupMemberUnbanned: (message: CometChat.Action, unbannedUser: CometChat.User, unbannedBy: CometChat.User, unbannedFrom: CometChat.Group) => { - console.log("User unbanned", { message, unbannedUser, unbannedBy, unbannedFrom }); - } + onGroupMemberKicked: (message, kickedUser, kickedBy, kickedFrom) => { + console.log(`${kickedBy.getName()} kicked ${kickedUser.getName()}`); + }, + onGroupMemberBanned: (message, bannedUser, bannedBy, bannedFrom) => { + console.log(`${bannedBy.getName()} banned ${bannedUser.getName()}`); + }, + onGroupMemberUnbanned: (message, unbannedUser, unbannedBy, unbannedFrom) => { + console.log(`${unbannedBy.getName()} unbanned ${unbannedUser.getName()}`); + } }) ); -``` - - - - -## Missed Group Member Kicked/Banned Events - -*In other words, as a member of a group, how do I know when someone is banned/kicked when my app is not running?* +// Remove listener when done +CometChat.removeGroupListener(listenerID); +``` -When you retrieve the list of previous messages if a member has been kicked/banned/unbanned from any group that the logged-in user is a member of, the list of messages will contain an `Action` message. An `Action` message is a sub-class of `BaseMessage` class. +--- -For group member kicked event, the details can be obtained using the below fields of the `Action` class- +## Missed Events in Message History -1. `action` - `kicked` -2. `actionBy` - User object containing the details of the user who has kicked the member -3. `actionOn` - User object containing the details of the member that has been kicked -4. `actionFor` - Group object containing the details of the Group from which the member was kicked +When fetching messages, kick/ban/unban events appear as `Action` messages: -For group member banned event, the details can be obtained using the below fields of the `Action` class- +```javascript +messages.forEach((message) => { + if (message.getCategory() === "action") { + const action = message.getAction(); + const user = message.getActionOn(); + const by = message.getActionBy(); + + switch (action) { + case "kicked": + console.log(`${by.getName()} kicked ${user.getName()}`); + break; + case "banned": + console.log(`${by.getName()} banned ${user.getName()}`); + break; + case "unbanned": + console.log(`${by.getName()} unbanned ${user.getName()}`); + break; + } + } +}); +``` -1. `action` - `banned` -2. `actionBy` - User object containing the details of the user who has banned the member -3. `actionOn` - User object containing the details of the member that has been banned -4. `actionFor` - Group object containing the details of the Group from which the member was banned +--- -For group member unbanned event, the details can be obtained using the below fields of the `Action` class- +## Next Steps -1. `action` - `unbanned` -2. `actionBy` - User object containing the details of the user who has unbanned the member -3. `actionOn` - User object containing the details of the member that has been unbanned -4. `actionFor` - Group object containing the details of the Group from which the member was unbanned + + + Add members to a group + + + Update member permissions + + diff --git a/sdk/javascript/groups-overview.mdx b/sdk/javascript/groups-overview.mdx index 4f3d1c36..1432b47c 100644 --- a/sdk/javascript/groups-overview.mdx +++ b/sdk/javascript/groups-overview.mdx @@ -1,10 +1,477 @@ --- title: "Groups" sidebarTitle: "Overview" +description: "Create and manage group conversations in your chat application" --- +{/* Agent-Friendly Quick Reference */} + +**Quick Reference** +```javascript +// Create a group +const group = new CometChat.Group("GUID", "Group Name", CometChat.GROUP_TYPE.PUBLIC); +await CometChat.createGroup(group); -Groups help your users to converse together in a single space. You can have three types of groups- private, public and password protected. +// Join a group +await CometChat.joinGroup("GUID", CometChat.GROUP_TYPE.PUBLIC, ""); -Each group includes three kinds of users- owner, moderator, member. +// Send message to group +const msg = new CometChat.TextMessage("GUID", "Hello!", CometChat.RECEIVER_TYPE.GROUP); +await CometChat.sendMessage(msg); + +// Fetch groups +const request = new CometChat.GroupsRequestBuilder().setLimit(30).build(); +const groups = await request.fetchNext(); + +// Leave group +await CometChat.leaveGroup("GUID"); +``` + +**Group Types:** `PUBLIC` (open), `PASSWORD` (requires password), `PRIVATE` (invite only) +**Member Scopes:** `ADMIN` > `MODERATOR` > `PARTICIPANT` + + +Groups enable multiple users to communicate together. CometChat supports public, private, and password-protected groups with role-based member management. + + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + + +--- + +## Group Types + +| Type | Visibility | How to Join | +|------|------------|-------------| +| **Public** | Visible to all users | Anyone can join freely | +| **Password** | Visible to all users | Requires correct password | +| **Private** | Only visible to members | Invitation only (auto-joined) | + +```javascript +// Group type constants +CometChat.GROUP_TYPE.PUBLIC +CometChat.GROUP_TYPE.PASSWORD +CometChat.GROUP_TYPE.PRIVATE +``` + +--- + +## Member Scopes + +| Scope | Capabilities | +|-------|-------------| +| **Admin** | Full control: manage all members, update/delete group, change any scope | +| **Moderator** | Moderate: kick/ban participants, update group info | +| **Participant** | Basic: send/receive messages and calls | + +```javascript +// Scope constants +CometChat.GROUP_MEMBER_SCOPE.ADMIN +CometChat.GROUP_MEMBER_SCOPE.MODERATOR +CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT +``` + + +The group creator is automatically assigned as Admin. + + +--- + +## Quick Start + +### Create a Group + + + +```javascript +const GUID = "group_" + Date.now(); +const groupName = "My Group"; +const groupType = CometChat.GROUP_TYPE.PUBLIC; + +const group = new CometChat.Group(GUID, groupName, groupType); + +CometChat.createGroup(group).then( + (group) => console.log("Group created:", group), + (error) => console.log("Error:", error) +); +``` + + +```javascript +async function createGroup() { + const GUID = "group_" + Date.now(); + const groupName = "My Group"; + const groupType = CometChat.GROUP_TYPE.PUBLIC; + + const group = new CometChat.Group(GUID, groupName, groupType); + + try { + const createdGroup = await CometChat.createGroup(group); + console.log("Group created:", createdGroup); + return createdGroup; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Fetch Groups + + + +```javascript +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .build(); + +groupsRequest.fetchNext().then( + (groups) => console.log("Groups:", groups), + (error) => console.log("Error:", error) +); +``` + + +```javascript +async function fetchGroups() { + const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .build(); + + try { + const groups = await groupsRequest.fetchNext(); + console.log("Groups:", groups); + return groups; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +--- + +## Group Management + + + + Fetch and search groups + + + Create new groups with members + + + Modify group settings + + + Remove groups permanently + + + +--- + +## Membership + + + + Join public or password groups + + + Exit a group + + + List group members + + + Add users to a group + + + +--- + +## Member Management + + + + Remove or ban users from groups + + + Promote or demote members + + + Transfer admin rights + + + +--- + +## Group Object Properties + +| Property | Method | Description | Editable | +|----------|--------|-------------|----------| +| GUID | `getGuid()` | Unique identifier | No (set at creation) | +| Name | `getName()` | Group name | Yes | +| Type | `getType()` | public, password, private | No | +| Icon | `getIcon()` | Group image URL | Yes | +| Description | `getDescription()` | Group description | Yes | +| Owner | `getOwner()` | UID of group owner | Yes | +| Metadata | `getMetadata()` | Custom JSON data | Yes | +| Members Count | `getMembersCount()` | Number of members | No | +| Has Joined | `getHasJoined()` | If logged-in user is member | No | +| Joined At | `getJoinedAt()` | When user joined | No | +| Scope | `getScope()` | User's scope in group | Yes | +| Tags | `getTags()` | Array of tags | Yes | +| Created At | `getCreatedAt()` | Creation timestamp | No | + +--- + +## Common Use Cases + +### Create Group with Members + + + +```javascript +const GUID = "team_chat"; +const groupName = "Team Chat"; +const groupType = CometChat.GROUP_TYPE.PRIVATE; + +const group = new CometChat.Group(GUID, groupName, groupType); + +const members = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.ADMIN), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT), + new CometChat.GroupMember("user3", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT) +]; + +CometChat.createGroupWithMembers(group, members, []).then( + (response) => { + console.log("Group created:", response.group); + console.log("Members added:", response.members); + } +); +``` + + +```javascript +async function createGroupWithMembers() { + const GUID = "team_chat"; + const groupName = "Team Chat"; + const groupType = CometChat.GROUP_TYPE.PRIVATE; + + const group = new CometChat.Group(GUID, groupName, groupType); + + const members = [ + new CometChat.GroupMember("user1", CometChat.GROUP_MEMBER_SCOPE.ADMIN), + new CometChat.GroupMember("user2", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT), + new CometChat.GroupMember("user3", CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT) + ]; + + try { + const response = await CometChat.createGroupWithMembers(group, members, []); + console.log("Group created:", response.group); + console.log("Members added:", response.members); + return response; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Join a Public Group + + + +```javascript +const GUID = "public_group"; +const groupType = CometChat.GROUP_TYPE.PUBLIC; + +CometChat.joinGroup(GUID, groupType).then( + (group) => console.log("Joined group:", group), + (error) => console.log("Error:", error) +); +``` + + +```javascript +async function joinPublicGroup(GUID) { + try { + const group = await CometChat.joinGroup(GUID, CometChat.GROUP_TYPE.PUBLIC); + console.log("Joined group:", group); + return group; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Join a Password Group + + + +```javascript +const GUID = "password_group"; +const groupType = CometChat.GROUP_TYPE.PASSWORD; +const password = "secret123"; + +CometChat.joinGroup(GUID, groupType, password).then( + (group) => console.log("Joined group:", group), + (error) => console.log("Error:", error) +); +``` + + +```javascript +async function joinPasswordGroup(GUID, password) { + try { + const group = await CometChat.joinGroup( + GUID, + CometChat.GROUP_TYPE.PASSWORD, + password + ); + console.log("Joined group:", group); + return group; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Search Groups + + + +```javascript +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .setSearchKeyword("team") + .build(); + +groupsRequest.fetchNext().then((groups) => { + console.log("Search results:", groups); +}); +``` + + +```javascript +async function searchGroups(keyword) { + const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .setSearchKeyword(keyword) + .build(); + + try { + const groups = await groupsRequest.fetchNext(); + console.log("Search results:", groups); + return groups; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Filter Joined Groups + + + +```javascript +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .joinedOnly(true) + .build(); + +groupsRequest.fetchNext().then((groups) => { + console.log("My groups:", groups); +}); +``` + + +```javascript +async function fetchJoinedGroups() { + const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .joinedOnly(true) + .build(); + + try { + const groups = await groupsRequest.fetchNext(); + console.log("My groups:", groups); + return groups; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +--- + +## Real-Time Group Events + +Listen for group changes: + +```javascript +const listenerID = "GROUP_LISTENER"; + +CometChat.addGroupListener( + listenerID, + new CometChat.GroupListener({ + onGroupMemberJoined: (message, joinedUser, joinedGroup) => { + console.log(joinedUser.getName(), "joined", joinedGroup.getName()); + }, + onGroupMemberLeft: (message, leftUser, leftGroup) => { + console.log(leftUser.getName(), "left", leftGroup.getName()); + }, + onGroupMemberKicked: (message, kickedUser, kickedBy, kickedFrom) => { + console.log(kickedUser.getName(), "was kicked by", kickedBy.getName()); + }, + onGroupMemberBanned: (message, bannedUser, bannedBy, bannedFrom) => { + console.log(bannedUser.getName(), "was banned"); + }, + onGroupMemberUnbanned: (message, unbannedUser, unbannedBy, unbannedFrom) => { + console.log(unbannedUser.getName(), "was unbanned"); + }, + onGroupMemberScopeChanged: (message, changedUser, newScope, oldScope, changedGroup) => { + console.log(changedUser.getName(), "scope changed to", newScope); + }, + onMemberAddedToGroup: (message, userAdded, userAddedBy, userAddedIn) => { + console.log(userAdded.getName(), "was added by", userAddedBy.getName()); + } + }) +); + +// Remove when done +CometChat.removeGroupListener(listenerID); +``` + +--- + +## Next Steps + + + + Learn all group creation options + + + Fetch and filter groups + + diff --git a/sdk/javascript/guide-calls-only.mdx b/sdk/javascript/guide-calls-only.mdx new file mode 100644 index 00000000..ff037df6 --- /dev/null +++ b/sdk/javascript/guide-calls-only.mdx @@ -0,0 +1,992 @@ +--- +title: "Calls Integration Guide" +sidebarTitle: "Calls Only" +description: "Complete step-by-step guide to integrate voice and video calling without chat" +--- + +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Standalone Calls Integration (No Chat SDK Required) +// 1. Install +npm install @cometchat/calls-sdk-javascript + +// 2. Initialize +await CometChatCalls.init({ appId: "APP_ID", region: "REGION" }); + +// 3. Generate call token (requires user auth token from REST API) +const callToken = await CometChatCalls.generateToken(sessionId, userAuthToken); + +// 4. Start call session +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setCallListener({ onCallEnded: () => CometChatCalls.endSession() }) + .build(); +CometChatCalls.startSession(callToken.token, callSettings, document.getElementById("call-container")); + +// 5. End call +CometChatCalls.endSession(); +``` + + +This guide walks you through integrating CometChat voice and video calling as a standalone feature, without the Chat SDK. This is ideal for applications that only need calling capabilities. + + +**Prerequisites** +- A CometChat account with an app created at [app.cometchat.com](https://app.cometchat.com) +- Your App ID and Region from the dashboard +- Node.js 14+ or a modern browser +- A backend server to generate user auth tokens via REST API + + +--- + +## Step 1: Install the Calls SDK + + + +```bash +npm install @cometchat/calls-sdk-javascript +``` + + +```bash +yarn add @cometchat/calls-sdk-javascript +``` + + +```html + +``` + + + +Import the SDK: + +```javascript +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; +``` + +--- + +## Step 2: Initialize the Calls SDK + +Initialization prepares the Calls SDK to handle audio/video streams. Unlike the Chat SDK, the Calls SDK focuses solely on real-time media communication. + + + +```javascript +// Configuration object for the Calls SDK +// Only requires appId and region - simpler than Chat SDK +const callAppSettings = { + appId: "YOUR_APP_ID", // Your CometChat App ID + region: "YOUR_REGION" // "us" or "eu" - must match your app's region +}; + +// init() prepares the SDK for call operations +// This sets up WebRTC capabilities and validates credentials +CometChatCalls.init(callAppSettings).then( + () => { + console.log("Calls SDK initialized"); + // SDK is ready - you can now generate call tokens + }, + (error) => { + // Common errors: invalid appId, wrong region, network issues + console.log("Calls init failed:", error); + } +); +``` + + +```javascript +async function initCallsSDK() { + const callAppSettings = { + appId: "YOUR_APP_ID", + region: "YOUR_REGION" + }; + + try { + // await ensures SDK is fully initialized before proceeding + await CometChatCalls.init(callAppSettings); + console.log("Calls SDK initialized"); + return true; + } catch (error) { + console.log("Calls init failed:", error); + return false; + } +} +``` + + + +### What This Code Does + +1. **Configures SDK**: Sets your app credentials for authentication +2. **Initializes WebRTC**: Prepares browser capabilities for audio/video +3. **Validates Credentials**: Confirms your app exists and region is correct + +--- + +## Step 3: Get User Auth Token + +Since you're using the Calls SDK standalone (without Chat SDK), you need to authenticate users differently. The Calls SDK requires a user auth token, which must be obtained from CometChat's REST API. + + +Since you're not using the Chat SDK, you must obtain user auth tokens via the CometChat REST API from your backend server. Never expose your REST API key in client-side code. + + +### Option A: Create Auth Token (Server-Side) + +This is the recommended approach for production. Your backend server creates auth tokens securely. + +```javascript +// ⚠️ This code runs on YOUR BACKEND SERVER, not in the browser +// Never expose your REST API key in client-side code + +const APP_ID = "YOUR_APP_ID"; +const REGION = "us"; // or "eu" +const UID = "user_123"; // The user who needs the token + +// Make a POST request to CometChat's REST API +const response = await fetch( + `https://${APP_ID}.api-${REGION}.cometchat.io/v3/users/${UID}/auth_tokens`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "apiKey": "YOUR_REST_API_KEY", // Keep this secret on server + "appId": APP_ID + } + } +); + +const data = await response.json(); +const authToken = data.data.authToken; + +// Send authToken to your client app via your own API +// The client will use this token to generate call tokens +``` + +### Option B: Get from Dashboard (Testing Only) + +For quick testing during development, you can manually create auth tokens: + +1. Navigate to **Users & Groups → Users** +2. Select a user +3. Click **+ Create Auth Token** + + +Dashboard-created tokens are for testing only. In production, always generate tokens programmatically on your server. + + +--- + +## Step 4: Generate Call Token + +A call token authorizes a specific user to join a specific call session. Each participant needs their own call token, but they all use the same session ID to join the same call. + + + +```javascript +// Session ID uniquely identifies this call +// All participants must use the SAME session ID to join the same call +// Generate a unique ID for new calls, or use an existing ID to join +const sessionId = "unique_session_id_" + Date.now(); + +// User auth token from Step 3 (obtained from your backend) +const userAuthToken = "USER_AUTH_TOKEN"; + +// generateToken() creates a call-specific token for this user +// This token authorizes the user to join the specified session +CometChatCalls.generateToken(sessionId, userAuthToken).then( + (callToken) => { + console.log("Call token generated:", callToken.token); + // callToken.token is what you pass to startSession() + // Store sessionId to share with other participants + }, + (error) => { + // Common errors: invalid auth token, expired token + console.log("Token generation failed:", error); + } +); +``` + + +```javascript +async function generateCallToken(sessionId, userAuthToken) { + try { + // generateToken() returns an object with a 'token' property + const callToken = await CometChatCalls.generateToken(sessionId, userAuthToken); + console.log("Call token generated:", callToken.token); + return callToken.token; + } catch (error) { + console.log("Token generation failed:", error); + throw error; + } +} + +// Usage for starting a new call +const sessionId = `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; +const token = await generateCallToken(sessionId, userAuthToken); + +// Usage for joining an existing call +const existingSessionId = "session_id_from_caller"; +const token = await generateCallToken(existingSessionId, userAuthToken); +``` + + + +### What This Code Does + +1. **Creates Session Identifier**: The session ID groups participants into the same call +2. **Generates Secure Token**: The call token authorizes this user for this specific session +3. **Enables Call Join**: The returned token is used to start or join the call session + +| Parameter | Description | +|-----------|-------------| +| `sessionId` | Unique identifier for the call session. All participants joining the same call must use the same session ID. Generate a new one for new calls. | +| `userAuthToken` | The user's auth token obtained from the REST API. Identifies who is joining the call. | + + +**Session ID Strategy**: Generate a unique session ID for each new call. Share this ID with other participants (via your app's UI, push notification, etc.) so they can join the same call. + + +--- + +## Step 5: Configure Call Settings + +Call settings define the behavior and appearance of the call UI, as well as event handlers for call lifecycle events. The `OngoingCallListener` receives real-time updates about participants and call state. + + + +```javascript +// OngoingCallListener handles real-time call events +// These callbacks fire during an active call session +const callListener = new CometChatCalls.OngoingCallListener({ + // Called when another participant joins the call + // user object contains: getName(), getUid(), getAvatar() + onUserJoined: (user) => { + console.log("User joined:", user.getName()); + // Update UI to show new participant + // Add their video stream to the grid + }, + + // Called when a participant leaves the call + // Could be voluntary leave or network disconnection + onUserLeft: (user) => { + console.log("User left:", user.getName()); + // Remove their video from the grid + // Update participant count + }, + + // Called whenever the participant list changes + // userList is an array of all current participants + onUserListUpdated: (userList) => { + console.log("Participants:", userList.length); + // Useful for updating participant count badge + // Or rebuilding the video grid layout + }, + + // Called when the call ends (by any participant or timeout) + // IMPORTANT: You must call endSession() to clean up resources + onCallEnded: () => { + console.log("Call ended"); + CometChatCalls.endSession(); // Required cleanup + // Hide call UI and return to previous screen + }, + + // Called when user clicks the end call button in default UI + // Only fires if using enableDefaultLayout(true) + onCallEndButtonPressed: () => { + console.log("End button pressed"); + CometChatCalls.endSession(); + // Navigate away from call screen + }, + + // Called when a call error occurs + // Common errors: network issues, permission denied, device unavailable + onError: (error) => { + console.log("Call error:", error); + // Show error message to user + // Consider ending the call on critical errors + }, + + // Called when available audio output devices change + // audioModes array contains available speakers/headphones + onAudioModesUpdated: (audioModes) => { + console.log("Audio modes:", audioModes); + // Update audio device selector UI + }, + + // Called when any participant mutes/unmutes + // event contains: user, muted (boolean) + onUserMuted: (event) => { + console.log("User muted:", event); + // Show mute indicator on participant's video + }, + + // Called when any participant starts screen sharing + onScreenShareStarted: () => { + console.log("Screen share started"); + // Adjust layout to show screen share prominently + }, + + // Called when screen sharing stops + onScreenShareStopped: () => { + console.log("Screen share stopped"); + // Return to normal video grid layout + } +}); + +// CallSettingsBuilder configures the call UI and behavior +// Chain methods to customize, then call build() to create settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) // Use CometChat's built-in call UI + .setIsAudioOnlyCall(false) // false = video call, true = audio only + .setCallListener(callListener) // Attach our event handlers + .build(); // Create the settings object +``` + + +```javascript +// Create a reusable function to build call settings +function createCallSettings(options = {}) { + const { + isAudioOnly = false, + startMuted = false, + startVideoOff = false, + onUserJoined, + onUserLeft, + onCallEnded, + onError + } = options; + + // Create listener with provided callbacks or defaults + const callListener = new CometChatCalls.OngoingCallListener({ + onUserJoined: onUserJoined || ((user) => { + console.log("User joined:", user.getName()); + }), + onUserLeft: onUserLeft || ((user) => { + console.log("User left:", user.getName()); + }), + onCallEnded: onCallEnded || (() => { + console.log("Call ended"); + CometChatCalls.endSession(); + }), + onCallEndButtonPressed: () => { + CometChatCalls.endSession(); + onCallEnded?.(); + }, + onError: onError || ((error) => { + console.error("Call error:", error); + }) + }); + + // Build settings with provided options + return new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIsAudioOnlyCall(isAudioOnly) + .startWithAudioMuted(startMuted) + .startWithVideoMuted(startVideoOff) + .setCallListener(callListener) + .build(); +} + +// Usage +const settings = createCallSettings({ + isAudioOnly: false, + startMuted: false, + onUserJoined: (user) => updateParticipantList(user, 'joined'), + onUserLeft: (user) => updateParticipantList(user, 'left'), + onCallEnded: () => navigateToHome(), + onError: (error) => showErrorToast(error.message) +}); +``` + + + +### What This Code Does + +1. **Creates Event Listener**: `OngoingCallListener` defines callbacks for call events: + - Participant join/leave notifications + - Call end detection + - Error handling + - Screen share and mute state changes + +2. **Configures Call UI**: `CallSettingsBuilder` customizes the call experience: + - Default layout provides ready-to-use call controls + - Audio/video settings control initial state + - Listener attachment connects your callbacks + +3. **Builds Settings Object**: `build()` creates the final configuration used by `startSession()` + +### Call Settings Options + +| Method | Description | Default | +|--------|-------------|---------| +| `enableDefaultLayout(boolean)` | Show/hide default UI controls (mute, video, end call buttons) | `true` | +| `setIsAudioOnlyCall(boolean)` | Audio-only call (no video) or video call | `false` | +| `startWithAudioMuted(boolean)` | Start with microphone muted | `false` | +| `startWithVideoMuted(boolean)` | Start with camera off | `false` | +| `showEndCallButton(boolean)` | Show the end call button in default UI | `true` | +| `showMuteAudioButton(boolean)` | Show the mute/unmute button | `true` | +| `showPauseVideoButton(boolean)` | Show the video on/off toggle | `true` | +| `showScreenShareButton(boolean)` | Show the screen share button | `true` | + + +**Default Layout vs Custom UI**: When `enableDefaultLayout(true)`, CometChat provides a complete call UI with all controls. Set to `false` if you want to build your own UI and control the call programmatically using the methods in Step 7. + + +--- + +## Step 6: Start Call Session + +Starting a call session renders the video/audio UI into a container element and establishes the WebRTC connection. The call token authorizes this specific user to join this specific session. + + + +```javascript +// The container element where the call UI will be rendered +// Must have explicit dimensions - the call UI fills this container +// HTML:
+const htmlElement = document.getElementById("call-container"); + +// Call token from Step 4 - authorizes this user for this session +const callToken = "GENERATED_CALL_TOKEN"; + +// startSession() performs these operations: +// 1. Requests camera/microphone permissions (if not already granted) +// 2. Establishes WebRTC connection to CometChat media servers +// 3. Renders the call UI into the container element +// 4. Begins transmitting/receiving audio and video streams +CometChatCalls.startSession(callToken, callSettings, htmlElement); + +// Note: startSession() doesn't return a Promise +// Use the callListener callbacks to track session state +``` +
+ +```jsx +import { useEffect, useRef, useCallback } from "react"; +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +/** + * CallScreen Component + * Renders a video call session in a container + * + * Props: + * - callToken: The generated call token from CometChatCalls.generateToken() + * - onCallEnd: Callback when the call ends (for navigation/cleanup) + */ +function CallScreen({ callToken, onCallEnd }) { + // useRef to get a reference to the DOM element + // The call UI will be rendered inside this element + const containerRef = useRef(null); + + useEffect(() => { + // Guard: Don't start if we don't have required data + if (!callToken || !containerRef.current) return; + + // Create call listener with callbacks + // These handle call lifecycle events + const callListener = new CometChatCalls.OngoingCallListener({ + onUserJoined: (user) => { + console.log("Participant joined:", user.getName()); + }, + onUserLeft: (user) => { + console.log("Participant left:", user.getName()); + }, + // When call ends (other party hangs up or timeout) + onCallEnded: () => { + CometChatCalls.endSession(); // Clean up resources + onCallEnd(); // Notify parent component + }, + // When user clicks end button in default UI + onCallEndButtonPressed: () => { + CometChatCalls.endSession(); + onCallEnd(); + }, + onError: (error) => { + console.error("Call error:", error); + // Optionally end call on critical errors + } + }); + + // Build call settings + const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) // Use built-in UI + .setCallListener(callListener) + .build(); + + // Start the call session + // This renders the call UI into containerRef.current + CometChatCalls.startSession(callToken, callSettings, containerRef.current); + + // Cleanup function - runs when component unmounts + // or when dependencies change + return () => { + CometChatCalls.endSession(); // Always clean up on unmount + }; + }, [callToken, onCallEnd]); // Re-run if these change + + // Container must have dimensions for the call UI to render properly + return ( +
+ ); +} + +export default CallScreen; +``` + + + +### What This Code Does + +1. **Gets Container Element**: The call UI needs a DOM element to render into +2. **Starts WebRTC Session**: `startSession()` establishes the peer-to-peer connection +3. **Renders Call UI**: The default layout includes video feeds and control buttons +4. **Handles Permissions**: Browser will prompt for camera/microphone access if needed + +### Container Requirements + +| Requirement | Description | +|-------------|-------------| +| **Dimensions** | Container must have explicit width and height (CSS or inline styles) | +| **Visibility** | Container must be visible (not `display: none`) when starting | +| **Single Session** | Only one call session can be active at a time | + + +**Browser Permissions**: The first time a user joins a call, the browser will request camera and microphone permissions. If denied, the call will fail. Handle this in your `onError` callback. + + +--- + +## Step 7: Call Controls + +During an active call session, you can programmatically control audio, video, screen sharing, and device selection. These methods are useful when building a custom UI or adding keyboard shortcuts. + +```javascript +// ==================== AUDIO CONTROLS ==================== + +// Mute/unmute the local microphone +// Other participants will stop/start hearing you +CometChatCalls.muteAudio(true); // Mute - others can't hear you +CometChatCalls.muteAudio(false); // Unmute - others can hear you + +// ==================== VIDEO CONTROLS ==================== + +// Pause/resume the local camera +// Other participants will see a placeholder or black screen when paused +CometChatCalls.pauseVideo(true); // Pause - camera off, others see placeholder +CometChatCalls.pauseVideo(false); // Resume - camera on, others see your video + +// ==================== SCREEN SHARING ==================== + +// Start sharing your screen +// Browser will prompt user to select screen/window/tab +// Only one participant can screen share at a time +CometChatCalls.startScreenShare(); + +// Stop screen sharing and return to camera +CometChatCalls.stopScreenShare(); + +// ==================== CAMERA SWITCHING ==================== + +// Switch between front and back camera (mobile devices only) +// On desktop, use setVideoInputDevice() instead +CometChatCalls.switchCamera(); + +// ==================== DEVICE MANAGEMENT ==================== + +// Get lists of available devices +// Returns arrays of MediaDeviceInfo objects with deviceId and label +const audioInputs = CometChatCalls.getAudioInputDevices(); // Microphones +const audioOutputs = CometChatCalls.getAudioOutputDevices(); // Speakers/headphones +const videoInputs = CometChatCalls.getVideoInputDevices(); // Cameras + +// Example: Build a device selector dropdown +audioInputs.forEach(device => { + console.log(`Mic: ${device.label} (${device.deviceId})`); +}); + +// Switch to a specific device by its deviceId +// Use deviceId from the arrays above +CometChatCalls.setAudioInputDevice(deviceId); // Change microphone +CometChatCalls.setAudioOutputDevice(deviceId); // Change speaker +CometChatCalls.setVideoInputDevice(deviceId); // Change camera + +// ==================== END CALL ==================== + +// End the call session and clean up resources +// This disconnects from the call and releases camera/microphone +CometChatCalls.endSession(); +``` + +### What This Code Does + +| Method | Action | Effect on Others | +|--------|--------|------------------| +| `muteAudio(true/false)` | Mute/unmute microphone | Others stop/start hearing you | +| `pauseVideo(true/false)` | Turn camera off/on | Others see placeholder/your video | +| `startScreenShare()` | Share screen | Others see your screen | +| `stopScreenShare()` | Stop sharing | Others see your camera again | +| `switchCamera()` | Toggle front/back camera | Others see different camera view | +| `setAudioInputDevice(id)` | Change microphone | Audio quality may change | +| `setAudioOutputDevice(id)` | Change speaker | Only affects local playback | +| `setVideoInputDevice(id)` | Change camera | Others see different camera | +| `endSession()` | Leave the call | You disappear from call | + + +**Custom UI**: If you set `enableDefaultLayout(false)` in call settings, you must implement your own UI buttons that call these methods. The default layout already includes buttons for mute, video, screen share, and end call. + + +--- + +## Step 8: End Call Session + +Ending a call session disconnects from the WebRTC connection, releases camera/microphone resources, and cleans up the call UI. Always call `endSession()` when leaving a call. + +```javascript +/** + * End the current call and clean up + * Call this when: + * - User clicks end call button (if using custom UI) + * - onCallEnded callback fires (other party ended) + * - User navigates away from call screen + * - An unrecoverable error occurs + */ +function endCall() { + // endSession() performs these operations: + // 1. Sends "leave" signal to other participants + // 2. Closes WebRTC peer connections + // 3. Stops local camera and microphone streams + // 4. Removes the call UI from the container + // 5. Cleans up internal SDK state + CometChatCalls.endSession(); + + // Hide or remove the call container from your UI + const container = document.getElementById("call-container"); + container.style.display = "none"; + + // Navigate back to previous screen or show call ended message + // This depends on your app's navigation structure +} + +// Alternative: End call with confirmation +async function endCallWithConfirmation() { + const confirmed = confirm("Are you sure you want to end the call?"); + if (confirmed) { + CometChatCalls.endSession(); + // Navigate away + } +} +``` + +### What This Code Does + +1. **Signals Other Participants**: Notifies others that you've left the call +2. **Closes Connections**: Terminates WebRTC peer connections +3. **Releases Hardware**: Stops camera and microphone access +4. **Cleans Up UI**: Removes the call interface from the container +5. **Resets State**: Prepares SDK for a new call session + + +**Always Call endSession()**: Failing to call `endSession()` can leave the camera/microphone active, cause memory leaks, and prevent starting new calls. Always call it in your cleanup code, error handlers, and component unmount functions. + + +--- + +## Complete Integration Example + +This example shows a complete `StandaloneCallService` class that encapsulates all Calls SDK functionality. Use this as a reference for structuring your integration. + +```javascript +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +/** + * StandaloneCallService - A complete wrapper for CometChat Calls SDK + * + * This class provides a clean interface for: + * - Initializing the Calls SDK + * - Starting new calls (as caller) + * - Joining existing calls (as participant) + * - Managing call controls (mute, video, screen share) + * + * Note: This is for standalone calling WITHOUT the Chat SDK. + * User authentication is handled via REST API auth tokens. + * + * Usage: + * const callService = new StandaloneCallService("APP_ID", "REGION"); + * await callService.initialize(); + * const sessionId = await callService.startCall(authToken, true, container); + * // Share sessionId with others to let them join + */ +class StandaloneCallService { + /** + * Create a new call service instance + * @param {string} appId - Your CometChat App ID + * @param {string} region - Your app region ("us" or "eu") + */ + constructor(appId, region) { + this.appId = appId; + this.region = region; + this.currentSessionId = null; // Track active call session + } + + /** + * Initialize the Calls SDK + * Must be called once before any other operations + * Typically called at app startup + */ + async initialize() { + await CometChatCalls.init({ + appId: this.appId, + region: this.region + }); + console.log("Calls SDK initialized"); + } + + /** + * Start a new call as the caller + * Generates a unique session ID and starts the call + * Share the returned sessionId with others to let them join + * + * @param {string} userAuthToken - Auth token from REST API + * @param {boolean} isVideoCall - true for video, false for audio-only + * @param {HTMLElement} container - DOM element to render call UI + * @returns {string} - The session ID (share with other participants) + */ + async startCall(userAuthToken, isVideoCall = true, container) { + // Generate unique session ID for this call + // Format: call__ ensures uniqueness + this.currentSessionId = `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + + // Generate call token for this user and session + const callToken = await CometChatCalls.generateToken( + this.currentSessionId, + userAuthToken + ); + + // Configure call settings + const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIsAudioOnlyCall(!isVideoCall) + .setCallListener(this.getCallListener()) + .build(); + + // Start the session - renders UI into container + CometChatCalls.startSession(callToken.token, callSettings, container); + + // Return session ID so caller can share it with others + return this.currentSessionId; + } + + /** + * Join an existing call as a participant + * Use the session ID provided by the caller + * + * @param {string} sessionId - Session ID from the caller + * @param {string} userAuthToken - Auth token from REST API + * @param {HTMLElement} container - DOM element to render call UI + */ + async joinCall(sessionId, userAuthToken, container) { + // Store the session ID we're joining + this.currentSessionId = sessionId; + + // Generate call token for this user to join this session + const callToken = await CometChatCalls.generateToken(sessionId, userAuthToken); + + // Build call settings with listener + const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setCallListener(this.getCallListener()) + .build(); + + // Join the call session + CometChatCalls.startSession(callToken.token, callSettings, container); + } + + /** + * Create the call event listener + * Handles participant join/leave, call end, and errors + * @returns {CometChatCalls.OngoingCallListener} + */ + getCallListener() { + return new CometChatCalls.OngoingCallListener({ + onUserJoined: (user) => { + console.log("User joined:", user); + // Trigger external callback if set + this.onParticipantJoined?.(user); + }, + onUserLeft: (user) => { + console.log("User left:", user); + this.onParticipantLeft?.(user); + }, + onCallEnded: () => { + console.log("Call ended"); + this.endCall(); + this.onCallEnded?.(); + }, + onCallEndButtonPressed: () => { + this.endCall(); + this.onCallEnded?.(); + }, + onError: (error) => { + console.error("Call error:", error); + this.onError?.(error); + } + }); + } + + // ==================== CALL CONTROLS ==================== + + /** + * Mute or unmute the local microphone + * @param {boolean} mute - true to mute, false to unmute + */ + muteAudio(mute) { + CometChatCalls.muteAudio(mute); + } + + /** + * Pause or resume the local camera + * @param {boolean} pause - true to pause (camera off), false to resume + */ + pauseVideo(pause) { + CometChatCalls.pauseVideo(pause); + } + + /** + * Start sharing your screen + * Browser will prompt to select screen/window/tab + */ + startScreenShare() { + CometChatCalls.startScreenShare(); + } + + /** + * Stop screen sharing and return to camera + */ + stopScreenShare() { + CometChatCalls.stopScreenShare(); + } + + /** + * End the current call and clean up resources + */ + endCall() { + CometChatCalls.endSession(); + this.currentSessionId = null; + } + + // ==================== EVENT HANDLERS ==================== + // Set these to receive callbacks from the call + // Example: callService.onParticipantJoined = (user) => updateUI(user); + + onParticipantJoined = null; // Called when someone joins + onParticipantLeft = null; // Called when someone leaves + onCallEnded = null; // Called when call ends + onError = null; // Called on errors +} + +// ==================== USAGE EXAMPLE ==================== + +// 1. Create service instance with your credentials +const callService = new StandaloneCallService("APP_ID", "REGION"); + +// 2. Initialize SDK (do this once at app startup) +await callService.initialize(); + +// 3. Set up event handlers to update your UI +callService.onParticipantJoined = (user) => { + console.log(`${user.getName()} joined the call`); + // Update participant list in UI +}; + +callService.onParticipantLeft = (user) => { + console.log(`${user.getName()} left the call`); + // Update participant list in UI +}; + +callService.onCallEnded = () => { + console.log("Call has ended"); + // Navigate back to home screen +}; + +// 4a. Start a new call (as caller) +const container = document.getElementById("call-container"); +const sessionId = await callService.startCall(userAuthToken, true, container); +console.log("Share this session ID to invite others:", sessionId); + +// 4b. OR join an existing call (as participant) +// const existingSessionId = "session_id_from_caller"; +// await callService.joinCall(existingSessionId, userAuthToken, container); + +// 5. Use call controls during the call +// callService.muteAudio(true); // Mute +// callService.pauseVideo(true); // Turn off camera +// callService.startScreenShare(); // Share screen + +// 6. End the call when done +// callService.endCall(); +``` + +### Code Structure Explained + +| Method | Purpose | When to Call | +|--------|---------|--------------| +| `constructor()` | Store app credentials | Once when creating instance | +| `initialize()` | Setup SDK | Once at app startup | +| `startCall()` | Begin new call as caller | When user initiates a call | +| `joinCall()` | Join existing call | When user accepts invitation | +| `muteAudio()` | Toggle microphone | During active call | +| `pauseVideo()` | Toggle camera | During active call | +| `startScreenShare()` | Share screen | During active call | +| `endCall()` | Leave and cleanup | When ending call | + +--- + +## Sharing Calls with Others + +To enable multiple users to join the same call: + +1. **Caller** generates a session ID and starts the call +2. **Caller** shares the session ID with other participants (via your app's UI, push notification, etc.) +3. **Participants** use the same session ID to join the call + +```javascript +// Caller +const sessionId = await callService.startCall(callerAuthToken, true, container); +// Send sessionId to other users via your backend + +// Participant +await callService.joinCall(sessionId, participantAuthToken, container); +``` + +--- + +## Next Steps + + + + Record calls for later playback + + + Add blur or custom backgrounds + + + Create webinar-style experiences + + + Combine with messaging + + diff --git a/sdk/javascript/guide-chat-calls.mdx b/sdk/javascript/guide-chat-calls.mdx new file mode 100644 index 00000000..9aea7236 --- /dev/null +++ b/sdk/javascript/guide-chat-calls.mdx @@ -0,0 +1,1024 @@ +--- +title: "Chat + Calls Integration Guide" +sidebarTitle: "Chat + Calls" +description: "Complete step-by-step guide to integrate messaging with voice and video calling" +--- + +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Chat + Calls Integration +// 1. Install both SDKs +npm install @cometchat/chat-sdk-javascript @cometchat/calls-sdk-javascript + +// 2. Initialize Chat SDK first +await CometChat.init("APP_ID", appSettings); + +// 3. Initialize Calls SDK +await CometChatCalls.init({ appId: "APP_ID", region: "REGION" }); + +// 4. Login to Chat SDK +await CometChat.login("UID", "AUTH_KEY"); + +// 5. Initiate a call +const call = new CometChat.Call("RECEIVER_UID", CometChat.CALL_TYPE.VIDEO, CometChat.RECEIVER_TYPE.USER); +const outgoingCall = await CometChat.initiateCall(call); + +// 6. Listen for incoming calls +CometChat.addCallListener("CALL_LISTENER", new CometChat.CallListener({ + onIncomingCallReceived: (call) => { /* show incoming call UI */ }, + onOutgoingCallAccepted: (call) => { /* start call session */ } +})); +``` + + +This guide walks you through integrating both CometChat messaging and calling into your application. The Chat SDK handles call signaling (initiating, accepting, rejecting calls), while the Calls SDK handles the actual audio/video streams. + + +**Prerequisites** +- A CometChat account with an app created at [app.cometchat.com](https://app.cometchat.com) +- Your App ID, Region, and Auth Key from the dashboard +- Node.js 14+ or a modern browser + + +--- + +## Step 1: Install Both SDKs + + + +```bash +npm install @cometchat/chat-sdk-javascript @cometchat/calls-sdk-javascript +``` + + +```bash +yarn add @cometchat/chat-sdk-javascript @cometchat/calls-sdk-javascript +``` + + + +Import both SDKs: + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; +``` + +--- + +## Step 2: Initialize Both SDKs + +The Chat SDK handles user authentication, messaging, and call signaling (initiating, accepting, rejecting calls). The Calls SDK handles the actual WebRTC audio/video streams. Both must be initialized, with the Chat SDK first. + + +**Order matters**: Initialize the Chat SDK first, then the Calls SDK. The Chat SDK establishes the user session that the Calls SDK depends on. + + + + +```javascript +const APP_ID = "YOUR_APP_ID"; +const REGION = "YOUR_REGION"; // "us" or "eu" + +// ==================== STEP 2a: Initialize Chat SDK ==================== +// The Chat SDK handles: +// - User authentication and sessions +// - Call signaling (initiate, accept, reject, end) +// - Real-time message delivery +// - Presence (online/offline status) + +const chatSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() // Get online/offline updates + .setRegion(REGION) // Connect to correct data center + .autoEstablishSocketConnection(true) // Auto-connect WebSocket on login + .build(); + +CometChat.init(APP_ID, chatSettings).then( + () => { + console.log("Chat SDK initialized"); + + // ==================== STEP 2b: Initialize Calls SDK ==================== + // The Calls SDK handles: + // - WebRTC peer connections + // - Audio/video streaming + // - Screen sharing + // - Call UI rendering + + const callSettings = { + appId: APP_ID, + region: REGION + }; + + return CometChatCalls.init(callSettings); + } +).then( + () => { + console.log("Calls SDK initialized"); + // Both SDKs ready - proceed to login + }, + (error) => { + console.log("Initialization failed:", error); + // Handle error - check credentials, network, region + } +); +``` + + +```javascript +/** + * Initialize both CometChat SDKs + * Must be called once at app startup, before login + * + * @returns {boolean} - true if both SDKs initialized successfully + */ +async function initializeCometChat() { + const APP_ID = "YOUR_APP_ID"; + const REGION = "YOUR_REGION"; + + try { + // Step 1: Initialize Chat SDK first + // This sets up user authentication and call signaling + const chatSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(REGION) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init(APP_ID, chatSettings); + console.log("Chat SDK initialized"); + + // Step 2: Initialize Calls SDK + // This sets up WebRTC for audio/video + await CometChatCalls.init({ + appId: APP_ID, + region: REGION + }); + console.log("Calls SDK initialized"); + + return true; + } catch (error) { + console.log("Initialization failed:", error); + // Common errors: + // - Invalid APP_ID + // - Wrong REGION (must match dashboard setting) + // - Network connectivity issues + return false; + } +} +``` + + + +### What This Code Does + +1. **Chat SDK Initialization**: + - Validates your app credentials + - Prepares WebSocket connection for real-time events + - Sets up call signaling infrastructure + +2. **Calls SDK Initialization**: + - Prepares WebRTC capabilities + - Sets up media server connections + - Enables audio/video streaming + +### Why Two SDKs? + +| SDK | Responsibility | Protocol | +|-----|----------------|----------| +| **Chat SDK** | User auth, messaging, call signaling | WebSocket | +| **Calls SDK** | Audio/video streaming, screen share | WebRTC | + +The Chat SDK tells users "there's an incoming call" (signaling), while the Calls SDK actually transmits the audio and video (media). + +--- + +## Step 3: Login + +Login authenticates the user with the Chat SDK and establishes their real-time connection. The Calls SDK uses the same user session, so you only need to login once. + +```javascript +/** + * Login a user to CometChat + * This authenticates with the Chat SDK - the Calls SDK uses the same session + * + * @param {string} uid - User's unique identifier + * @param {string} authKey - Your Auth Key (dev only) or use authToken for production + * @returns {CometChat.User} - The logged in user object + */ +async function login(uid, authKey) { + // Always check for existing session first + // This prevents duplicate logins and session conflicts + const loggedInUser = await CometChat.getLoggedinUser(); + if (loggedInUser) { + console.log("Already logged in:", loggedInUser.getName()); + return loggedInUser; + } + + try { + // Login with Auth Key (development) or Auth Token (production) + // This establishes the WebSocket connection for real-time events + const user = await CometChat.login(uid, authKey); + console.log("Login successful:", user.getName()); + + // After login, the user can: + // - Send and receive messages + // - Initiate and receive calls + // - See other users' online status + return user; + } catch (error) { + console.log("Login failed:", error); + // Common errors: + // - ERR_UID_NOT_FOUND: User doesn't exist in CometChat + // - ERR_AUTH_TOKEN_NOT_FOUND: Invalid auth key/token + throw error; + } +} +``` + +### What This Code Does + +1. **Checks Existing Session**: `getLoggedinUser()` returns the current user or null +2. **Authenticates User**: `login()` validates credentials with CometChat servers +3. **Establishes Connection**: Opens WebSocket for real-time messaging and call signaling +4. **Returns User Object**: Contains user profile data (uid, name, avatar, etc.) + + +**Single Login**: You only login to the Chat SDK. The Calls SDK automatically uses the same authenticated session when generating call tokens. + + +--- + +## Step 4: Set Up Call Listeners + +Call listeners receive real-time notifications about call events. Register these after login to handle incoming calls, call acceptance/rejection, and call cancellation. + +```javascript +const CALL_LISTENER_ID = "CALL_LISTENER"; + +// addCallListener() registers callbacks for call signaling events +// These events are separate from the actual audio/video (handled by Calls SDK) +CometChat.addCallListener( + CALL_LISTENER_ID, + new CometChat.CallListener({ + // ==================== INCOMING CALL ==================== + // Called when another user calls you + // incomingCall contains: sender info, call type, session ID + onIncomingCallReceived: (incomingCall) => { + console.log("Incoming call from:", incomingCall.getSender().getName()); + console.log("Call type:", incomingCall.getType()); // "audio" or "video" + + // Show incoming call UI with accept/reject buttons + // Store the call object to use when accepting/rejecting + showIncomingCallUI(incomingCall); + }, + + // ==================== OUTGOING CALL ACCEPTED ==================== + // Called when the person you're calling accepts + // This is your signal to start the actual call session + onOutgoingCallAccepted: (acceptedCall) => { + console.log("Call accepted"); + + // Now start the audio/video session using Calls SDK + // The acceptedCall contains the session ID needed + startCallSession(acceptedCall); + }, + + // ==================== OUTGOING CALL REJECTED ==================== + // Called when the person you're calling rejects or is busy + onOutgoingCallRejected: (rejectedCall) => { + console.log("Call rejected"); + + // Hide the "calling..." UI + // Show appropriate message (rejected, busy, etc.) + hideCallingUI(); + }, + + // ==================== INCOMING CALL CANCELLED ==================== + // Called when the caller hangs up before you answer + onIncomingCallCancelled: (cancelledCall) => { + console.log("Incoming call cancelled"); + + // Hide the incoming call UI + // The caller gave up waiting + hideIncomingCallUI(); + } + }) +); + +// IMPORTANT: Remove listener when no longer needed +// Call this on logout or component unmount to prevent memory leaks +// CometChat.removeCallListener(CALL_LISTENER_ID); +``` + +### What This Code Does + +1. **Registers Event Handlers**: `addCallListener()` subscribes to call signaling events +2. **Handles Incoming Calls**: `onIncomingCallReceived` fires when someone calls you +3. **Handles Call Acceptance**: `onOutgoingCallAccepted` fires when your call is answered +4. **Handles Rejections**: `onOutgoingCallRejected` fires when your call is declined +5. **Handles Cancellations**: `onIncomingCallCancelled` fires when caller hangs up + +### Call Event Flow + +| Event | When It Fires | Your Action | +|-------|---------------|-------------| +| `onIncomingCallReceived` | Someone calls you | Show accept/reject UI | +| `onOutgoingCallAccepted` | They answered your call | Start call session | +| `onOutgoingCallRejected` | They rejected your call | Hide calling UI | +| `onIncomingCallCancelled` | Caller hung up | Hide incoming call UI | + + +**Signaling vs Media**: These listeners handle call signaling (who's calling whom). The actual audio/video is handled separately by the Calls SDK in Step 8. + + +--- + +## Step 5: Initiate a Call + +To start a call, create a Call object and use `initiateCall()`. This sends a call invitation to the recipient, who will receive it via their `onIncomingCallReceived` listener. + +### Call a User + +```javascript +/** + * Initiate a call to another user + * This sends a call invitation - the actual audio/video starts after they accept + * + * @param {string} receiverUID - The UID of the user to call + * @param {string} callType - CometChat.CALL_TYPE.VIDEO or AUDIO + * @returns {CometChat.Call} - The outgoing call object + */ +async function callUser(receiverUID, callType = CometChat.CALL_TYPE.VIDEO) { + // Create a Call object with: + // 1. receiverUID - Who you're calling + // 2. callType - VIDEO or AUDIO + // 3. receiverType - USER (for 1-on-1) or GROUP (for group calls) + const call = new CometChat.Call( + receiverUID, + callType, // CometChat.CALL_TYPE.VIDEO or CometChat.CALL_TYPE.AUDIO + CometChat.RECEIVER_TYPE.USER // This is a 1-on-1 call + ); + + try { + // initiateCall() sends the call invitation to the recipient + // They'll receive it via onIncomingCallReceived + // Returns immediately - doesn't wait for them to answer + const outgoingCall = await CometChat.initiateCall(call); + console.log("Call initiated:", outgoingCall); + + // Show "calling..." UI while waiting for response + // The recipient has ~45 seconds to answer before timeout + showOutgoingCallUI(outgoingCall); + + return outgoingCall; + } catch (error) { + console.log("Call initiation failed:", error); + // Common errors: + // - ERR_UID_NOT_FOUND: Recipient doesn't exist + // - ERR_USER_NOT_LOGGED_IN: You're not logged in + // - ERR_CALL_ALREADY_INITIATED: Already in a call + throw error; + } +} + +// Usage: Start a video call to user_456 +await callUser("user_456", CometChat.CALL_TYPE.VIDEO); + +// Usage: Start an audio-only call +await callUser("user_456", CometChat.CALL_TYPE.AUDIO); +``` + +### Call a Group + +```javascript +/** + * Initiate a call to a group + * All online group members will receive the call invitation + * + * @param {string} groupGUID - The GUID of the group to call + * @param {string} callType - CometChat.CALL_TYPE.VIDEO or AUDIO + * @returns {CometChat.Call} - The outgoing call object + */ +async function callGroup(groupGUID, callType = CometChat.CALL_TYPE.VIDEO) { + // For group calls, use the group's GUID as the receiver + const call = new CometChat.Call( + groupGUID, + callType, + CometChat.RECEIVER_TYPE.GROUP // This is a group call + ); + + try { + // All online group members receive onIncomingCallReceived + // Multiple members can join the same call + const outgoingCall = await CometChat.initiateCall(call); + console.log("Group call initiated:", outgoingCall); + return outgoingCall; + } catch (error) { + console.log("Group call failed:", error); + // Additional error: ERR_NOT_A_MEMBER if you're not in the group + throw error; + } +} +``` + +### What This Code Does + +1. **Creates Call Object**: Defines who you're calling and the call type +2. **Sends Invitation**: `initiateCall()` notifies the recipient(s) +3. **Returns Immediately**: Doesn't wait for answer - use listeners for response +4. **Triggers Listener**: Recipient's `onIncomingCallReceived` fires + +| Parameter | Description | +|-----------|-------------| +| `receiverUID/GUID` | Who to call (user UID or group GUID) | +| `callType` | `VIDEO` (camera + mic) or `AUDIO` (mic only) | +| `receiverType` | `USER` for 1-on-1, `GROUP` for group calls | + +--- + +## Step 6: Accept an Incoming Call + +When you receive an incoming call (via `onIncomingCallReceived`), use `acceptCall()` to answer it. This notifies the caller that you've accepted, triggering their `onOutgoingCallAccepted` listener. + +```javascript +/** + * Accept an incoming call + * This notifies the caller and prepares for the call session + * + * @param {CometChat.Call} incomingCall - The call object from onIncomingCallReceived + * @returns {CometChat.Call} - The accepted call object with session info + */ +async function acceptCall(incomingCall) { + // Get the session ID from the incoming call + // This ID links both parties to the same call session + const sessionId = incomingCall.getSessionId(); + + try { + // acceptCall() notifies the caller that you've answered + // The caller's onOutgoingCallAccepted will fire + // Returns the call object with updated status + const acceptedCall = await CometChat.acceptCall(sessionId); + console.log("Call accepted:", acceptedCall); + + // Now start the actual audio/video session + // Both parties should call startCallSession() at this point + startCallSession(acceptedCall); + + return acceptedCall; + } catch (error) { + console.log("Accept call failed:", error); + // Common errors: + // - ERR_CALL_NOT_FOUND: Call was cancelled or timed out + // - ERR_CALL_ALREADY_JOINED: You already accepted this call + throw error; + } +} +``` + +### What This Code Does + +1. **Gets Session ID**: Extracts the unique call session identifier +2. **Sends Acceptance**: `acceptCall()` notifies the caller you've answered +3. **Triggers Caller's Listener**: Their `onOutgoingCallAccepted` fires +4. **Starts Call Session**: Both parties now start the audio/video session + + +**Both Parties Start Session**: After acceptance, both the caller (in `onOutgoingCallAccepted`) and receiver (after `acceptCall()`) should call `startCallSession()` to begin the actual audio/video. + + +--- + +## Step 7: Reject an Incoming Call + +If you don't want to answer an incoming call, use `rejectCall()` to decline it. You can specify different rejection statuses to indicate why you're not answering. + +```javascript +/** + * Reject an incoming call + * This notifies the caller that you've declined + * + * @param {CometChat.Call} incomingCall - The call object from onIncomingCallReceived + * @param {string} status - Rejection reason (REJECTED, BUSY, or CANCELLED) + * @returns {CometChat.Call} - The rejected call object + */ +async function rejectCall(incomingCall, status = CometChat.CALL_STATUS.REJECTED) { + const sessionId = incomingCall.getSessionId(); + + try { + // rejectCall() notifies the caller that you've declined + // The caller's onOutgoingCallRejected will fire + // The status parameter tells them why you rejected + const rejectedCall = await CometChat.rejectCall(sessionId, status); + console.log("Call rejected:", rejectedCall); + + // Hide the incoming call UI + hideIncomingCallUI(); + + return rejectedCall; + } catch (error) { + console.log("Reject call failed:", error); + throw error; + } +} + +// ==================== REJECTION STATUSES ==================== +// Use different statuses to communicate why you're not answering: + +// REJECTED - User explicitly declined the call +// Use when: User clicks "Decline" button +await rejectCall(incomingCall, CometChat.CALL_STATUS.REJECTED); + +// BUSY - User is already in another call +// Use when: User is on another call and can't answer +await rejectCall(incomingCall, CometChat.CALL_STATUS.BUSY); + +// CANCELLED - Caller cancelled before answer (usually automatic) +// Use when: Implementing custom timeout or auto-reject +await rejectCall(incomingCall, CometChat.CALL_STATUS.CANCELLED); +``` + +### What This Code Does + +1. **Gets Session ID**: Identifies which call to reject +2. **Sends Rejection**: `rejectCall()` notifies the caller +3. **Includes Status**: Tells caller why you rejected (declined, busy, etc.) +4. **Triggers Caller's Listener**: Their `onOutgoingCallRejected` fires + +### Rejection Status Options + +| Status | Meaning | When to Use | +|--------|---------|-------------| +| `REJECTED` | User declined the call | User clicked "Decline" | +| `BUSY` | User is on another call | Already in a call | +| `CANCELLED` | Call was cancelled | Timeout or auto-reject | + +--- + +## Step 8: Start the Call Session + +Once a call is accepted (either by you or the other party), start the actual audio/video session using the Calls SDK. This is where the WebRTC connection is established and media streams begin. + +```javascript +/** + * Start the audio/video call session + * Called after a call is accepted (by either party) + * + * @param {CometChat.Call} call - The accepted call object + */ +function startCallSession(call) { + // Get session ID - links both parties to the same call + const sessionId = call.getSessionId(); + + // Get call type to configure audio-only vs video + const callType = call.getType(); + + // Get the container element where call UI will render + const container = document.getElementById("call-container"); + + // ==================== STEP 1: Generate Call Token ==================== + // The call token authorizes this user to join this specific session + // Uses the logged-in user's auth token from the Chat SDK + CometChatCalls.generateToken(sessionId, CometChat.getLoggedinUser().getAuthToken()).then( + (callToken) => { + // ==================== STEP 2: Configure Call Settings ==================== + // Set up the call UI and event handlers + const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) // Use built-in call UI + .setIsAudioOnlyCall(callType === CometChat.CALL_TYPE.AUDIO) // Match call type + .setCallListener(getCallSessionListener(sessionId)) // Attach event handlers + .build(); + + // ==================== STEP 3: Start the Session ==================== + // This renders the call UI and establishes WebRTC connection + // Both parties' video/audio will appear in the container + CometChatCalls.startSession(callToken.token, callSettings, container); + }, + (error) => { + console.log("Token generation failed:", error); + // Handle error - possibly end the call + } + ); +} + +/** + * Create event listener for the call session + * Handles participant events and call end + * + * @param {string} sessionId - The call session ID + * @returns {CometChatCalls.OngoingCallListener} + */ +function getCallSessionListener(sessionId) { + return new CometChatCalls.OngoingCallListener({ + // Called when another participant joins + onUserJoined: (user) => { + console.log("User joined:", user); + // Update participant list in UI + }, + + // Called when a participant leaves + onUserLeft: (user) => { + console.log("User left:", user); + // Update participant list in UI + }, + + // Called when the call ends (other party hung up) + onCallEnded: () => { + console.log("Call ended"); + endCallSession(sessionId); + }, + + // Called when user clicks end button in default UI + onCallEndButtonPressed: () => { + console.log("End button pressed"); + endCallSession(sessionId); + }, + + // Called on errors (network issues, permission denied, etc.) + onError: (error) => { + console.log("Call error:", error); + // Consider ending call on critical errors + } + }); +} +``` + +### What This Code Does + +1. **Generates Call Token**: Creates authorization for this user to join this session +2. **Configures Settings**: Sets up call UI, audio/video mode, and event handlers +3. **Starts WebRTC Session**: Establishes peer connection and begins streaming +4. **Renders Call UI**: Displays video feeds and control buttons in the container + +### Call Session Flow + +``` +acceptCall() or onOutgoingCallAccepted + │ + ▼ + startCallSession() + │ + ├── generateToken() → Get authorization + │ + ├── CallSettingsBuilder → Configure UI and handlers + │ + └── startSession() → Start WebRTC, render UI + │ + ▼ + ═══════════════════ + AUDIO/VIDEO ACTIVE + ═══════════════════ +``` + + +**Both Parties Call This**: When a call is accepted, both the caller (in `onOutgoingCallAccepted`) and the receiver (after `acceptCall()`) should call `startCallSession()` to join the same session. + + +--- + +## Step 9: End the Call + +Ending a call requires cleanup in both SDKs: the Chat SDK (to update call status) and the Calls SDK (to close the WebRTC connection). + +```javascript +/** + * End the current call and clean up both SDKs + * Call this when: + * - User clicks end call button (if using custom UI) + * - onCallEnded fires (other party ended) + * - An error requires ending the call + * + * @param {string} sessionId - The call session ID + */ +async function endCallSession(sessionId) { + try { + // ==================== STEP 1: End in Chat SDK ==================== + // This updates the call status in CometChat's system + // Notifies the other party that the call has ended + // Records the call in conversation history + await CometChat.endCall(sessionId); + + // ==================== STEP 2: Clear Active Call ==================== + // Removes the call from the SDK's internal state + // Allows initiating new calls + CometChat.clearActiveCall(); + + // ==================== STEP 3: End Calls SDK Session ==================== + // Closes WebRTC peer connections + // Stops camera and microphone + // Removes call UI from container + CometChatCalls.endSession(); + + // ==================== STEP 4: Update Your UI ==================== + // Hide the call container + document.getElementById("call-container").style.display = "none"; + + console.log("Call ended successfully"); + } catch (error) { + console.log("End call failed:", error); + // Even if Chat SDK fails, still clean up Calls SDK + CometChat.clearActiveCall(); + CometChatCalls.endSession(); + } +} +``` + +### What This Code Does + +1. **Updates Call Status**: `endCall()` marks the call as ended in CometChat +2. **Clears Active Call**: `clearActiveCall()` resets SDK state for new calls +3. **Closes WebRTC**: `endSession()` stops media streams and connections +4. **Cleans Up UI**: Hides the call container + +### Cleanup Order + +| Step | SDK | Method | Purpose | +|------|-----|--------|---------| +| 1 | Chat | `endCall()` | Update call status, notify other party | +| 2 | Chat | `clearActiveCall()` | Reset state for new calls | +| 3 | Calls | `endSession()` | Close WebRTC, release camera/mic | + + +**Always Clean Up Both SDKs**: Failing to call both `CometChat.endCall()` and `CometChatCalls.endSession()` can leave resources hanging and prevent new calls from working properly. + + +--- + +## Complete Integration Example + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +class ChatCallService { + constructor(appId, region, authKey) { + this.appId = appId; + this.region = region; + this.authKey = authKey; + this.currentCall = null; + } + + // ==================== INITIALIZATION ==================== + + async initialize() { + // Initialize Chat SDK + const chatSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(this.region) + .build(); + + await CometChat.init(this.appId, chatSettings); + console.log("Chat SDK initialized"); + + // Initialize Calls SDK + await CometChatCalls.init({ + appId: this.appId, + region: this.region + }); + console.log("Calls SDK initialized"); + } + + async login(uid) { + const loggedInUser = await CometChat.getLoggedinUser(); + if (loggedInUser) return loggedInUser; + + return await CometChat.login(uid, this.authKey); + } + + // ==================== MESSAGING ==================== + + setupMessageListeners(onMessage) { + CometChat.addMessageListener( + "MESSAGE_LISTENER", + new CometChat.MessageListener({ + onTextMessageReceived: onMessage, + onMediaMessageReceived: onMessage + }) + ); + } + + async sendMessage(receiverUID, text) { + const message = new CometChat.TextMessage( + receiverUID, + text, + CometChat.RECEIVER_TYPE.USER + ); + return await CometChat.sendMessage(message); + } + + // ==================== CALLING ==================== + + setupCallListeners(callbacks) { + CometChat.addCallListener( + "CALL_LISTENER", + new CometChat.CallListener({ + onIncomingCallReceived: (call) => { + this.currentCall = call; + callbacks.onIncomingCall?.(call); + }, + onOutgoingCallAccepted: (call) => { + this.currentCall = call; + callbacks.onCallAccepted?.(call); + this.startCallSession(call, callbacks.callContainer); + }, + onOutgoingCallRejected: (call) => { + this.currentCall = null; + callbacks.onCallRejected?.(call); + }, + onIncomingCallCancelled: (call) => { + this.currentCall = null; + callbacks.onCallCancelled?.(call); + } + }) + ); + } + + async initiateCall(receiverUID, isVideo = true) { + const callType = isVideo ? CometChat.CALL_TYPE.VIDEO : CometChat.CALL_TYPE.AUDIO; + const call = new CometChat.Call( + receiverUID, + callType, + CometChat.RECEIVER_TYPE.USER + ); + + this.currentCall = await CometChat.initiateCall(call); + return this.currentCall; + } + + async acceptCall(container) { + if (!this.currentCall) throw new Error("No incoming call"); + + const sessionId = this.currentCall.getSessionId(); + const acceptedCall = await CometChat.acceptCall(sessionId); + this.currentCall = acceptedCall; + + this.startCallSession(acceptedCall, container); + return acceptedCall; + } + + async rejectCall() { + if (!this.currentCall) return; + + const sessionId = this.currentCall.getSessionId(); + await CometChat.rejectCall(sessionId, CometChat.CALL_STATUS.REJECTED); + this.currentCall = null; + } + + async startCallSession(call, container) { + const sessionId = call.getSessionId(); + const user = await CometChat.getLoggedinUser(); + + const callToken = await CometChatCalls.generateToken( + sessionId, + user.getAuthToken() + ); + + const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIsAudioOnlyCall(call.getType() === CometChat.CALL_TYPE.AUDIO) + .setCallListener(new CometChatCalls.OngoingCallListener({ + onCallEnded: () => this.endCall(), + onCallEndButtonPressed: () => this.endCall(), + onError: (error) => console.error("Call error:", error) + })) + .build(); + + CometChatCalls.startSession(callToken.token, callSettings, container); + } + + async endCall() { + if (!this.currentCall) return; + + const sessionId = this.currentCall.getSessionId(); + + try { + await CometChat.endCall(sessionId); + } catch (e) { + // Call may already be ended + } + + CometChat.clearActiveCall(); + CometChatCalls.endSession(); + this.currentCall = null; + } + + // ==================== CALL CONTROLS ==================== + + muteAudio(mute) { + CometChatCalls.muteAudio(mute); + } + + pauseVideo(pause) { + CometChatCalls.pauseVideo(pause); + } + + startScreenShare() { + CometChatCalls.startScreenShare(); + } + + stopScreenShare() { + CometChatCalls.stopScreenShare(); + } + + // ==================== CLEANUP ==================== + + async logout() { + CometChat.removeMessageListener("MESSAGE_LISTENER"); + CometChat.removeCallListener("CALL_LISTENER"); + await CometChat.logout(); + } +} + +// ==================== USAGE ==================== + +const service = new ChatCallService("APP_ID", "REGION", "AUTH_KEY"); + +// Initialize +await service.initialize(); +await service.login("user_123"); + +// Setup listeners +service.setupMessageListeners((msg) => { + console.log("New message:", msg.getText()); +}); + +service.setupCallListeners({ + callContainer: document.getElementById("call-container"), + onIncomingCall: (call) => { + // Show incoming call UI + if (confirm(`Incoming ${call.getType()} call from ${call.getSender().getName()}. Accept?`)) { + service.acceptCall(document.getElementById("call-container")); + } else { + service.rejectCall(); + } + }, + onCallAccepted: (call) => { + console.log("Call connected"); + }, + onCallRejected: (call) => { + console.log("Call was rejected"); + }, + onCallCancelled: (call) => { + console.log("Call was cancelled"); + } +}); + +// Send a message +await service.sendMessage("user_456", "Hello!"); + +// Start a video call +await service.initiateCall("user_456", true); +``` + +--- + +## Call Flow Diagram + +``` +┌─────────────┐ ┌─────────────┐ +│ Caller │ │ Receiver │ +└─────────────┘ └─────────────┘ + │ │ + │ 1. initiateCall() │ + │ ─────────────────────────────────────────► │ + │ │ + │ 2. onIncomingCallReceived() + │ │ + │ 3. acceptCall() │ + │ ◄───────────────────────────────────────── │ + │ │ + │ 4. onOutgoingCallAccepted() │ + │ │ + │ 5. startCallSession() ◄──────────────────►│ 5. startCallSession() + │ │ + │ ═══════════════════════════════════════ │ + │ AUDIO/VIDEO CONNECTED │ + │ ═══════════════════════════════════════ │ + │ │ + │ 6. endCall() │ + │ ─────────────────────────────────────────► │ + │ │ + │ 7. onCallEnded() │ + │ │ +``` + +--- + +## Next Steps + + + + Record calls for later playback + + + Alert users of incoming calls + + + Create group chats and calls + + + Add content moderation + + diff --git a/sdk/javascript/guide-chat-only.mdx b/sdk/javascript/guide-chat-only.mdx new file mode 100644 index 00000000..82865acc --- /dev/null +++ b/sdk/javascript/guide-chat-only.mdx @@ -0,0 +1,867 @@ +--- +title: "Chat Integration Guide" +sidebarTitle: "Chat Only" +description: "Complete step-by-step guide to integrate text and media messaging" +--- + +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Complete Chat Integration in 5 Steps +// 1. Install +npm install @cometchat/chat-sdk-javascript + +// 2. Initialize (once at app start) +await CometChat.init("APP_ID", new CometChat.AppSettingsBuilder().setRegion("REGION").build()); + +// 3. Login +await CometChat.login("USER_UID", "AUTH_KEY"); // Dev only +// await CometChat.login("AUTH_TOKEN"); // Production + +// 4. Send Message +const msg = new CometChat.TextMessage("RECEIVER_UID", "Hello!", CometChat.RECEIVER_TYPE.USER); +await CometChat.sendMessage(msg); + +// 5. Receive Messages +CometChat.addMessageListener("LISTENER_ID", new CometChat.MessageListener({ + onTextMessageReceived: (msg) => console.log(msg.getText()) +})); +``` + + +This guide walks you through integrating CometChat messaging into your JavaScript application. Follow these steps in order for a smooth integration. + + +**Prerequisites** +- A CometChat account with an app created at [app.cometchat.com](https://app.cometchat.com) +- Your App ID, Region, and Auth Key from the dashboard +- Node.js 14+ or a modern browser + + +--- + +## Step 1: Install the SDK + + + +```bash +npm install @cometchat/chat-sdk-javascript +``` + + +```bash +yarn add @cometchat/chat-sdk-javascript +``` + + +```html + +``` + + + +Import the SDK in your code: + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; +``` + +--- + +## Step 2: Initialize CometChat + +Initialization establishes the connection between your app and CometChat's servers. This step configures the SDK with your app credentials and sets up the WebSocket connection for real-time messaging. + + +**Call `init()` once** at application startup, before any other CometChat methods. Calling it multiple times can cause issues. + + + + +```javascript +const appID = "YOUR_APP_ID"; +const region = "YOUR_REGION"; // "us" or "eu" + +// AppSettingsBuilder configures how the SDK behaves: +// - subscribePresenceForAllUsers(): Receive online/offline status updates for all users +// - setRegion(): Connect to the correct data center (us or eu) +// - autoEstablishSocketConnection(): Automatically connect WebSocket on login +const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + +// init() returns a Promise - the SDK is ready when it resolves +// All other CometChat methods will fail if called before init() completes +CometChat.init(appID, appSettings).then( + () => { + console.log("CometChat initialized successfully"); + // SDK is now ready - you can proceed to login + }, + (error) => { + console.log("Initialization failed:", error); + // Common errors: invalid appID, network issues, wrong region + } +); +``` + + +```typescript +const appID: string = "YOUR_APP_ID"; +const region: string = "YOUR_REGION"; + +// AppSettingsBuilder with TypeScript types for better IDE support +const appSettings: CometChat.AppSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + +CometChat.init(appID, appSettings).then( + (): void => { + console.log("CometChat initialized successfully"); + }, + (error: CometChat.CometChatException): void => { + // CometChatException contains error code and message for debugging + console.log("Initialization failed:", error); + } +); +``` + + +```javascript +async function initCometChat() { + const appID = "YOUR_APP_ID"; + const region = "YOUR_REGION"; + + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + + try { + // await blocks until initialization completes + // This ensures the SDK is ready before proceeding + await CometChat.init(appID, appSettings); + console.log("CometChat initialized successfully"); + return true; + } catch (error) { + // Handle initialization errors (network, invalid credentials, etc.) + console.log("Initialization failed:", error); + return false; + } +} +``` + + + +### What This Code Does + +1. **Creates App Settings**: `AppSettingsBuilder` configures SDK behavior: + - `subscribePresenceForAllUsers()` - Enables real-time online/offline status for all users + - `setRegion()` - Connects to the correct data center (must match your app's region) + - `autoEstablishSocketConnection()` - Automatically opens WebSocket when user logs in + +2. **Initializes the SDK**: `CometChat.init()` performs these operations: + - Validates your App ID and region + - Sets up internal SDK state + - Prepares the WebSocket connection (but doesn't connect yet) + - Returns a Promise that resolves when ready + +| Parameter | Description | +|-----------|-------------| +| `appID` | Your unique App ID from the CometChat dashboard. Found in Dashboard → App Settings | +| `region` | Your app region: `"us"` (United States) or `"eu"` (Europe). Must match your app's region | + +--- + +## Step 3: Create Users (If Needed) + +CometChat maintains its own user database that mirrors your application's users. Before a user can send or receive messages, they must exist in CometChat. This step registers users from your app with CometChat. + + +CometChat doesn't manage your user database. Create users in your backend first, then register them with CometChat using the same UID. This ensures user IDs are consistent across your app and CometChat. + + + +**UID Format**: User IDs can only contain alphanumeric characters, underscores (`_`), and hyphens (`-`). No spaces or special characters allowed. Max 100 characters. + + + + +```javascript +const uid = "user_123"; // Must match the user ID in your app's database +const name = "John Doe"; // Display name shown in chat UI + +// Create a User object with the unique identifier +const user = new CometChat.User(uid); +user.setName(name); // Required: display name for the user + +// createUser() registers this user with CometChat +// The Auth Key is required for user creation (server-side operation) +CometChat.createUser(user, "YOUR_AUTH_KEY").then( + (createdUser) => { + // createdUser contains the full user object with CometChat-assigned properties + console.log("User created:", createdUser); + // User can now login and send/receive messages + }, + (error) => { + // Common errors: duplicate UID, invalid characters in UID, invalid Auth Key + console.log("User creation failed:", error); + } +); +``` + + +```javascript +async function createUser(uid, name) { + // Create User object - uid is the unique identifier, name is the display name + const user = new CometChat.User(uid); + user.setName(name); + + try { + // Register user with CometChat - requires Auth Key + // In production, this should be done on your backend server + const createdUser = await CometChat.createUser(user, "YOUR_AUTH_KEY"); + console.log("User created:", createdUser); + return createdUser; + } catch (error) { + // Handle errors: ERR_UID_ALREADY_EXISTS means user already registered + console.log("User creation failed:", error); + throw error; + } +} +``` + + + +### What This Code Does + +1. **Creates a User Object**: `new CometChat.User(uid)` creates a user representation with: + - `uid` - Unique identifier (should match your app's user ID) + - `name` - Display name shown in chat interfaces + +2. **Registers with CometChat**: `createUser()` sends the user data to CometChat servers: + - Creates a new user record in CometChat's database + - Returns the complete user object with additional CometChat properties + - Fails if the UID already exists (user already registered) + +3. **When to Call This**: + - When a new user signs up in your app + - During initial data migration from your existing user database + - NOT needed if user already exists in CometChat + +--- + +## Step 4: Login + +Login authenticates a user and establishes their real-time connection to CometChat. After login, the user can send/receive messages and their online status becomes visible to others. + + +**Security**: Use Auth Key only during development. In production, generate Auth Tokens on your server and use `CometChat.login(authToken)` instead. Auth Keys have full access to your app and should never be exposed in client-side production code. + + + + +```javascript +async function login(uid) { + // IMPORTANT: Always check for existing session first + // This prevents unnecessary API calls and potential session conflicts + const loggedInUser = await CometChat.getLoggedinUser(); + if (loggedInUser) { + // User already has an active session - reuse it + console.log("Already logged in:", loggedInUser.getName()); + return loggedInUser; + } + + // Login with Auth Key - DEVELOPMENT ONLY + // Auth Key provides full access and should never be in production client code + try { + // login() authenticates the user and establishes WebSocket connection + // Returns the User object with all profile information + const user = await CometChat.login(uid, "YOUR_AUTH_KEY"); + console.log("Login successful:", user.getName()); + return user; + } catch (error) { + // Common errors: invalid UID, user doesn't exist, invalid Auth Key + console.log("Login failed:", error); + throw error; + } +} +``` + + +```javascript +async function loginWithToken(authToken) { + // Check for existing session to avoid unnecessary login calls + const loggedInUser = await CometChat.getLoggedinUser(); + if (loggedInUser) { + console.log("Already logged in:", loggedInUser.getName()); + return loggedInUser; + } + + // Login with Auth Token - PRODUCTION RECOMMENDED + // Auth Token is generated on your server using the REST API + // It's user-specific and can have expiration, making it more secure + try { + // Single-parameter login() uses Auth Token + const user = await CometChat.login(authToken); + console.log("Login successful:", user.getName()); + return user; + } catch (error) { + // Common errors: expired token, invalid token, user doesn't exist + console.log("Login failed:", error); + throw error; + } +} +``` + + + +### What This Code Does + +1. **Checks Existing Session**: `getLoggedinUser()` returns the currently logged-in user or `null`: + - Prevents duplicate login attempts + - Reuses existing WebSocket connection + - Avoids session conflicts + +2. **Authenticates User**: `login()` performs these operations: + - Validates credentials with CometChat servers + - Creates a user session + - Establishes WebSocket connection for real-time messaging + - Returns the User object with profile data + +3. **Two Authentication Methods**: + - **Auth Key** (development): Quick setup, but exposes full app access + - **Auth Token** (production): Generated server-side, user-specific, can expire + + +**Always check `getLoggedinUser()` first** to avoid unnecessary login calls and potential session issues. The SDK maintains session state, so users don't need to login again after page refresh if the session is still valid. + + +--- + +## Step 5: Send Messages + +Sending messages is the core functionality of chat. CometChat supports text messages, media messages (images, videos, audio, files), and custom messages for specialized data. + +### Text Message + +Text messages are the most common message type. They contain plain text content and can be sent to individual users or groups. + + + +```javascript +async function sendTextMessage(receiverUID, text) { + // TextMessage constructor takes 3 parameters: + // 1. receiverUID - The UID of the user who will receive this message + // 2. text - The message content (string) + // 3. receiverType - USER or GROUP (determines routing) + const textMessage = new CometChat.TextMessage( + receiverUID, + text, + CometChat.RECEIVER_TYPE.USER // Indicates this is a 1-on-1 message + ); + + try { + // sendMessage() transmits the message to CometChat servers + // The server routes it to the recipient and stores it for history + // Returns the sent message with server-assigned ID and timestamp + const message = await CometChat.sendMessage(textMessage); + console.log("Message sent:", message); + // message.getId() - unique message ID + // message.getSentAt() - server timestamp + return message; + } catch (error) { + // Common errors: user doesn't exist, network issues, rate limit exceeded + console.log("Message failed:", error); + throw error; + } +} + +// Usage: Send "Hello!" to user with UID "user_456" +await sendTextMessage("user_456", "Hello!"); +``` + + +```javascript +async function sendGroupMessage(groupGUID, text) { + // For group messages, use the group's GUID as the receiver + // RECEIVER_TYPE.GROUP tells CometChat to broadcast to all group members + const textMessage = new CometChat.TextMessage( + groupGUID, + text, + CometChat.RECEIVER_TYPE.GROUP // Broadcasts to all group members + ); + + try { + // Group messages are delivered to all members who are online + // Offline members receive them when they fetch message history + const message = await CometChat.sendMessage(textMessage); + console.log("Message sent:", message); + return message; + } catch (error) { + // Common errors: group doesn't exist, user not a member, banned from group + console.log("Message failed:", error); + throw error; + } +} + +// Usage: Send to group with GUID "group_123" +await sendGroupMessage("group_123", "Hello everyone!"); +``` + + + +### Media Message + +Media messages allow sending files like images, videos, audio recordings, and documents. The SDK handles file upload automatically. + +```javascript +async function sendMediaMessage(receiverUID, file, type) { + // MediaMessage constructor takes 4 parameters: + // 1. receiverUID - Recipient's UID or group GUID + // 2. file - File object (from input element or Blob) + // 3. type - MESSAGE_TYPE.IMAGE, VIDEO, AUDIO, or FILE + // 4. receiverType - USER or GROUP + const mediaMessage = new CometChat.MediaMessage( + receiverUID, + file, + type, // Determines how the file is processed and displayed + CometChat.RECEIVER_TYPE.USER + ); + + try { + // sendMediaMessage() uploads the file to CometChat's servers + // Then sends a message with the file URL to the recipient + // Progress can be tracked with onProgress callback (not shown here) + const message = await CometChat.sendMediaMessage(mediaMessage); + console.log("Media sent:", message); + // message.getAttachment() - contains URL, name, size, mimeType + return message; + } catch (error) { + // Common errors: file too large, unsupported format, network issues + console.log("Media failed:", error); + throw error; + } +} + +// Usage with HTML file input +// +const fileInput = document.getElementById("file-input"); +fileInput.addEventListener("change", async (e) => { + const file = e.target.files[0]; // Get the selected file + // Determine type based on file MIME type + await sendMediaMessage("user_456", file, CometChat.MESSAGE_TYPE.IMAGE); +}); +``` + +### What This Code Does + +1. **Creates Message Object**: Constructs a message with recipient, content, and type +2. **Sends to Server**: `sendMessage()` or `sendMediaMessage()` transmits to CometChat +3. **Server Processing**: CometChat stores the message and routes it to recipients +4. **Returns Confirmation**: The sent message object includes server-assigned ID and timestamp + +| Message Type | Use Case | Max Size | +|--------------|----------|----------| +| `TEXT` | Plain text chat | 64 KB | +| `IMAGE` | Photos, screenshots | 25 MB | +| `VIDEO` | Video clips | 100 MB | +| `AUDIO` | Voice messages | 25 MB | +| `FILE` | Documents, PDFs | 25 MB | + +--- + +## Step 6: Receive Messages + +Real-time message reception is handled through listeners. The SDK maintains a WebSocket connection and invokes your callback functions when events occur. This enables instant message delivery without polling. + + +**Register listeners AFTER login**. Listeners won't work if the user isn't logged in because the WebSocket connection is established during login. + + +```javascript +// Unique ID for this listener - used to remove it later +// Use descriptive IDs like "CHAT_SCREEN_LISTENER" or "NOTIFICATION_LISTENER" +const listenerID = "UNIQUE_LISTENER_ID"; + +// addMessageListener() registers callbacks for various message events +// The SDK calls these functions automatically when events occur +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + // Called when a text message is received from another user + // textMessage contains: sender, text, timestamp, conversation info + onTextMessageReceived: (textMessage) => { + console.log("Text message:", textMessage.getText()); + console.log("From:", textMessage.getSender().getName()); + // Update your UI to display the new message + }, + + // Called when a media message (image, video, etc.) is received + // mediaMessage.getAttachment() contains the file URL and metadata + onMediaMessageReceived: (mediaMessage) => { + console.log("Media message:", mediaMessage.getAttachment()); + // getAttachment() returns: { url, name, size, mimeType, extension } + }, + + // Called when another user starts typing in a conversation with you + // Useful for showing "User is typing..." indicator + onTypingStarted: (typingIndicator) => { + console.log(`${typingIndicator.getSender().getName()} is typing...`); + // Show typing indicator in UI + }, + + // Called when the user stops typing (after ~5 seconds of inactivity) + onTypingEnded: (typingIndicator) => { + console.log(`${typingIndicator.getSender().getName()} stopped typing`); + // Hide typing indicator in UI + }, + + // Called when your sent messages are delivered to the recipient's device + // Useful for showing delivery checkmarks (✓✓) + onMessagesDelivered: (messageReceipt) => { + console.log("Delivered:", messageReceipt.getMessageId()); + // Update message status in UI to "delivered" + }, + + // Called when the recipient has read your messages + // Useful for showing read receipts (blue checkmarks) + onMessagesRead: (messageReceipt) => { + console.log("Read:", messageReceipt.getMessageId()); + // Update message status in UI to "read" + } + }) +); + +// IMPORTANT: Remove listener when no longer needed +// This prevents memory leaks and duplicate event handling +// Call this on component unmount or when navigating away +// CometChat.removeMessageListener(listenerID); +``` + +### What This Code Does + +1. **Registers Event Handlers**: `addMessageListener()` subscribes to real-time events +2. **WebSocket Events**: The SDK receives events via WebSocket and invokes your callbacks +3. **Multiple Listeners**: You can register multiple listeners with different IDs for different parts of your app + +### Event Types Explained + +| Event | When It Fires | Common Use | +|-------|---------------|------------| +| `onTextMessageReceived` | New text message arrives | Display in chat UI | +| `onMediaMessageReceived` | New media message arrives | Display image/video preview | +| `onTypingStarted` | User begins typing | Show "typing..." indicator | +| `onTypingEnded` | User stops typing | Hide typing indicator | +| `onMessagesDelivered` | Message reaches recipient | Show ✓✓ checkmarks | +| `onMessagesRead` | Recipient reads message | Show blue checkmarks | + + +**Listener Lifecycle**: Register listeners after login, remove them on logout or component unmount. Using unique IDs allows you to manage multiple listeners independently. + + +--- + +## Step 7: Fetch Message History + +When a user opens a conversation, you need to load previous messages. The `MessagesRequestBuilder` provides a paginated way to fetch message history with various filtering options. + +```javascript +async function fetchMessages(uid, limit = 30) { + // MessagesRequestBuilder configures what messages to fetch + // setUID() - Fetch messages from a specific user conversation + // setLimit() - Number of messages per page (max 100) + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(uid) // For user conversations - use setGUID() for groups + .setLimit(limit) // How many messages to fetch (default 30, max 100) + .build(); // Creates the request object + + try { + // fetchPrevious() retrieves older messages (pagination going backward) + // Returns an array of message objects sorted by timestamp (oldest first) + // Call fetchPrevious() again on the same request object to get the next page + const messages = await messagesRequest.fetchPrevious(); + console.log("Messages:", messages); + // Each message has: getId(), getText(), getSender(), getSentAt(), etc. + return messages; + } catch (error) { + // Common errors: invalid UID, network issues + console.log("Fetch failed:", error); + throw error; + } +} + +// For group conversations, use setGUID() instead of setUID() +async function fetchGroupMessages(guid, limit = 30) { + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(guid) // Group's unique identifier + .setLimit(limit) + .build(); + + const messages = await messagesRequest.fetchPrevious(); + return messages; +} +``` + +### What This Code Does + +1. **Builds Request**: `MessagesRequestBuilder` configures the query parameters +2. **Fetches Messages**: `fetchPrevious()` retrieves messages from the server +3. **Pagination**: Calling `fetchPrevious()` again on the same request gets the next page +4. **Returns Array**: Messages are returned as an array, oldest first + +### Additional Filtering Options + +```javascript +// Advanced message fetching with filters +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(uid) + .setLimit(50) + .setMessageId(lastMessageId) // Fetch messages before this ID + .setTimestamp(timestamp) // Fetch messages before this time + .hideDeletedMessages(true) // Exclude deleted messages + .setCategories(["message"]) // Only fetch regular messages + .setTypes(["text", "image"]) // Only text and image messages + .build(); +``` + +| Method | Description | +|--------|-------------| +| `setUID(uid)` | Fetch messages from a user conversation | +| `setGUID(guid)` | Fetch messages from a group conversation | +| `setLimit(n)` | Number of messages per page (max 100) | +| `setMessageId(id)` | Fetch messages before/after this message | +| `hideDeletedMessages(true)` | Exclude deleted messages | +| `setCategories([...])` | Filter by message category | +| `setTypes([...])` | Filter by message type | + +--- + +## Step 8: Logout + +Logout ends the user's session and disconnects from CometChat. This should be called when the user signs out of your application. + +```javascript +async function logout() { + try { + // logout() performs these operations: + // 1. Closes the WebSocket connection + // 2. Clears the local session data + // 3. Notifies the server to end the session + // 4. User's status changes to "offline" for other users + await CometChat.logout(); + console.log("Logout successful"); + // Redirect to login page or update UI + } catch (error) { + // Logout rarely fails, but handle it gracefully + console.log("Logout failed:", error); + } +} +``` + +### What This Code Does + +1. **Closes WebSocket**: Disconnects the real-time connection +2. **Clears Session**: Removes local authentication state +3. **Updates Status**: User appears offline to other users +4. **Cleanup**: Prepares for a new user to login + + +**Best Practice**: Remove all message listeners before logout to prevent memory leaks and ensure clean state for the next user. + + +```javascript +// Complete logout with cleanup +async function cleanLogout() { + // Remove all listeners first + CometChat.removeMessageListener("CHAT_LISTENER"); + CometChat.removeUserListener("USER_LISTENER"); + CometChat.removeGroupListener("GROUP_LISTENER"); + + // Then logout + await CometChat.logout(); +} +``` + +--- + +## Complete Integration Example + +This example shows a complete `ChatService` class that encapsulates all CometChat functionality. Use this as a reference for structuring your integration. + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +/** + * ChatService - A complete wrapper for CometChat SDK + * + * This class provides a clean interface for: + * - Initializing the SDK + * - User authentication + * - Sending and receiving messages + * - Managing listeners + * + * Usage: + * const chat = new ChatService("APP_ID", "REGION", "AUTH_KEY"); + * await chat.initialize(); + * await chat.login("user_123"); + * chat.setupListeners((msg) => console.log(msg)); + * await chat.sendMessage("user_456", "Hello!"); + */ +class ChatService { + constructor(appID, region, authKey) { + this.appID = appID; + this.region = region; + this.authKey = authKey; + this.listenerID = "CHAT_LISTENER"; + } + + /** + * Initialize CometChat SDK + * Must be called once before any other operations + * Typically called at app startup + */ + async initialize() { + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() // Enable presence updates + .setRegion(this.region) // Connect to correct data center + .build(); + + await CometChat.init(this.appID, appSettings); + console.log("CometChat initialized"); + } + + /** + * Login a user to CometChat + * Checks for existing session first to avoid duplicate logins + * @param {string} uid - User's unique identifier + * @returns {CometChat.User} - The logged in user object + */ + async login(uid) { + // Check for existing session + const loggedInUser = await CometChat.getLoggedinUser(); + if (loggedInUser) return loggedInUser; + + // Perform login + return await CometChat.login(uid, this.authKey); + } + + /** + * Register message listeners for real-time updates + * Call this after login to start receiving messages + * @param {Function} onMessage - Callback for new messages + */ + setupListeners(onMessage) { + CometChat.addMessageListener( + this.listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: onMessage, // Text messages + onMediaMessageReceived: onMessage // Media messages + }) + ); + } + + /** + * Send a text message to another user + * @param {string} receiverUID - Recipient's user ID + * @param {string} text - Message content + * @returns {CometChat.TextMessage} - The sent message + */ + async sendMessage(receiverUID, text) { + const message = new CometChat.TextMessage( + receiverUID, + text, + CometChat.RECEIVER_TYPE.USER + ); + return await CometChat.sendMessage(message); + } + + /** + * Fetch message history for a conversation + * @param {string} uid - User ID to fetch messages from + * @param {number} limit - Number of messages to fetch + * @returns {Array} - Array of message objects + */ + async fetchMessages(uid, limit = 30) { + const request = new CometChat.MessagesRequestBuilder() + .setUID(uid) + .setLimit(limit) + .build(); + return await request.fetchPrevious(); + } + + /** + * Logout and cleanup + * Removes listeners and ends the session + */ + async logout() { + CometChat.removeMessageListener(this.listenerID); + await CometChat.logout(); + } +} + +// ============================================ +// USAGE EXAMPLE +// ============================================ + +// 1. Create service instance with your credentials +const chat = new ChatService("APP_ID", "REGION", "AUTH_KEY"); + +// 2. Initialize SDK (do this once at app startup) +await chat.initialize(); + +// 3. Login user (after user authenticates in your app) +await chat.login("user_123"); + +// 4. Setup listeners to receive real-time messages +chat.setupListeners((msg) => { + console.log("New message:", msg); + // Update your UI here +}); + +// 5. Send a message +await chat.sendMessage("user_456", "Hello!"); + +// 6. Fetch message history when opening a conversation +const messages = await chat.fetchMessages("user_456", 50); + +// 7. Logout when user signs out +await chat.logout(); +``` + +### Code Structure Explained + +| Method | Purpose | When to Call | +|--------|---------|--------------| +| `constructor()` | Store credentials | Once when creating instance | +| `initialize()` | Setup SDK | Once at app startup | +| `login()` | Authenticate user | After user signs in | +| `setupListeners()` | Enable real-time | After login | +| `sendMessage()` | Send chat message | When user sends | +| `fetchMessages()` | Load history | When opening conversation | +| `logout()` | End session | When user signs out | + +--- + +## Next Steps + + + + Create and manage group conversations + + + Show real-time typing status + + + Track message delivery and read status + + + Add voice and video calling + + diff --git a/sdk/javascript/guide-moderation.mdx b/sdk/javascript/guide-moderation.mdx new file mode 100644 index 00000000..0ffd6584 --- /dev/null +++ b/sdk/javascript/guide-moderation.mdx @@ -0,0 +1,816 @@ +--- +title: "Moderation Integration Guide" +sidebarTitle: "Moderation" +description: "Complete step-by-step guide to integrate AI-powered content moderation" +--- + +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Moderation is automatic once enabled in Dashboard +// 1. Enable moderation in CometChat Dashboard → Moderation → Rules + +// 2. Check moderation status when sending +const message = await CometChat.sendMessage(textMessage); +if (message.getModerationStatus() === CometChat.ModerationStatus.PENDING) { + console.log("Message under review"); +} + +// 3. Listen for moderation results +CometChat.addMessageListener("MOD_LISTENER", new CometChat.MessageListener({ + onMessageModerated: (msg) => { + const status = msg.getModerationStatus(); + // APPROVED, DISAPPROVED, or PENDING + } +})); + +// 4. Manual flagging by users +await CometChat.flagMessage(message); +``` + + +This guide walks you through integrating CometChat's AI-powered moderation to automatically review messages for inappropriate content and allow users to flag messages manually. + + +**Prerequisites** +- CometChat SDK already integrated (see [Chat Integration Guide](/sdk/javascript/guide-chat-only)) +- Moderation enabled in your CometChat plan +- Access to the [CometChat Dashboard](https://app.cometchat.com) + + +--- + +## Overview + +CometChat Moderation provides two types of content review: + +| Type | Description | Trigger | +|------|-------------|---------| +| **AI Moderation** | Automatic review of text, images, and videos | Automatic on send | +| **User Flagging** | Manual reporting by users | User action | + +--- + +## Step 1: Enable Moderation in Dashboard + +1. Go to [app.cometchat.com](https://app.cometchat.com) +2. Select your app +3. Navigate to **Moderation → Rules** +4. Enable moderation and configure rules: + - Profanity filter + - Spam detection + - Image/video content analysis + - Custom keywords + + +Moderation rules are configured in the dashboard, not in code. The SDK automatically applies these rules to messages. + + +--- + +## Step 2: Understand Moderation Status + +When moderation is enabled, every text, image, and video message goes through review: + +```javascript +// Moderation statuses +CometChat.ModerationStatus.PENDING // Under review +CometChat.ModerationStatus.APPROVED // Passed moderation +CometChat.ModerationStatus.DISAPPROVED // Blocked by moderation +``` + +### Message Flow with Moderation + +``` +User sends message + │ + ▼ +┌─────────────────┐ +│ Message sent │ +│ Status: PENDING │ +└─────────────────┘ + │ + ▼ +┌─────────────────┐ +│ AI Moderation │ +│ Reviews content │ +└─────────────────┘ + │ + ├──────────────────┐ + ▼ ▼ +┌─────────────┐ ┌──────────────┐ +│ APPROVED │ │ DISAPPROVED │ +│ Message │ │ Message │ +│ visible │ │ blocked │ +└─────────────┘ └──────────────┘ +``` + +--- + +## Step 3: Check Moderation Status on Send + +When moderation is enabled, messages are reviewed before being delivered. Check the moderation status after sending to know if the message is pending review, approved, or blocked. + + + +```javascript +/** + * Send a message and handle moderation status + * Messages may be immediately approved, pending review, or blocked + * + * @param {string} receiverUID - Recipient's user ID + * @param {string} text - Message content + * @returns {Object} - Message and moderation status + */ +async function sendModeratedMessage(receiverUID, text) { + // Create a standard text message + const textMessage = new CometChat.TextMessage( + receiverUID, + text, + CometChat.RECEIVER_TYPE.USER + ); + + try { + // Send the message - it goes through moderation automatically + const message = await CometChat.sendMessage(textMessage); + + // Check the moderation status + // This tells you what happened to the message + const status = message.getModerationStatus(); + + switch (status) { + case CometChat.ModerationStatus.PENDING: + // Message is being reviewed by AI moderation + // It will be delivered if approved, blocked if not + // Listen for onMessageModerated to get the final result + console.log("Message under moderation review"); + return { message, pending: true }; + + case CometChat.ModerationStatus.APPROVED: + // Message passed moderation immediately + // This happens when content is clearly safe + console.log("Message approved immediately"); + return { message, pending: false }; + + case CometChat.ModerationStatus.DISAPPROVED: + // Message was blocked immediately + // This is rare on send - usually happens via listener + // Content clearly violated moderation rules + console.log("Message blocked"); + return { message, blocked: true }; + } + } catch (error) { + console.log("Send failed:", error); + throw error; + } +} +``` + + +```typescript +interface ModerationResult { + message: CometChat.TextMessage; + pending?: boolean; + blocked?: boolean; +} + +/** + * Send a message with moderation status handling + * Returns the message and its moderation state + */ +async function sendModeratedMessage( + receiverUID: string, + text: string +): Promise { + const textMessage = new CometChat.TextMessage( + receiverUID, + text, + CometChat.RECEIVER_TYPE.USER + ); + + const message = await CometChat.sendMessage(textMessage); + const status = message.getModerationStatus(); + + switch (status) { + case CometChat.ModerationStatus.PENDING: + // Message queued for AI review + return { message, pending: true }; + case CometChat.ModerationStatus.APPROVED: + // Message passed moderation + return { message, pending: false }; + case CometChat.ModerationStatus.DISAPPROVED: + // Message blocked by moderation + return { message, blocked: true }; + default: + return { message }; + } +} +``` + + + +### What This Code Does + +1. **Sends Message**: `sendMessage()` transmits the message through CometChat +2. **Triggers Moderation**: AI automatically reviews the content +3. **Returns Status**: `getModerationStatus()` tells you the result +4. **Enables UI Updates**: You can show pending indicators or blocked notices + +### Moderation Status Values + +| Status | Meaning | UI Action | +|--------|---------|-----------| +| `PENDING` | Under AI review | Show "reviewing..." indicator | +| `APPROVED` | Passed moderation | Display normally | +| `DISAPPROVED` | Blocked by moderation | Show blocked notice or hide | + +--- + +## Step 4: Listen for Moderation Results + +Register a listener to receive real-time moderation decisions. This is essential for updating your UI when pending messages are approved or blocked. + + + +```javascript +const listenerID = "MODERATION_LISTENER"; + +// addMessageListener() registers callbacks for message events +// including moderation results +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + // ==================== MODERATION RESULTS ==================== + // Called when a pending message gets a final moderation decision + // This fires for YOUR messages that were pending review + onMessageModerated: (message) => { + const messageId = message.getId(); + const status = message.getModerationStatus(); + + switch (status) { + case CometChat.ModerationStatus.APPROVED: + // Message passed moderation - it will be delivered + console.log(`Message ${messageId} approved`); + // Update UI - remove pending indicator, show as sent + updateMessageStatus(messageId, "approved"); + break; + + case CometChat.ModerationStatus.DISAPPROVED: + // Message was blocked - it won't be delivered + console.log(`Message ${messageId} blocked`); + // Update UI - show blocked notice or remove message + handleBlockedMessage(messageId, message); + break; + } + }, + + // ==================== INCOMING MESSAGES ==================== + // Called when you receive a message from another user + // These have already passed moderation (or are pending) + onTextMessageReceived: (textMessage) => { + const status = textMessage.getModerationStatus(); + + if (status === CometChat.ModerationStatus.APPROVED) { + // Message passed moderation - safe to display + displayMessage(textMessage); + } else if (status === CometChat.ModerationStatus.PENDING) { + // Message is still being reviewed + // Optionally show with a pending indicator + displayMessage(textMessage, { pending: true }); + } + // Don't display DISAPPROVED messages from others + // They shouldn't reach you, but handle just in case + }, + + // Also handle media messages the same way + onMediaMessageReceived: (mediaMessage) => { + const status = mediaMessage.getModerationStatus(); + if (status === CometChat.ModerationStatus.APPROVED) { + displayMessage(mediaMessage); + } + } + }) +); + +// IMPORTANT: Remove listener when done to prevent memory leaks +// CometChat.removeMessageListener(listenerID); +``` + + +```typescript +const listenerID: string = "MODERATION_LISTENER"; + +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + // Handle moderation decisions for your sent messages + onMessageModerated: (message: CometChat.BaseMessage): void => { + const messageId = message.getId(); + const status = message.getModerationStatus(); + + switch (status) { + case CometChat.ModerationStatus.APPROVED: + // Message approved - update UI to show as sent + updateMessageStatus(messageId, "approved"); + break; + case CometChat.ModerationStatus.DISAPPROVED: + // Message blocked - show notice or remove + handleBlockedMessage(messageId, message); + break; + } + }, + + // Handle incoming messages (already moderated) + onTextMessageReceived: (textMessage: CometChat.TextMessage): void => { + const status = textMessage.getModerationStatus(); + + if (status === CometChat.ModerationStatus.APPROVED) { + displayMessage(textMessage); + } + // Skip DISAPPROVED messages + } + }) +); +``` + + + +### What This Code Does + +1. **Listens for Moderation Results**: `onMessageModerated` fires when pending messages get a decision +2. **Handles Incoming Messages**: `onTextMessageReceived` includes moderation status +3. **Filters Blocked Content**: Only displays approved messages +4. **Updates UI**: Removes pending indicators or shows blocked notices + +### Event Flow + +| Event | When It Fires | Your Action | +|-------|---------------|-------------| +| `onMessageModerated` | Your pending message gets approved/blocked | Update message status in UI | +| `onTextMessageReceived` | You receive a message | Check status before displaying | +| `onMediaMessageReceived` | You receive media | Check status before displaying | + + +**Incoming Messages**: Messages you receive from others have usually already passed moderation. The `DISAPPROVED` status on incoming messages is rare but possible if moderation rules change. + + +--- + +## Step 5: Handle Blocked Messages + +When a message is disapproved by moderation, decide how to handle it in your UI. The approach differs based on whether it's your message or someone else's. + +```javascript +/** + * Handle a message that was blocked by moderation + * Different handling for sender vs receiver + * + * @param {string} messageId - The blocked message's ID + * @param {CometChat.BaseMessage} message - The blocked message object + */ +function handleBlockedMessage(messageId, message) { + const sender = message.getSender(); + const currentUser = CometChat.getLoggedinUser(); + + if (sender.getUid() === currentUser.getUid()) { + // ==================== YOUR MESSAGE WAS BLOCKED ==================== + // This means your message violated moderation rules + // You should inform the user why their message wasn't sent + + // Option 1: Show a notification explaining the block + // Best for: Transparent communication with users + showNotification("Your message was blocked due to policy violation"); + + // Option 2: Replace the message content with a notice + // Best for: Keeping message in timeline but showing it was blocked + replaceMessageContent(messageId, "This message was blocked"); + + // Option 3: Remove the message from the UI entirely + // Best for: Clean UI, but user might be confused + removeMessageFromUI(messageId); + + } else { + // ==================== SOMEONE ELSE'S MESSAGE WAS BLOCKED ==================== + // This is rare - blocked messages usually don't reach you + // But handle it just in case (e.g., moderation rules changed) + + // Simply don't display it or remove if already shown + removeMessageFromUI(messageId); + } +} + +/** + * Update a message's visual status in the UI + * Used to remove pending indicators when moderation completes + * + * @param {string} messageId - The message ID + * @param {string} status - New status ("approved", "blocked", etc.) + */ +function updateMessageStatus(messageId, status) { + // Find the message element in your UI + const messageElement = document.querySelector(`[data-message-id="${messageId}"]`); + + if (messageElement) { + // Remove pending indicator + messageElement.classList.remove("pending"); + + // Add new status class for styling + messageElement.classList.add(status); + + // If approved, you might want to remove any "reviewing..." text + const pendingBadge = messageElement.querySelector(".pending-badge"); + if (pendingBadge) { + pendingBadge.remove(); + } + } +} +``` + +### What This Code Does + +1. **Identifies Sender**: Checks if the blocked message is yours or someone else's +2. **Handles Your Blocked Messages**: Shows notification, replaces content, or removes +3. **Handles Others' Blocked Messages**: Simply removes from UI +4. **Updates Visual Status**: Removes pending indicators when moderation completes + +### Handling Strategies + +| Strategy | Pros | Cons | Best For | +|----------|------|------|----------| +| **Notification** | Clear communication | Interrupts user | Transparent apps | +| **Replace Content** | Message stays in timeline | Takes up space | Audit trails | +| **Remove Message** | Clean UI | User confusion | Minimal UI | + + +**User Experience**: Be transparent with users about why their message was blocked. Vague messages like "Something went wrong" lead to frustration. Clear messages like "Your message was blocked due to community guidelines" help users understand and adjust their behavior. + + +--- + +## Step 6: User Flagging (Manual Reports) + +In addition to AI moderation, allow users to manually flag inappropriate messages. This creates a community-driven moderation layer where users can report content that AI might miss. + + + +```javascript +/** + * Flag a message for manual review + * This reports the message to moderators for human review + * + * @param {CometChat.BaseMessage} message - The message to flag + * @returns {boolean} - true if flagged successfully + */ +async function flagMessage(message) { + try { + // flagMessage() reports this message to CometChat's moderation system + // The message will appear in Dashboard → Moderation → Flagged Messages + // Moderators can then review and take action + await CometChat.flagMessage(message); + console.log("Message flagged successfully"); + + // Update UI to show the message was reported + // This provides feedback to the user who reported it + showNotification("Message reported. Thank you for helping keep our community safe."); + + return true; + } catch (error) { + console.log("Flag failed:", error); + + // Handle specific error cases + if (error.code === "ERR_ALREADY_FLAGGED") { + // User already reported this message + showNotification("You've already reported this message"); + } else if (error.code === "ERR_CANNOT_FLAG_OWN_MESSAGE") { + // Can't flag your own messages + showNotification("You cannot report your own messages"); + } else { + showNotification("Failed to report message. Please try again."); + } + + return false; + } +} + +// ==================== USAGE EXAMPLE ==================== +// Typically triggered from a context menu or report button + +// Add click handler to report button +const reportButton = document.getElementById("report-btn"); +reportButton.addEventListener("click", () => { + // selectedMessage is the message the user right-clicked or long-pressed + flagMessage(selectedMessage); +}); +``` + + +```jsx +import { useState } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +/** + * MessageActions Component + * Provides action buttons for a message, including report + * + * @param {Object} props + * @param {CometChat.BaseMessage} props.message - The message to act on + */ +function MessageActions({ message }) { + const [flagged, setFlagged] = useState(false); + const [loading, setLoading] = useState(false); + + /** + * Handle the flag/report action + * Flags the message and updates UI state + */ + const handleFlag = async () => { + setLoading(true); + + try { + // Flag the message for moderator review + await CometChat.flagMessage(message); + setFlagged(true); + + // Show success feedback + alert("Message reported successfully. Thank you for helping keep our community safe."); + } catch (error) { + if (error.code === "ERR_ALREADY_FLAGGED") { + // Already reported - update UI to reflect this + setFlagged(true); + alert("You've already reported this message"); + } else { + alert("Failed to report message. Please try again."); + } + } finally { + setLoading(false); + } + }; + + return ( +
+ +
+ ); +} + +export default MessageActions; +``` +
+
+ +### What This Code Does + +1. **Reports Message**: `flagMessage()` sends the message to CometChat's moderation queue +2. **Handles Errors**: Catches duplicate reports and other error cases +3. **Updates UI**: Shows feedback to the user who reported +4. **Prevents Duplicates**: Tracks flagged state to prevent re-reporting + +### Flagging Best Practices + +| Practice | Description | +|----------|-------------| +| **Confirm Action** | Consider showing a confirmation dialog before flagging | +| **Provide Feedback** | Always tell users their report was received | +| **Prevent Abuse** | Track flagged messages to prevent spam reporting | +| **Easy Access** | Make the report option easy to find but not accidental | + + +**Moderator Review**: Flagged messages appear in the CometChat Dashboard under Moderation → Flagged Messages. Moderators can review each report and take action (approve, delete, or ban user). + + +--- + +## Step 7: Review Flagged Messages (Admin) + +Flagged messages can be reviewed in the CometChat Dashboard: + +1. Go to **Moderation → Flagged Messages** +2. Review each flagged message +3. Take action: Approve, Delete, or Ban User + + +For programmatic access to flagged messages, use the [CometChat REST API](/rest-api/moderation). + + +--- + +## Complete Integration Example + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +class ModeratedChatService { + constructor() { + this.pendingMessages = new Map(); + this.listenerID = "MODERATION_LISTENER"; + } + + setupModerationListeners(callbacks) { + CometChat.addMessageListener( + this.listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: (message) => { + this.handleIncomingMessage(message, callbacks); + }, + + onMediaMessageReceived: (message) => { + this.handleIncomingMessage(message, callbacks); + }, + + onMessageModerated: (message) => { + this.handleModerationResult(message, callbacks); + } + }) + ); + } + + handleIncomingMessage(message, callbacks) { + const status = message.getModerationStatus(); + + switch (status) { + case CometChat.ModerationStatus.APPROVED: + callbacks.onMessageReceived?.(message); + break; + + case CometChat.ModerationStatus.PENDING: + // Optionally show with indicator + callbacks.onMessageReceived?.(message, { pending: true }); + break; + + case CometChat.ModerationStatus.DISAPPROVED: + // Don't display blocked messages from others + console.log("Blocked message not displayed"); + break; + } + } + + handleModerationResult(message, callbacks) { + const messageId = message.getId(); + const status = message.getModerationStatus(); + + // Remove from pending tracking + this.pendingMessages.delete(messageId); + + if (status === CometChat.ModerationStatus.APPROVED) { + callbacks.onMessageApproved?.(message); + } else if (status === CometChat.ModerationStatus.DISAPPROVED) { + callbacks.onMessageBlocked?.(message); + } + } + + async sendMessage(receiverUID, text) { + const textMessage = new CometChat.TextMessage( + receiverUID, + text, + CometChat.RECEIVER_TYPE.USER + ); + + const message = await CometChat.sendMessage(textMessage); + const status = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.PENDING) { + this.pendingMessages.set(message.getId(), message); + } + + return { + message, + status, + isPending: status === CometChat.ModerationStatus.PENDING + }; + } + + async flagMessage(message) { + try { + await CometChat.flagMessage(message); + return { success: true }; + } catch (error) { + return { + success: false, + alreadyFlagged: error.code === "ERR_ALREADY_FLAGGED", + error + }; + } + } + + cleanup() { + CometChat.removeMessageListener(this.listenerID); + } +} + +// Usage +const moderatedChat = new ModeratedChatService(); + +moderatedChat.setupModerationListeners({ + onMessageReceived: (message, options) => { + console.log("New message:", message.getText()); + if (options?.pending) { + console.log("(pending moderation)"); + } + // Add to UI + }, + + onMessageApproved: (message) => { + console.log("Message approved:", message.getId()); + // Update UI - remove pending indicator + }, + + onMessageBlocked: (message) => { + console.log("Message blocked:", message.getId()); + // Update UI - show blocked notice or remove + } +}); + +// Send a message +const result = await moderatedChat.sendMessage("user_456", "Hello!"); +if (result.isPending) { + console.log("Message sent, awaiting moderation..."); +} + +// Flag a message +const flagResult = await moderatedChat.flagMessage(someMessage); +if (flagResult.success) { + console.log("Message reported"); +} +``` + +--- + +## Moderation Best Practices + + + + Let users know their message is being reviewed: + + ```javascript + // Show a subtle indicator +
+ {messageText} + {isPending && Reviewing...} +
+ ``` +
+ + + Don't just silently remove messages - inform the sender: + + ```javascript + if (message.getSender().getUid() === currentUser.getUid()) { + showNotification("Your message couldn't be sent due to community guidelines"); + } + ``` + + + + Make it easy for users to report inappropriate content: + + ```javascript + // Add to message context menu + flagMessage(message)}> + Report Message + + ``` + + + + Configure rules carefully in the dashboard to avoid false positives. Start with basic rules and adjust based on your community's needs. + +
+ +--- + +## Supported Message Types + +| Message Type | AI Moderation | User Flagging | +|--------------|---------------|---------------| +| Text Messages | ✅ | ✅ | +| Image Messages | ✅ | ✅ | +| Video Messages | ✅ | ✅ | +| Audio Messages | ❌ | ✅ | +| Custom Messages | ❌ | ✅ | + +--- + +## Next Steps + + + + Let users block other users + + + Moderate group conversations + + + Get notified of moderation events + + + Programmatic moderation management + + diff --git a/sdk/javascript/guide-notifications.mdx b/sdk/javascript/guide-notifications.mdx new file mode 100644 index 00000000..0e7a232b --- /dev/null +++ b/sdk/javascript/guide-notifications.mdx @@ -0,0 +1,1050 @@ +--- +title: "Push Notifications Guide" +sidebarTitle: "Notifications" +description: "Complete step-by-step guide to integrate push notifications for messages and calls" +--- + +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Push notifications require: +// 1. Firebase Cloud Messaging (FCM) setup +// 2. CometChat Dashboard configuration +// 3. Client-side token registration + +// Register FCM token with CometChat +await CometChat.registerTokenForPushNotification(fcmToken); + +// Handle notification when app is in foreground +messaging.onMessage((payload) => { + const data = payload.data; + if (data.type === "chat") { + showNotification(data.title, data.body); + } else if (data.type === "call") { + showIncomingCallUI(data); + } +}); + +// Unregister on logout +await CometChat.unregisterTokenForPushNotification(fcmToken); +``` + + +This guide walks you through integrating push notifications to alert users of new messages and incoming calls when your app is in the background or closed. + + +**Prerequisites** +- CometChat SDK already integrated +- Firebase project with Cloud Messaging enabled +- Push notifications enabled in your CometChat plan + + +--- + +## Overview + +Push notifications ensure users never miss important messages or calls: + +| Scenario | Without Push | With Push | +|----------|--------------|-----------| +| App in foreground | ✅ Real-time listeners | ✅ Real-time listeners | +| App in background | ❌ No alerts | ✅ Push notification | +| App closed | ❌ No alerts | ✅ Push notification | + +--- + +## Step 1: Set Up Firebase Cloud Messaging + +### 1a. Create Firebase Project + +1. Go to [Firebase Console](https://console.firebase.google.com) +2. Create a new project or select existing +3. Navigate to **Project Settings → Cloud Messaging** +4. Note your **Server Key** and **Sender ID** + +### 1b. Add Firebase to Your App + + + +```bash +npm install firebase +``` + + +```html + + +``` + + + +### 1c. Initialize Firebase + +```javascript +import { initializeApp } from "firebase/app"; +import { getMessaging, getToken, onMessage } from "firebase/messaging"; + +const firebaseConfig = { + apiKey: "YOUR_API_KEY", + authDomain: "YOUR_PROJECT.firebaseapp.com", + projectId: "YOUR_PROJECT_ID", + storageBucket: "YOUR_PROJECT.appspot.com", + messagingSenderId: "YOUR_SENDER_ID", + appId: "YOUR_APP_ID" +}; + +const app = initializeApp(firebaseConfig); +const messaging = getMessaging(app); +``` + +--- + +## Step 2: Configure CometChat Dashboard + +1. Go to [app.cometchat.com](https://app.cometchat.com) +2. Select your app +3. Navigate to **Notifications → Push Notifications** +4. Enable push notifications +5. Add your Firebase credentials: + - **FCM Server Key**: From Firebase Console + - **FCM Sender ID**: From Firebase Console + +--- + +## Step 3: Request Notification Permission + +Before you can show push notifications, you must request permission from the user. Browsers require explicit user consent for notifications. + +```javascript +/** + * Request permission to show notifications + * Must be called in response to a user action (click, tap) + * + * @returns {boolean} - true if permission granted + */ +async function requestNotificationPermission() { + try { + // Notification.requestPermission() shows the browser's permission dialog + // Returns: "granted", "denied", or "default" + // + // IMPORTANT: This must be triggered by a user action (click, tap) + // Calling it on page load will likely be blocked by the browser + const permission = await Notification.requestPermission(); + + if (permission === "granted") { + // User allowed notifications + // You can now show notifications and register for push + console.log("Notification permission granted"); + return true; + } else if (permission === "denied") { + // User blocked notifications + // You cannot show notifications or request again + // User must manually enable in browser settings + console.log("Notification permission denied"); + return false; + } else { + // permission === "default" + // User dismissed the dialog without choosing + // You can ask again later + console.log("Notification permission dismissed"); + return false; + } + } catch (error) { + // Some browsers don't support notifications + console.log("Permission request failed:", error); + return false; + } +} + +// ==================== USAGE ==================== +// Call this when user clicks "Enable Notifications" button +// NOT on page load - browsers block unprompted permission requests + +document.getElementById("enable-notifications-btn").addEventListener("click", async () => { + const granted = await requestNotificationPermission(); + if (granted) { + // Proceed to get FCM token and register + await registerPushNotifications(); + } else { + // Show message explaining how to enable manually + showMessage("To receive notifications, please enable them in your browser settings."); + } +}); +``` + +### What This Code Does + +1. **Requests Permission**: Shows the browser's notification permission dialog +2. **Handles Response**: Processes granted, denied, or dismissed states +3. **Returns Result**: Lets you know if you can proceed with registration + +### Permission States + +| State | Meaning | Can Request Again? | +|-------|---------|-------------------| +| `granted` | User allowed notifications | N/A - already allowed | +| `denied` | User blocked notifications | No - must change in settings | +| `default` | User dismissed dialog | Yes - can ask again | + + +**User Action Required**: Modern browsers block notification permission requests that aren't triggered by user interaction. Always request permission in response to a button click or similar action. + + +--- + +## Step 4: Get FCM Token + +The FCM (Firebase Cloud Messaging) token uniquely identifies this browser/device for push notifications. Firebase uses this token to route notifications to the correct recipient. + +```javascript +import { getToken } from "firebase/messaging"; + +/** + * Get the FCM token for this browser/device + * This token is used to send push notifications to this specific client + * + * @returns {string|null} - The FCM token, or null if failed + */ +async function getFCMToken() { + try { + // getToken() requests a unique token from Firebase + // The VAPID key authenticates your app with Firebase + // + // This token: + // - Is unique to this browser on this device + // - May change if user clears browser data + // - Should be sent to your server and CometChat + const token = await getToken(messaging, { + vapidKey: "YOUR_VAPID_KEY" // From Firebase Console → Web Push certificates + }); + + if (token) { + console.log("FCM Token:", token); + // Token looks like: "dGVzdC10b2tlbi1mb3ItZGVtby1wdXJwb3Nlcy..." + // It's a long string that uniquely identifies this client + return token; + } else { + // No token available - usually means: + // - Notification permission not granted + // - Service worker not registered + // - Browser doesn't support push + console.log("No token available"); + return null; + } + } catch (error) { + console.log("Token retrieval failed:", error); + // Common errors: + // - messaging/permission-blocked: User denied notifications + // - messaging/unsupported-browser: Browser doesn't support push + // - Invalid VAPID key + return null; + } +} +``` + +### What This Code Does + +1. **Requests Token**: `getToken()` gets a unique identifier from Firebase +2. **Authenticates with VAPID**: The VAPID key proves your app's identity +3. **Returns Token**: This token is used to send notifications to this client + +### Finding Your VAPID Key + +1. Go to [Firebase Console](https://console.firebase.google.com) +2. Select your project +3. Navigate to **Project Settings → Cloud Messaging** +4. Scroll to **Web Push certificates** +5. Click **Generate key pair** if none exists +6. Copy the **Key pair** value + + +**Token Lifecycle**: FCM tokens can change when users clear browser data, update the browser, or when Firebase rotates tokens. Listen for token refresh events and update your server accordingly. + + +--- + +## Step 5: Register Token with CometChat + +After obtaining the FCM token, register it with CometChat so they know where to send push notifications for this user. + + + +```javascript +/** + * Complete push notification registration flow + * 1. Request permission + * 2. Get FCM token + * 3. Register with CometChat + * + * @returns {boolean} - true if registration successful + */ +async function registerPushNotifications() { + // ==================== STEP 1: Request Permission ==================== + const hasPermission = await requestNotificationPermission(); + if (!hasPermission) { + console.log("Cannot register: permission not granted"); + return false; + } + + // ==================== STEP 2: Get FCM Token ==================== + const fcmToken = await getFCMToken(); + if (!fcmToken) { + console.log("Cannot register: failed to get FCM token"); + return false; + } + + // ==================== STEP 3: Register with CometChat ==================== + try { + // registerTokenForPushNotification() tells CometChat: + // "Send push notifications for this user to this FCM token" + // + // CometChat will now send notifications when: + // - User receives a new message (and app is in background) + // - User receives an incoming call + // - Other configured notification events occur + await CometChat.registerTokenForPushNotification(fcmToken); + console.log("Push notifications registered"); + + // Store token for later unregistration (on logout) + // This ensures we can properly clean up + localStorage.setItem("fcmToken", fcmToken); + + return true; + } catch (error) { + console.log("Registration failed:", error); + // Common errors: + // - User not logged in to CometChat + // - Invalid FCM token + // - Push notifications not enabled in CometChat plan + return false; + } +} +``` + + +```typescript +/** + * Register for push notifications + * Handles the complete flow from permission to registration + */ +async function registerPushNotifications(): Promise { + // Step 1: Get permission + const hasPermission = await requestNotificationPermission(); + if (!hasPermission) return false; + + // Step 2: Get FCM token + const fcmToken = await getFCMToken(); + if (!fcmToken) return false; + + // Step 3: Register with CometChat + try { + await CometChat.registerTokenForPushNotification(fcmToken); + console.log("Push notifications registered"); + + // Store for cleanup on logout + localStorage.setItem("fcmToken", fcmToken); + return true; + } catch (error) { + console.log("Registration failed:", error); + return false; + } +} +``` + + + +### What This Code Does + +1. **Checks Permission**: Ensures user has granted notification permission +2. **Gets FCM Token**: Obtains the unique device/browser identifier +3. **Registers with CometChat**: Links the FCM token to the logged-in user +4. **Stores Token**: Saves token for cleanup during logout + +### Registration Flow + +``` +User clicks "Enable Notifications" + │ + ▼ + requestPermission() + │ + ├── denied → Show "enable in settings" message + │ + ▼ granted + getFCMToken() + │ + ├── failed → Show error message + │ + ▼ success + registerTokenForPushNotification() + │ + ▼ + ✅ Push notifications active +``` + + +**Login Required**: You must be logged in to CometChat before registering for push notifications. The token is associated with the logged-in user. + + +--- + +## Step 6: Handle Foreground Notifications + +When the app is in the foreground (user is actively using it), Firebase doesn't automatically show notifications. You need to handle them manually and decide how to display them. + +```javascript +import { onMessage } from "firebase/messaging"; + +// onMessage() listens for notifications when the app is in the foreground +// These won't show automatically - you decide how to handle them +onMessage(messaging, (payload) => { + console.log("Foreground message:", payload); + + // payload.data contains the notification data from CometChat + const { data } = payload; + + // ==================== CHECK NOTIFICATION TYPE ==================== + // CometChat sends different types of notifications + // Handle each type appropriately + + if (data.type === "chat") { + // ==================== CHAT NOTIFICATION ==================== + // New message received while app is open + // You might want to: + // - Show a toast/snackbar notification + // - Play a sound + // - Update unread count badge + // - Skip if user is viewing that conversation + handleChatNotification(data); + + } else if (data.type === "call") { + // ==================== CALL NOTIFICATION ==================== + // Incoming call while app is open + // You should show the incoming call UI immediately + // This is time-sensitive - user needs to answer quickly + handleCallNotification(data); + } +}); + +/** + * Handle a chat notification in the foreground + * Shows a browser notification or in-app toast + * + * @param {Object} data - Notification data from CometChat + */ +function handleChatNotification(data) { + // Option 1: Show browser notification + // Good for: Consistent experience, works even if tab is not focused + new Notification(data.title, { + body: data.body, + icon: data.senderAvatar || "/default-avatar.png", + tag: data.conversationId // Prevents duplicate notifications for same conversation + }); + + // Option 2: Show in-app notification (toast/snackbar) + // Good for: Custom styling, more control, less intrusive + showInAppNotification({ + title: data.title, + body: data.body, + onClick: () => openConversation(data.conversationId) + }); + + // Option 3: Just update UI (unread badge, etc.) + // Good for: Minimal interruption when user is actively chatting + updateUnreadBadge(data.conversationId); +} + +/** + * Handle a call notification in the foreground + * Shows the incoming call UI + * + * @param {Object} data - Notification data from CometChat + */ +function handleCallNotification(data) { + // Show incoming call UI immediately + // This should be prominent - calls are time-sensitive + showIncomingCallUI({ + callerName: data.senderName, + callerAvatar: data.senderAvatar, + callType: data.callType, // "audio" or "video" + sessionId: data.sessionId + }); + + // Optionally play a ringtone + playRingtone(); +} +``` + +### What This Code Does + +1. **Listens for Messages**: `onMessage()` receives notifications when app is in foreground +2. **Identifies Type**: Checks if it's a chat message or call notification +3. **Handles Appropriately**: Shows notification, updates UI, or triggers call screen + +### Foreground Notification Options + +| Option | Best For | Pros | Cons | +|--------|----------|------|------| +| **Browser Notification** | Consistent UX | Works when tab unfocused | Can be intrusive | +| **In-App Toast** | Custom styling | Full control | Only visible in app | +| **Silent Update** | Active users | Non-intrusive | Easy to miss | + + +**Smart Notifications**: Consider not showing notifications if the user is already viewing the conversation that the message is from. This prevents annoying duplicate alerts. + + +--- + +## Step 7: Handle Background Notifications + +When the app is in the background or closed, a service worker handles notifications. Create a service worker file to process and display these notifications. + +### 7a. Create Service Worker + +Create `firebase-messaging-sw.js` in your public folder (the root of your web server): + +```javascript +// firebase-messaging-sw.js +// This file runs in the background, separate from your main app +// It handles push notifications when the app is not in the foreground + +// Import Firebase libraries for service workers +// These are the "compat" versions designed for service worker environments +importScripts("https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js"); +importScripts("https://www.gstatic.com/firebasejs/9.0.0/firebase-messaging-compat.js"); + +// Initialize Firebase with the SAME config as your main app +// This connects the service worker to your Firebase project +firebase.initializeApp({ + apiKey: "YOUR_API_KEY", + authDomain: "YOUR_PROJECT.firebaseapp.com", + projectId: "YOUR_PROJECT_ID", + storageBucket: "YOUR_PROJECT.appspot.com", + messagingSenderId: "YOUR_SENDER_ID", + appId: "YOUR_APP_ID" +}); + +const messaging = firebase.messaging(); + +// ==================== HANDLE BACKGROUND MESSAGES ==================== +// This fires when a push notification arrives and the app is: +// - In the background (another tab is focused) +// - Minimized +// - Closed entirely +messaging.onBackgroundMessage((payload) => { + console.log("Background message:", payload); + + const { data } = payload; + + // Build the notification to display + // These options control how the notification appears + const notificationTitle = data.title || "New Message"; + const notificationOptions = { + body: data.body || "You have a new message", + icon: data.senderAvatar || "/default-avatar.png", // Small icon + badge: "/badge-icon.png", // Monochrome icon for status bar (mobile) + tag: data.conversationId, // Groups notifications - same tag = replace + data: data // Pass data for click handling + }; + + // Show the notification + // self.registration is the service worker's registration object + self.registration.showNotification(notificationTitle, notificationOptions); +}); + +// ==================== HANDLE NOTIFICATION CLICKS ==================== +// This fires when user clicks on a notification +// Use this to open the app and navigate to the relevant screen +self.addEventListener("notificationclick", (event) => { + // Close the notification + event.notification.close(); + + // Get the data we attached to the notification + const data = event.notification.data; + + // waitUntil() keeps the service worker alive until we're done + event.waitUntil( + // Find all open windows/tabs of our app + clients.matchAll({ type: "window" }).then((clientList) => { + // Check if app is already open + for (const client of clientList) { + if (client.url.includes(self.location.origin) && "focus" in client) { + // App is open - focus it and send a message + client.focus(); + + // Tell the app which notification was clicked + // The app can then navigate to the right screen + client.postMessage({ + type: "NOTIFICATION_CLICK", + data: data + }); + return; + } + } + + // App is not open - open a new window + if (clients.openWindow) { + // Build the URL based on notification type + const url = data.type === "call" + ? `/call/${data.sessionId}` // Open call screen + : `/chat/${data.conversationId}`; // Open conversation + return clients.openWindow(url); + } + }) + ); +}); +``` + +### What This Code Does + +1. **Initializes Firebase**: Connects service worker to your Firebase project +2. **Handles Background Messages**: `onBackgroundMessage` processes notifications when app is not active +3. **Shows Notifications**: `showNotification` displays the system notification +4. **Handles Clicks**: `notificationclick` event opens the app and navigates to the right screen + +### 7b. Register Service Worker + +Register the service worker in your main application code: + +```javascript +// In your main app (e.g., index.js or App.js) +// This tells the browser to use your service worker for push notifications + +if ("serviceWorker" in navigator) { + // Register the service worker + // The path is relative to your web root + navigator.serviceWorker.register("/firebase-messaging-sw.js") + .then((registration) => { + console.log("Service Worker registered:", registration); + // Service worker is now active and will handle background notifications + }) + .catch((error) => { + console.log("Service Worker registration failed:", error); + // Common errors: + // - File not found (wrong path) + // - HTTPS required (service workers only work on HTTPS or localhost) + // - Syntax error in service worker file + }); +} +``` + +### Service Worker Requirements + +| Requirement | Description | +|-------------|-------------| +| **HTTPS** | Service workers only work on HTTPS (or localhost for development) | +| **File Location** | Must be in your web root or a parent of the pages it controls | +| **Same Origin** | Must be served from the same origin as your app | + + +**Firebase Config Must Match**: The Firebase configuration in your service worker must exactly match the configuration in your main app. Mismatched configs will cause notifications to fail. + + +--- + +## Step 8: Handle Notification Clicks + +When a user clicks a notification (from the service worker), your app receives a message. Listen for these messages to navigate to the appropriate screen. + +```javascript +// Listen for messages from the service worker +// This fires when user clicks a notification and the app is already open +navigator.serviceWorker.addEventListener("message", (event) => { + // Check if this is a notification click event + if (event.data.type === "NOTIFICATION_CLICK") { + const data = event.data.data; + + console.log("Notification clicked:", data); + + // ==================== HANDLE BASED ON TYPE ==================== + // Navigate to the appropriate screen based on notification type + + if (data.type === "chat") { + // ==================== CHAT NOTIFICATION CLICKED ==================== + // User clicked a message notification + // Navigate to that conversation + navigateToConversation(data.conversationId); + + // Optionally mark messages as read + markConversationAsRead(data.conversationId); + + } else if (data.type === "call") { + // ==================== CALL NOTIFICATION CLICKED ==================== + // User clicked a call notification + // This might be a missed call or ongoing call + handleIncomingCall(data); + } + } +}); + +/** + * Navigate to a specific conversation + * Implementation depends on your routing library + * + * @param {string} conversationId - The conversation to open + */ +function navigateToConversation(conversationId) { + // React Router example: + // history.push(`/chat/${conversationId}`); + + // Next.js example: + // router.push(`/chat/${conversationId}`); + + // Vanilla JS example: + window.location.href = `/chat/${conversationId}`; +} + +/** + * Handle an incoming call from notification + * + * @param {Object} data - Call notification data + */ +function handleIncomingCall(data) { + // Check if call is still active + // Calls have a timeout, so the call might have ended + + // If using CometChat call listeners, the call state + // should already be tracked. Just show the call UI. + showIncomingCallUI({ + callerName: data.senderName, + callerAvatar: data.senderAvatar, + callType: data.callType, + sessionId: data.sessionId + }); +} +``` + +### What This Code Does + +1. **Listens for Service Worker Messages**: Receives notification click events +2. **Identifies Notification Type**: Checks if it's a chat or call notification +3. **Navigates Appropriately**: Opens the relevant screen in your app + +### Click Handling Flow + +``` +User clicks notification + │ + ▼ +Service Worker receives click + │ + ├── App is open → postMessage() to app + │ │ + │ ▼ + │ App receives message + │ │ + │ ▼ + │ Navigate to screen + │ + └── App is closed → openWindow() with URL + │ + ▼ + App opens at URL +``` + + +**Deep Linking**: The notification click handler essentially implements deep linking. Make sure your app can handle being opened directly to a conversation or call screen. + + +--- + +## Step 9: Unregister on Logout + +When the user logs out, unregister the push token to stop receiving notifications for that user. This is important for security and user experience. + +```javascript +/** + * Logout and clean up push notifications + * Unregisters the FCM token so the user stops receiving notifications + */ +async function logout() { + try { + // ==================== STEP 1: Get Stored FCM Token ==================== + // We stored this during registration + const fcmToken = localStorage.getItem("fcmToken"); + + if (fcmToken) { + // ==================== STEP 2: Unregister from CometChat ==================== + // This tells CometChat to stop sending notifications to this token + // Important: Do this BEFORE logging out, while still authenticated + await CometChat.unregisterTokenForPushNotification(fcmToken); + + // Clean up stored token + localStorage.removeItem("fcmToken"); + + console.log("Push notifications unregistered"); + } + + // ==================== STEP 3: Logout from CometChat ==================== + // This ends the user session + await CometChat.logout(); + + console.log("Logged out successfully"); + + // Navigate to login screen + // window.location.href = "/login"; + + } catch (error) { + console.log("Logout failed:", error); + // Even if unregister fails, still try to logout + try { + await CometChat.logout(); + } catch (e) { + // Logout also failed - force redirect anyway + } + } +} +``` + +### What This Code Does + +1. **Retrieves Stored Token**: Gets the FCM token we saved during registration +2. **Unregisters from CometChat**: Tells CometChat to stop sending notifications +3. **Cleans Up Storage**: Removes the stored token +4. **Logs Out**: Ends the CometChat session + +### Why Unregister? + +| Reason | Explanation | +|--------|-------------| +| **Security** | Prevents notifications going to wrong user if device is shared | +| **Privacy** | User shouldn't receive notifications after logging out | +| **Clean State** | Prepares for a different user to log in | +| **Resource Efficiency** | Stops unnecessary notification delivery attempts | + + +**Order Matters**: Unregister the token BEFORE calling `CometChat.logout()`. After logout, you won't be authenticated to make the unregister call. + + +--- + +## Complete Integration Example + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { initializeApp } from "firebase/app"; +import { getMessaging, getToken, onMessage } from "firebase/messaging"; + +class PushNotificationService { + constructor(firebaseConfig, vapidKey) { + this.firebaseConfig = firebaseConfig; + this.vapidKey = vapidKey; + this.messaging = null; + this.fcmToken = null; + } + + async initialize() { + // Initialize Firebase + const app = initializeApp(this.firebaseConfig); + this.messaging = getMessaging(app); + + // Register service worker + if ("serviceWorker" in navigator) { + await navigator.serviceWorker.register("/firebase-messaging-sw.js"); + } + + // Set up foreground message handler + this.setupForegroundHandler(); + + // Set up notification click handler + this.setupClickHandler(); + } + + async register() { + // Request permission + const permission = await Notification.requestPermission(); + if (permission !== "granted") { + console.log("Notification permission denied"); + return false; + } + + // Get FCM token + this.fcmToken = await getToken(this.messaging, { + vapidKey: this.vapidKey + }); + + if (!this.fcmToken) { + console.log("Failed to get FCM token"); + return false; + } + + // Register with CometChat + await CometChat.registerTokenForPushNotification(this.fcmToken); + localStorage.setItem("fcmToken", this.fcmToken); + + console.log("Push notifications registered"); + return true; + } + + async unregister() { + const token = this.fcmToken || localStorage.getItem("fcmToken"); + + if (token) { + await CometChat.unregisterTokenForPushNotification(token); + localStorage.removeItem("fcmToken"); + this.fcmToken = null; + } + } + + setupForegroundHandler() { + onMessage(this.messaging, (payload) => { + const { data } = payload; + + if (data.type === "chat") { + this.showChatNotification(data); + } else if (data.type === "call") { + this.onIncomingCall?.(data); + } + }); + } + + setupClickHandler() { + navigator.serviceWorker.addEventListener("message", (event) => { + if (event.data.type === "NOTIFICATION_CLICK") { + this.onNotificationClick?.(event.data.data); + } + }); + } + + showChatNotification(data) { + // Check if we should show notification + // (e.g., don't show if user is viewing that conversation) + if (this.shouldShowNotification?.(data) === false) { + return; + } + + new Notification(data.title, { + body: data.body, + icon: data.senderAvatar || "/default-avatar.png", + tag: data.conversationId + }); + } + + // Event handlers (set by consumer) + onIncomingCall = null; + onNotificationClick = null; + shouldShowNotification = null; +} + +// Usage +const pushService = new PushNotificationService( + { + apiKey: "...", + authDomain: "...", + projectId: "...", + messagingSenderId: "...", + appId: "..." + }, + "YOUR_VAPID_KEY" +); + +await pushService.initialize(); + +// After CometChat login +await pushService.register(); + +// Set up handlers +pushService.onIncomingCall = (data) => { + showIncomingCallUI(data); +}; + +pushService.onNotificationClick = (data) => { + if (data.type === "chat") { + navigateToConversation(data.conversationId); + } +}; + +pushService.shouldShowNotification = (data) => { + // Don't show if user is viewing this conversation + return currentConversationId !== data.conversationId; +}; + +// On logout +await pushService.unregister(); +await CometChat.logout(); +``` + +--- + +## Notification Payload Structure + +CometChat sends notifications with this data structure: + +### Chat Notification + +```json +{ + "type": "chat", + "title": "John Doe", + "body": "Hello! How are you?", + "senderUid": "user_123", + "senderName": "John Doe", + "senderAvatar": "https://...", + "receiverUid": "user_456", + "receiverType": "user", + "conversationId": "user_user_123_user_456", + "messageId": "12345", + "messageType": "text" +} +``` + +### Call Notification + +```json +{ + "type": "call", + "title": "Incoming Video Call", + "body": "John Doe is calling...", + "senderUid": "user_123", + "senderName": "John Doe", + "senderAvatar": "https://...", + "callType": "video", + "sessionId": "call_session_123" +} +``` + +--- + +## Troubleshooting + + + + 1. Check browser notification permissions + 2. Verify FCM token is registered with CometChat + 3. Check Firebase Console for delivery status + 4. Ensure service worker is registered + + + + 1. Verify CometChat user is logged in + 2. Check FCM token is valid + 3. Ensure push notifications are enabled in CometChat Dashboard + + + + 1. Verify service worker is registered + 2. Check service worker console for errors + 3. Ensure Firebase config in service worker matches app config + + + +--- + +## Next Steps + + + + Set up messaging first + + + Add voice and video calls + + + Server-side notifications + + + iOS and Android push setup + + diff --git a/sdk/javascript/guides.mdx b/sdk/javascript/guides.mdx new file mode 100644 index 00000000..3b9c2d4f --- /dev/null +++ b/sdk/javascript/guides.mdx @@ -0,0 +1,188 @@ +--- +title: "Integration Guides" +sidebarTitle: "Guides" +description: "Step-by-step guides for common CometChat integration scenarios" +--- + +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +Choose your integration path: +- **Chat Only** → [guide-chat-only](/sdk/javascript/guide-chat-only) - Text, media, groups +- **Calls Only** → [guide-calls-only](/sdk/javascript/guide-calls-only) - Standalone video/audio +- **Chat + Calls** → [guide-chat-calls](/sdk/javascript/guide-chat-calls) - Full communication suite +- **Moderation** → [guide-moderation](/sdk/javascript/guide-moderation) - Content filtering +- **Notifications** → [guide-notifications](/sdk/javascript/guide-notifications) - Push alerts + + +These guides provide complete, step-by-step instructions for integrating CometChat into your application. Each guide is designed to be followed from start to finish, with copy-paste ready code examples. + +--- + +## Choose Your Integration Path + + + + **Best for**: Messaging apps, customer support, social features + + Includes: + - Text and media messages + - Typing indicators + - Read receipts + - Group conversations + + + + **Best for**: Video conferencing, telehealth, virtual meetings + + Includes: + - Voice and video calls + - Screen sharing + - No Chat SDK required + - Standalone implementation + + + + **Best for**: Full communication apps, team collaboration + + Includes: + - All chat features + - Integrated calling + - Call signaling via chat + - Complete solution + + + + **Best for**: Community apps, marketplaces, social platforms + + Includes: + - AI content moderation + - User flagging + - Profanity filtering + - Image/video scanning + + + +--- + +## Add-On Features + + + + Alert users of messages and calls when app is in background + + + + Integrate AI-powered chatbots and assistants + + + +--- + +## Quick Decision Guide + +| I want to... | Use this guide | +|--------------|----------------| +| Add chat to my app | [Chat Only](/sdk/javascript/guide-chat-only) | +| Add video calls without chat | [Calls Only](/sdk/javascript/guide-calls-only) | +| Build a full communication app | [Chat + Calls](/sdk/javascript/guide-chat-calls) | +| Filter inappropriate content | [Moderation](/sdk/javascript/guide-moderation) | +| Send push notifications | [Notifications](/sdk/javascript/guide-notifications) | + +--- + +## Integration Checklist + +Use this checklist to track your integration progress: + +### Basic Setup +- [ ] Create CometChat account and app +- [ ] Get App ID, Region, and Auth Key +- [ ] Install SDK(s) +- [ ] Initialize CometChat +- [ ] Implement user login + +### Chat Features +- [ ] Send text messages +- [ ] Send media messages +- [ ] Receive messages (listeners) +- [ ] Fetch message history +- [ ] Typing indicators +- [ ] Read receipts +- [ ] Create/join groups + +### Calling Features +- [ ] Initialize Calls SDK +- [ ] Initiate calls +- [ ] Accept/reject calls +- [ ] Handle call events +- [ ] End calls properly + +### Production Readiness +- [ ] Switch to Auth Tokens (not Auth Key) +- [ ] Enable push notifications +- [ ] Configure moderation rules +- [ ] Handle errors gracefully +- [ ] Test on multiple devices + +--- + +## Common Integration Patterns + + + + ```javascript + // Initialize in useEffect or app startup + useEffect(() => { + const init = async () => { + await CometChat.init(APP_ID, appSettings); + // Check for existing session + const user = await CometChat.getLoggedinUser(); + if (user) setUser(user); + }; + init(); + }, []); + ``` + + + + ```javascript + // Initialize in main.js or plugin + export default { + async install(app) { + await CometChat.init(APP_ID, appSettings); + app.config.globalProperties.$cometchat = CometChat; + } + } + ``` + + + + ```typescript + // Initialize in app.module.ts or service + @Injectable({ providedIn: 'root' }) + export class CometChatService { + async initialize() { + await CometChat.init(APP_ID, appSettings); + } + } + ``` + + + +--- + +## Need Help? + + + + Complete SDK documentation + + + Working code examples + + + Get technical help + + diff --git a/sdk/javascript/interactive-messages.mdx b/sdk/javascript/interactive-messages.mdx index 2f083f73..fd068db8 100644 --- a/sdk/javascript/interactive-messages.mdx +++ b/sdk/javascript/interactive-messages.mdx @@ -1,203 +1,376 @@ --- title: "Interactive Messages" +sidebarTitle: "Interactive Messages" +description: "Send messages with embedded forms, buttons, and interactive elements" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Send interactive message (form, card, buttons) +const interactiveData = { + title: "Quick Survey", + formFields: [ + { elementType: "textInput", elementId: "name", label: "Your Name" }, + { elementType: "dropdown", elementId: "rating", label: "Rating", + options: [{ label: "Good", value: "4" }, { label: "Great", value: "5" }] } + ], + submitElement: { elementType: "button", elementId: "submit", buttonText: "Submit" } +}; -An InteractiveMessage is a specialised object that encapsulates an interactive unit within a chat message, such as an embedded form that users can fill out directly within the chat interface. This enhances user engagement by making the chat experience more interactive and responsive to user input. - -## InteractiveMessage - -`InteractiveMessage` is a chat message with embedded interactive content. It can contain various properties: - -| Parameter | Description | Required | -| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | -| receiverId | The UID or GUID of the recipient | Yes | -| receiverType | The type of the receiver to whom the message is to be sent i.e CometChatConstants.RECEIVER\_TYPE\_USER (user) or CometChatConstants.RECEIVER\_TYPE\_GROUP (group) | Yes | -| messageType | The type of the message that needs to be sent | Yes | -| interactiveData | A JSONObject holding structured data for the interactive element. | Yes | -| allowSenderInteraction | A boolean determining whether the message sender can interact with the message by default it is set to false. | Optional (Default: false) | -| interactionGoal | An InteractionGoal object encapsulating the intended outcome of interacting with the InteractiveMessage by default it is set to none | Optional (Default: none) | - -## Interaction - -An `Interaction` represents a user action involved with an `InteractiveMessage`. It includes: +const message = new CometChat.InteractiveMessage( + receiverID, + CometChat.RECEIVER_TYPE.GROUP, + "form", // type: form, card, etc. + interactiveData +); +await CometChat.sendInteractiveMessage(message); -* `elementId`: An identifier for a specific interactive element. -* `interactedAt`: A timestamp indicating when the interaction occurred. +// Listen for interactive messages +CometChat.addMessageListener("LISTENER", new CometChat.MessageListener({ + onInteractiveMessageReceived: (msg) => { + const data = msg.getInteractiveData(); + } +})); -## Goal Completion +// Set interaction goal +message.setInteractionGoal(new CometChat.InteractionGoal( + ["submitBtn"], CometChat.INTERACTION_TYPE.ANY_OF +)); +``` + -A key feature of `InteractiveMessage` is checking whether a user's interactions with the message meet the defined `InteractionGoal` +Interactive messages contain embedded interactive elements like forms, buttons, and inputs that users can interact with directly in the chat interface. -You would be tracking every interaction users perform on an `InteractiveMessage` (captured as `Interaction` objects) and comparing those with the defined `InteractionGoal`. The completion of a goal can vary depending on the goal type: + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + -| Goals | Description | Keys | -| -------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------- | -| **Any Interaction** | The goal is considered completed if there is at least one interaction. | CometChatConstants.INTERACTION\_TYPE\_ANY | -| **Any of Specific Interactions** | The goal is achieved if any of the specified interactions occurred. | CometChatConstants.INTERACTION\_TYPE\_ANY\_OF | -| **All of Specific Interactions** | The goal is completed when all specified interactions occur. | CometChatConstants.INTERACTION\_TYPE\_ALL\_OF | -| **None** | The goal is never completed. | CometChatConstants.INTERACTION\_TYPE\_NONE | +--- -This user interaction tracking mechanism provides a flexible and efficient way to monitor user engagement within an interactive chat session. By defining clear interaction goals and checking user interactions against these goals, you can manage user engagement and improve the overall chat experience in your CometChat-enabled application. +## Use Cases -## InteractionGoal +| Type | Description | +|------|-------------| +| Forms | Surveys, feedback forms, data collection | +| Buttons | Quick actions, confirmations, navigation | +| Cards | Product cards, booking confirmations | +| Polls | Voting, decision making | -The `InteractionGoal` represents the desired outcome of an interaction with an `InteractiveMessage`. It includes: +--- -* `elementIds`: A list of identifiers for the interactive elements. -* `type`: The type of interaction goal from the `CometChatConstants`. +## InteractiveMessage Properties -## Sending InteractiveMessages +| Property | Description | Required | +|----------|-------------|----------| +| `receiverId` | UID or GUID of recipient | Yes | +| `receiverType` | USER or GROUP | Yes | +| `messageType` | Type of interactive message (e.g., "form") | Yes | +| `interactiveData` | JSON object with interactive content | Yes | +| `allowSenderInteraction` | Can sender interact (default: false) | No | +| `interactionGoal` | Defines completion criteria | No | -The `InteractiveMessage` can be sent using the `sendInteractiveMessage` method of the `CometChat` class. The method requires an `InteractiveMessage` object and a `CallbackListener` for handling the response. +--- -Here is an example of how to use it: +## Send an Interactive Message - -```js + +```javascript const interactiveData = { -title: "Survey", -formFields: [ - { - elementType: "textInput", - elementId: "name", - optional: false, - label: "Name", - placeholder: { - text: "Enter text here" + title: "Quick Survey", + formFields: [ + { + elementType: "textInput", + elementId: "name", + label: "Your Name", + placeholder: { text: "Enter your name" } + }, + { + elementType: "dropdown", + elementId: "rating", + label: "How would you rate us?", + options: [ + { label: "Excellent", value: "5" }, + { label: "Good", value: "4" }, + { label: "Average", value: "3" } + ] } - }, - { - elementType: "textInput", - elementId: "age", - optional: true, - label: "Age", - maxLines: 1, - placeholder: { - text: "Enter text here" + ], + submitElement: { + elementType: "button", + elementId: "submitBtn", + buttonText: "Submit", + action: { + actionType: "urlNavigation", + url: "https://example.com/thanks" } - }, - { - elementType: "Select", - elementId: "checkBox1", - optional: true, - label: "Check box element", - defaultValue: ["chk_option_2"], - options: [ - { - label: "Option 1", - value: "chk_option_1" - }, - { - label: "Option 2", - value: "chk_option_2" - } - ] - }, - { - elementType: "dropdown", - elementId: "gender", - optional: false, - label: "Gender", - defaultValue: "male", - options: [ - { - label: "Male", - value: "male" - }, - { - label: "Female", - value: "female" - } - ] } -], -submitElement: { - elementType: "button", - elementId: "submitButton", - buttonText: "Submit", - disableAfterInteracted: false, - action: { - actionType: "urlNavigation", - url: "https://www.cometchat.com/" - } -} }; +const message = new CometChat.InteractiveMessage( + "group-123", + CometChat.RECEIVER_TYPE.GROUP, + "form", + interactiveData +); +CometChat.sendInteractiveMessage(message).then( + (msg) => console.log("Interactive message sent:", msg), + (error) => console.log("Failed:", error) +); +``` + + +```javascript +const interactiveData = { + title: "Order Confirmation", + text: "Your order #12345 has been placed!", + buttons: [ + { + elementType: "button", + elementId: "trackBtn", + buttonText: "Track Order", + action: { + actionType: "urlNavigation", + url: "https://example.com/track/12345" + } + }, + { + elementType: "button", + elementId: "supportBtn", + buttonText: "Contact Support", + action: { + actionType: "urlNavigation", + url: "https://example.com/support" + } + } + ] +}; -const interactiveMessage = new CometChat.InteractiveMessage(receiverId,receiverType,"form", interactiveData); - +const message = new CometChat.InteractiveMessage( + "user1", + CometChat.RECEIVER_TYPE.USER, + "card", + interactiveData +); -CometChat.sendInteractiveMessage(interactiveMessage) - .then((message: CometChat.InteractiveMessage) => { - // This block is executed when the InteractiveMessage is sent successfully. - }) - .catch((error: CometChat.CometChatException) => { - // This block is executed if an error occurs while sending the InteractiveMessage. - }); +CometChat.sendInteractiveMessage(message); +``` + + +```javascript +const sendInteractiveMessage = async () => { + try { + const interactiveData = { + title: "Quick Survey", + formFields: [ + { + elementType: "textInput", + elementId: "name", + label: "Your Name", + placeholder: { text: "Enter your name" } + }, + { + elementType: "dropdown", + elementId: "rating", + label: "How would you rate us?", + options: [ + { label: "Excellent", value: "5" }, + { label: "Good", value: "4" }, + { label: "Average", value: "3" } + ] + } + ], + submitElement: { + elementType: "button", + elementId: "submitBtn", + buttonText: "Submit" + } + }; + + const message = new CometChat.InteractiveMessage( + "group-123", + CometChat.RECEIVER_TYPE.GROUP, + "form", + interactiveData + ); + + const sentMessage = await CometChat.sendInteractiveMessage(message); + console.log("Interactive message sent:", sentMessage); + } catch (error) { + console.log("Failed:", error); + } +}; ``` - - -## Event Listeners -CometChat SDK provides event listeners to handle real-time events related to `InteractiveMessage`. +--- -## On InteractiveMessage Received +## Receive Interactive Messages -The `onInteractiveMessageReceived` event listener is triggered when an `InteractiveMessage` is received. +Listen for incoming interactive messages: -Here is an example: +```javascript +const listenerID = "INTERACTIVE_LISTENER"; - - -```js CometChat.addMessageListener( - "UNIQUE_ID", + listenerID, new CometChat.MessageListener({ - onInteractiveMessageReceived: (message: CometChat.InteractiveMessage) => { - // This block is executed when an InteractiveMessage is received. - // Here you can define logic to handle the received InteractiveMessage and display it in your chat interface. - }, + onInteractiveMessageReceived: (message) => { + console.log("Interactive message received:", message); + + const data = message.getInteractiveData(); + const type = message.getType(); + + // Render based on type + renderInteractiveMessage(type, data); + } }) ); + +// Remove listener when done +CometChat.removeMessageListener(listenerID); ``` - +--- - +## Interaction Goals -On Interaction Goal Completed +Track when users complete interactions with your message. -The `onInteractionGoalCompleted` event listener is invoked when an interaction goal is achieved. +### Goal Types -Here is an example: +| Goal | Description | +|------|-------------| +| `ANY` | Completed with any interaction | +| `ANY_OF` | Completed when any specified element is interacted with | +| `ALL_OF` | Completed when all specified elements are interacted with | +| `NONE` | Never marked as completed | - - -```js +### Set an Interaction Goal + +```javascript +const interactionGoal = new CometChat.InteractionGoal( + ["submitBtn", "ratingInput"], // Element IDs + CometChat.INTERACTION_TYPE.ALL_OF // All must be interacted with +); + +const message = new CometChat.InteractiveMessage( + "group-123", + CometChat.RECEIVER_TYPE.GROUP, + "form", + interactiveData +); + +message.setInteractionGoal(interactionGoal); + +CometChat.sendInteractiveMessage(message); +``` + +### Listen for Goal Completion + +```javascript CometChat.addMessageListener( - "UNIQUE_ID", + "GOAL_LISTENER", new CometChat.MessageListener({ - onInteractionGoalCompleted: (receipt: CometChat.InteractionReceipt) => { - // This block is executed when an interaction goal is completed. - // Here you can specify the actions your application should take once an interaction goal is achieved, such as updating the UI or notifying the user. - }, + onInteractionGoalCompleted: (receipt) => { + console.log("Interaction goal completed:", receipt); + // User has completed the required interactions + } }) ); ``` - +--- - +## Form Field Types + +| Type | Description | +|------|-------------| +| `textInput` | Single or multi-line text input | +| `dropdown` | Select from options | +| `checkbox` | Multiple selection | +| `radio` | Single selection | +| `button` | Action button | + +### Text Input + +```javascript +{ + elementType: "textInput", + elementId: "feedback", + label: "Your Feedback", + optional: false, + maxLines: 3, + placeholder: { text: "Enter your feedback" } +} +``` + +### Dropdown + +```javascript +{ + elementType: "dropdown", + elementId: "department", + label: "Select Department", + defaultValue: "sales", + options: [ + { label: "Sales", value: "sales" }, + { label: "Support", value: "support" }, + { label: "Billing", value: "billing" } + ] +} +``` + +### Checkbox + +```javascript +{ + elementType: "checkbox", + elementId: "interests", + label: "Select Interests", + defaultValue: ["tech"], + options: [ + { label: "Technology", value: "tech" }, + { label: "Sports", value: "sports" }, + { label: "Music", value: "music" } + ] +} +``` + +--- + +## Allow Sender Interaction + +By default, the sender cannot interact with their own interactive message. Enable it if needed: + +```javascript +const message = new CometChat.InteractiveMessage( + "group-123", + CometChat.RECEIVER_TYPE.GROUP, + "form", + interactiveData +); -These event listeners offer your application a way to provide real-time updates in response to incoming interactive messages and goal completions, contributing to a more dynamic and responsive user chat experience. +message.setAllowSenderInteraction(true); + +CometChat.sendInteractiveMessage(message); +``` + +--- -## Usage +## Next Steps -An InteractiveMessage is constructed with the receiver's UID, the receiver type, the interactive type, and interactive data as a JSONObject. Once created, the InteractiveMessage can be sent using CometChat's sendInteractiveMessage() method. Incoming InteractiveMessages can be received and processed via CometChat's message listener framework. + + + Send ephemeral real-time messages + + + Send custom message types + + diff --git a/sdk/javascript/join-group.mdx b/sdk/javascript/join-group.mdx index 744f9e72..10df5511 100644 --- a/sdk/javascript/join-group.mdx +++ b/sdk/javascript/join-group.mdx @@ -1,107 +1,180 @@ --- -title: "Join A Group" +title: "Join a Group" +sidebarTitle: "Join Group" +description: "Join public, password-protected, or private groups" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Join a public group +await CometChat.joinGroup("group_guid", CometChat.GROUP_TYPE.PUBLIC, ""); -## Join a Group +// Join a password-protected group +await CometChat.joinGroup("group_guid", CometChat.GROUP_TYPE.PASSWORD, "password"); + +// Check if already a member +const group = await CometChat.getGroup("group_guid"); +if (group.getHasJoined()) { + console.log("Already a member"); +} + +// Listen for join events +CometChat.addGroupListener("GROUP_LISTENER", new CometChat.GroupListener({ + onGroupMemberJoined: (message, joinedUser, joinedGroup) => { + console.log(joinedUser.getName(), "joined", joinedGroup.getName()); + } +})); + +// Note: Private groups require admin to add members (can't join directly) +``` + + +Join a group to start participating in group conversations. The join process varies based on the group type. + + +**Availability**: SDK, API, UI Kits + +Once joined, CometChat tracks membership - you don't need to rejoin each session. + -In order to start participating in group conversations, you will have to join a group. You can do so using the `joinGroup()` method. +--- + +## Join a Group - + ```javascript -var GUID = "GUID"; -var password = ""; -var groupType = CometChat.GROUP_TYPE.PUBLIC; +const GUID = "group-123"; +const groupType = CometChat.GROUP_TYPE.PUBLIC; +const password = ""; CometChat.joinGroup(GUID, groupType, password).then( -group => { - console.log("Group joined successfully:", group); -}, error => { - console.log("Group joining failed with exception:", error); -} + (group) => console.log("Joined group:", group.getName()), + (error) => console.log("Failed to join:", error) ); ``` - + +```javascript +const GUID = "group-123"; +const groupType = CometChat.GROUP_TYPE.PASSWORD; +const password = "secret123"; +CometChat.joinGroup(GUID, groupType, password).then( + (group) => console.log("Joined group:", group.getName()), + (error) => console.log("Failed to join:", error) +); +``` + ```typescript -var GUID: string = "GUID"; +const GUID: string = "group-123"; +const groupType: string = CometChat.GROUP_TYPE.PUBLIC; +const password: string = ""; -CometChat.joinGroup(GUID, CometChat.GroupType.Public).then( - (group: CometChat.Group) => { - console.log("Group joined successfully:", group); - }, (error: CometChat.CometChatException) => { - console.log("Group joining failed with exception:", error); +CometChat.joinGroup(GUID, groupType, password).then( + (group: CometChat.Group) => console.log("Joined group:", group.getName()), + (error: CometChat.CometChatException) => console.log("Failed:", error) +); +``` + + +```javascript +const joinGroup = async () => { + try { + const GUID = "group-123"; + const groupType = CometChat.GROUP_TYPE.PUBLIC; + const password = ""; // Use password for PASSWORD type groups + + const group = await CometChat.joinGroup(GUID, groupType, password); + console.log("Joined group:", group.getName()); + } catch (error) { + console.log("Failed to join:", error); } -); +}; ``` - - -The `joinGroup()` method takes the below parameters +| Parameter | Description | +|-----------|-------------| +| `GUID` | Group identifier | +| `groupType` | PUBLIC, PASSWORD, or PRIVATE | +| `password` | Required for PASSWORD groups | -| Parameter | Description | -| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `GUID` | The GUID of the group you would like to join. | -| `groupType` | Type of the group. CometChat provides 3 types of groups viz. 1. CometChat.GROUP\_TYPE.PUBLIC 2. CometChat.GROUP\_TYPE.PASSWORD 3. CometChats.GROUP\_TYPE.PRIVATE | -| `password` | Password is mandatory in case of a password protected group. | + +Private groups cannot be joined directly - users must be added by an admin. + -Once you have joined a group successfully, you can send and receive messages in that group. +--- -CometChat keeps a track of the groups joined and you do not need to join the group every time you want to communicate in the group. +## Check Membership -You can identify if a group is joined using the `hasJoined` parameter in the `Group` object. +Use `hasJoined` to check if the user is already a member: -## Real-time Group Member Joined Events +```javascript +const group = await CometChat.getGroup("group-123"); -*In other words, as a member of a group, how do I know if someone joins the group when my app is running?* +if (group.getHasJoined()) { + console.log("Already a member"); +} else { + // Show join button +} +``` -If a user joins any group, the members of the group receive a real-time event in the `onGroupMemberJoined()` method of the `GroupListener` class. +--- - - -```javascript -CometChat.addGroupListener( - "UNIQUE_LISTNER_ID", - new CometChat.GroupListener({ - onGroupMemberJoined: (message, joinedUser, joinedGroup) => { - console.log("User joined", { message, joinedUser, joinedGroup }); - } - }) -); -``` +## Real-Time Join Events - +Listen for when users join groups you're a member of: + +```javascript +const listenerID = "GROUP_LISTENER"; - -```typescript CometChat.addGroupListener( - "UNIQUE_LISTNER_ID", + listenerID, new CometChat.GroupListener({ - onGroupMemberJoined: (message: CometChat.Action, joinedUser: CometChat.User, joinedGroup: CometChat.Group) => { - console.log("User joined", { message, joinedUser, joinedGroup }); - } + onGroupMemberJoined: (message, joinedUser, joinedGroup) => { + console.log(`${joinedUser.getName()} joined ${joinedGroup.getName()}`); + } }) ); + +// Remove listener when done +CometChat.removeGroupListener(listenerID); ``` - +--- - +## Missed Join Events -## Missed Group Member Joined Events +When fetching message history, join events appear as `Action` messages: -*In other words, as a member of a group, how do I know if someone joins the group when my app is not running?* +```javascript +// In your message list +messages.forEach((message) => { + if (message.getCategory() === "action") { + const action = message.getAction(); + if (action === "joined") { + const user = message.getActionBy(); + console.log(`${user.getName()} joined the group`); + } + } +}); +``` -When you retrieve the list of previous messages if a member has joined any group that the logged-in user is a member of, the list of messages will contain an `Action` message. An `Action` message is a sub-class of `BaseMessage` class. +--- -For the group member joined event, in the `Action` object received, the following fields can help you get the relevant information- +## Next Steps -1. `action` - `joined` -2. `actionBy` - User object containing the details of the user who joined the group -3. `actionFor`- Group object containing the details of the group the user has joined + + + Leave a group + + + View group members + + diff --git a/sdk/javascript/key-concepts.mdx b/sdk/javascript/key-concepts.mdx index 37e5885f..b69b47eb 100644 --- a/sdk/javascript/key-concepts.mdx +++ b/sdk/javascript/key-concepts.mdx @@ -1,127 +1,1158 @@ --- title: "Key Concepts" +description: "Understand the core concepts of CometChat: users, groups, messages, conversations, and real-time events" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Core Entities +User → uid, name, avatar, status, metadata +Group → guid, name, type (public/password/private), membersCount +Message → id, sender, receiver, type (text/media/custom), category +Conversation → conversationId, type (user/group), lastMessage, unreadCount -### CometChat Dashboard +// Key Constants +CometChat.RECEIVER_TYPE.USER | GROUP +CometChat.MESSAGE_TYPE.TEXT | IMAGE | VIDEO | AUDIO | FILE +CometChat.GROUP_TYPE.PUBLIC | PASSWORD | PRIVATE +CometChat.GROUP_MEMBER_SCOPE.ADMIN | MODERATOR | PARTICIPANT -The CometChat Dashboard enables you to create new apps (projects) and manage your existing apps. +// Essential Listeners +MessageListener → onTextMessageReceived, onMediaMessageReceived, onTypingStarted +UserListener → onUserOnline, onUserOffline +GroupListener → onGroupMemberJoined, onGroupMemberLeft, onGroupMemberKicked +CallListener → onIncomingCallReceived, onOutgoingCallAccepted +ConnectionListener → onConnected, onDisconnected - -How many apps to create? +// Security: Auth Key (dev only) vs Auth Token (production) +// Use REST API Key server-side only, never expose in client +``` + + +Before diving into implementation, understanding these core concepts will help you build better chat experiences. This guide covers everything you need to know about how CometChat works. -Ideally, you should create two apps- one for development and one for production. And you should use a single app irrespective of the number of platforms. +--- -Do not create separate apps for every platform; if you do, your users on different platforms will not be able to communicate with each other! +## How CometChat Works - +CometChat provides the messaging infrastructure so you can focus on your app's unique features. -* For every app, a unique App ID is generated. This App ID will be required when integrating CometChat within your app. -* Along with the App ID, you will need to create an Auth Key (from the Dashboard) which can be used for user authentication. +```mermaid +graph LR + subgraph "Your App" + A[Frontend] + B[Backend] + end + + subgraph "CometChat" + C[SDK] + D[WebSocket] + E[REST API] + F[Dashboard] + end + + A -->|Real-time| C + C -->|Messages & Events| D + B -->|User Management| E + F -->|Configuration| E +``` -### Auth & Rest API Keys +| Component | What It Does | When to Use | +|-----------|--------------|-------------| +| **SDK** | Real-time messaging from client | Sending/receiving messages, presence, typing | +| **REST API** | Server-side operations | Creating users, generating auth tokens | +| **Dashboard** | Configuration & monitoring | Setup, analytics, testing | +| **WebSocket** | Real-time event delivery | Automatic (SDK manages this) | -You can generate two types of keys from the dashboard. + +**Key Principle:** CometChat handles messaging infrastructure. You handle user management and business logic in your app. + -| Type | Privileges | Recommended Use | -| ------------ | ---------------------------------------------------------------- | --------------------------------------------- | -| Auth Key | The Auth Key can be used to create & login users. | In your client side code (during development) | -| Rest API Key | The Rest API Key can be used to perform any CometChat operation. | In your server side code | +--- -### Users +## CometChat Dashboard -A user is anyone who uses CometChat. +The [CometChat Dashboard](https://app.cometchat.com) is your control center: -### UID + + + Sign up and create a new app. Choose a region closest to your users. + + + Navigate to **API & Auth Keys** to find your App ID, Region, and Auth Key. + + + Enable extensions, set up webhooks, and configure settings. + + + Use the pre-created test users (`cometchat-uid-1` to `cometchat-uid-5`) for development. + + + Track messages, users, and API calls in the Analytics section. + + -* Each user is uniquely identified using UID. -* The UID is typically the primary ID of the user from your database. + +**How many apps should I create?** - +Create **two apps**: one for development and one for production. Use a single app across all platforms (web, iOS, Android) so users can communicate regardless of their device. + -UID can be alphanumeric with underscore and hyphen. Spaces, punctuation and other special characters are not allowed. +--- + +## API Keys & Security + +CometChat provides different keys for different purposes: + +| Key | Access Level | Where to Use | Security | +|-----|--------------|--------------|----------| +| **App ID** | Identifies your app | Client & Server | Public (safe to expose) | +| **Auth Key** | Create/login users | Client (dev only) | ⚠️ Development only | +| **REST API Key** | Full admin access | Server only | 🔒 Never expose | +| **Auth Token** | Single user session | Client | ✅ Production recommended | +```mermaid +flowchart TD + A[Development] -->|Auth Key| B[Quick Testing] + C[Production] -->|Auth Token| D[Secure Login] + + E[Your Server] -->|REST API Key| F[Create Users] + E -->|REST API Key| G[Generate Auth Tokens] + + style A fill:#fff3cd + style C fill:#d4edda + style E fill:#cce5ff +``` + + +**Security Rules:** +1. Never expose REST API Key in client code +2. Use Auth Key only during development +3. In production, generate Auth Tokens server-side -### Auth Token +--- + +## Users -* A single user can have multiple auth tokens. The auth tokens should be per user per device. -* It should be generated by API call ideally, via server to server call. The auth token should then be given to CometChat for login. -* An Auth Token can only be deleted via dashboard or using REST API. +A **User** represents anyone who can send or receive messages in your app. -### Authentication +### User Lifecycle -To allow a user to use CometChat, the user must log in to CometChat. +```mermaid +sequenceDiagram + participant App as Your App + participant Server as Your Server + participant CC as CometChat + + App->>Server: User signs up + Server->>Server: Save to your database + Server->>CC: Create CometChat user (REST API) + CC->>Server: User created + Server->>App: Registration complete + + App->>Server: User logs in + Server->>Server: Verify credentials + Server->>CC: Generate Auth Token + CC->>Server: Return token + Server->>App: Send token + App->>CC: CometChat.login(token) + CC->>App: Session established +``` -**CometChat does not handle user management.** You must handle user registration and login at your end. Once the user is logged into your app/site, you can log in the user to CometChat **programmatically**. So the user does not ever directly login to CometChat. +### User Identifier (UID) -**CometChat does not handle friends management.** If you want to associate friends with your users, you must handle friends management in your app. Once two users are friends (i.e. they have accepted each other as friends), then you can associate them as friends in CometChat. +Each user needs a unique identifier: -### Typical Workflow +| Rule | Valid | Invalid | +|------|-------|---------| +| Alphanumeric | `user123`, `john_doe` | - | +| Underscores | `user_name` | - | +| Hyphens | `user-456` | - | +| No spaces | - | `user 123` | +| No special chars | - | `john@doe`, `user.name` | +| Case-sensitive | `User1` ≠ `user1` | - | -| Your App | Your Server | CometChat | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | -| User registers in your app | You store the user information in your database (e.g. ID, name, email, phone, location etc. in `users` table) | You add the user to CometChat (only ID & name) using the Rest API | -| User logs in to your app | You verify the credentials, login the user and retrieve the user ID | You log in the user to CometChat using the same user ID programmatically | -| User sends a friend request | You display the request to the potential friend | No action required | -| User accepts a friend request | You display the users as friends | You add both the users as friends using the Rest API | + +**Best Practice:** Use the same user ID from your database as the CometChat UID for easy mapping. + + +### User Properties + +```javascript +// Creating a user with all properties +const user = new CometChat.User("user123"); +user.setName("John Doe"); +user.setAvatar("https://example.com/avatar.png"); +user.setRole("premium"); +user.setMetadata({ + department: "Engineering", + location: "New York" +}); +user.setTags(["developer", "team-alpha"]); +user.setStatusMessage("Available for chat"); + +// Create the user (requires Auth Key) +CometChat.createUser(user, authKey); +``` + +| Property | Type | Description | Editable | +|----------|------|-------------|----------| +| `uid` | string | Unique identifier | Create only | +| `name` | string | Display name | ✅ | +| `avatar` | string | Profile picture URL | ✅ | +| `role` | string | Role for filtering/permissions | ✅ | +| `metadata` | object | Custom JSON data | ✅ | +| `tags` | array | Tags for categorization | ✅ | +| `statusMessage` | string | Custom status text | ✅ | +| `status` | string | `online` / `offline` | ❌ (system) | +| `lastActiveAt` | number | Last activity timestamp | ❌ (system) | ### User Roles -A role is a category for a group of similar users. For example, you may want to group your premium users using the role "Premium". You then use this to filter users or enable/disable features by writing conditional code. +Roles help you segment users and control features: -### User List +```javascript +// Filter users by role +const usersRequest = new CometChat.UsersRequestBuilder() + .setRoles(["premium", "moderator"]) + .build(); -* The User List can be used to build the **Contacts** or **Who's Online** view in your app. -* The list of users can be different based on the logged-in user. +// Subscribe to presence for specific roles only +const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForRoles(["premium", "vip"]) + .setRegion(region) + .build(); +``` -### Groups +| Example Role | Use Case | +|--------------|----------| +| `default` | Regular users | +| `premium` | Paid subscribers | +| `moderator` | Content moderators | +| `admin` | App administrators | +| `support` | Customer support agents | -A group can be used for multiple users to communicate with each other on a particular topic/interest. +--- -### GUID +## Groups -* Each group is uniquely identified using GUID. -* The GUID is typically the primary ID of the group from your database. If you do not store group information in your database, you can generate a random string for use as GUID. +A **Group** enables multiple users to communicate together. - +### Group Types + +```mermaid +graph TD + subgraph Public + A[Anyone can see] --> B[Anyone can join] + end + + subgraph Password + C[Anyone can see] --> D[Password required] + end + + subgraph Private + E[Members only see] --> F[Invite only] + end +``` + +| Type | Visibility | Join Method | Use Case | +|------|------------|-------------|----------| +| **Public** | Everyone | Open join | Community channels, public forums | +| **Password** | Everyone | Password required | Semi-private rooms, events | +| **Private** | Members only | Invitation (auto-join) | Team chats, support tickets | + +```javascript +// Create different group types +const publicGroup = new CometChat.Group( + "community", + "Community Chat", + CometChat.GROUP_TYPE.PUBLIC +); + +const passwordGroup = new CometChat.Group( + "event-123", + "VIP Event", + CometChat.GROUP_TYPE.PASSWORD, + "secretPassword" +); + +const privateGroup = new CometChat.Group( + "team-alpha", + "Team Alpha", + CometChat.GROUP_TYPE.PRIVATE +); +``` + +### Member Scopes (Permissions) + +```mermaid +graph TD + Admin[Admin] -->|can manage| Moderator[Moderator] + Admin -->|can manage| Participant[Participant] + Moderator -->|can manage| Participant + + Admin -->|can| A1[Delete group] + Admin -->|can| A2[Change any scope] + Admin -->|can| A3[Update group settings] + + Moderator -->|can| M1[Kick members] + Moderator -->|can| M2[Ban members] + Moderator -->|can| M3[Update group info] + + Participant -->|can| P1[Send messages] + Participant -->|can| P2[Receive messages] + Participant -->|can| P3[Make calls] +``` + +| Scope | Assigned To | Capabilities | +|-------|-------------|--------------| +| **Admin** | Group creator (default) | Full control: delete group, manage all members, change settings | +| **Moderator** | Promoted by admin | Moderate: kick/ban participants, update group info | +| **Participant** | All other members | Basic: send/receive messages, join calls | + +```javascript +// Add member with specific scope +const member = new CometChat.GroupMember( + "user123", + CometChat.GROUP_MEMBER_SCOPE.MODERATOR +); + +// Change member scope +CometChat.updateGroupMemberScope( + "group-guid", + "user123", + CometChat.GROUP_MEMBER_SCOPE.ADMIN +); +``` + +### Group Properties + +```javascript +// Create group with all properties +const group = new CometChat.Group( + "team-123", // GUID + "Engineering Team", // Name + CometChat.GROUP_TYPE.PRIVATE +); + +group.setIcon("https://example.com/group-icon.png"); +group.setDescription("Engineering team discussions"); +group.setMetadata({ department: "Engineering", project: "Alpha" }); +group.setTags(["engineering", "internal"]); + +CometChat.createGroup(group); +``` + +--- + +## Messages + +Messages are the core of chat functionality. CometChat supports multiple message types and categories. + +### Message Categories & Types + +```mermaid +graph TD + Message[Message] --> Category[Category] + Category --> MC[message] + Category --> Custom[custom] + Category --> Action[action] + Category --> Call[call] + + MC --> Text[text] + MC --> Image[image] + MC --> Video[video] + MC --> Audio[audio] + MC --> File[file] + + Custom --> Location[location] + Custom --> Poll[poll] + Custom --> YourType[your-custom-type] + + Action --> GroupMember[groupMember] + Action --> MessageAction[message] + + Call --> AudioCall[audio] + Call --> VideoCall[video] +``` + +| Category | Description | Examples | +|----------|-------------|----------| +| `message` | Standard messages | Text, images, videos, files | +| `custom` | Your custom types | Location, polls, payments | +| `action` | System events | Member joined, message deleted | +| `call` | Call events | Call initiated, ended | + +### Sending Different Message Types + + + + ```javascript + const textMessage = new CometChat.TextMessage( + "receiver-uid", // Receiver UID or GUID + "Hello, how are you?", // Message text + CometChat.RECEIVER_TYPE.USER // USER or GROUP + ); + + // Optional: Add metadata + textMessage.setMetadata({ priority: "high" }); + + // Optional: Add tags + textMessage.setTags(["important"]); + + CometChat.sendMessage(textMessage).then( + (message) => console.log("Sent:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```javascript + // From file input + const file = document.getElementById("fileInput").files[0]; + + const mediaMessage = new CometChat.MediaMessage( + "receiver-uid", + file, + CometChat.MESSAGE_TYPE.IMAGE, // IMAGE, VIDEO, AUDIO, FILE + CometChat.RECEIVER_TYPE.USER + ); + + // Optional: Add caption + mediaMessage.setCaption("Check out this photo!"); + + CometChat.sendMediaMessage(mediaMessage).then( + (message) => console.log("Sent:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```javascript + // Example: Location message + const customMessage = new CometChat.CustomMessage( + "receiver-uid", + CometChat.RECEIVER_TYPE.USER, + "location", // Your custom type + { + latitude: 37.7749, + longitude: -122.4194, + address: "San Francisco, CA" + } + ); + + CometChat.sendCustomMessage(customMessage).then( + (message) => console.log("Sent:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```javascript + // Text message + async function sendTextMessage(receiverID, text, isGroup = false) { + const receiverType = isGroup + ? CometChat.RECEIVER_TYPE.GROUP + : CometChat.RECEIVER_TYPE.USER; + + const textMessage = new CometChat.TextMessage( + receiverID, + text, + receiverType + ); + + try { + const message = await CometChat.sendMessage(textMessage); + console.log("Sent:", message); + return message; + } catch (error) { + console.error("Error:", error); + throw error; + } + } + + // Media message + async function sendMediaMessage(receiverID, file, type, isGroup = false) { + const receiverType = isGroup + ? CometChat.RECEIVER_TYPE.GROUP + : CometChat.RECEIVER_TYPE.USER; + + const mediaMessage = new CometChat.MediaMessage( + receiverID, + file, + type, + receiverType + ); + + try { + const message = await CometChat.sendMediaMessage(mediaMessage); + console.log("Sent:", message); + return message; + } catch (error) { + console.error("Error:", error); + throw error; + } + } + + // Custom message + async function sendCustomMessage(receiverID, customType, data, isGroup = false) { + const receiverType = isGroup + ? CometChat.RECEIVER_TYPE.GROUP + : CometChat.RECEIVER_TYPE.USER; + + const customMessage = new CometChat.CustomMessage( + receiverID, + receiverType, + customType, + data + ); + + try { + const message = await CometChat.sendCustomMessage(customMessage); + console.log("Sent:", message); + return message; + } catch (error) { + console.error("Error:", error); + throw error; + } + } + + // Usage + await sendTextMessage("user123", "Hello!"); + await sendMediaMessage("user123", file, CometChat.MESSAGE_TYPE.IMAGE); + await sendCustomMessage("user123", "location", { latitude: 37.7749, longitude: -122.4194 }); + ``` + + + +### Message Properties + +| Property | Method | Description | +|----------|--------|-------------| +| ID | `getId()` | Unique message identifier | +| Sender | `getSender()` | User who sent the message | +| Receiver | `getReceiver()` | User or Group receiving | +| Type | `getType()` | text, image, video, etc. | +| Category | `getCategory()` | message, custom, action, call | +| Sent At | `getSentAt()` | Timestamp when sent | +| Delivered At | `getDeliveredAt()` | When delivered | +| Read At | `getReadAt()` | When read | +| Edited At | `getEditedAt()` | When edited (if edited) | +| Deleted At | `getDeletedAt()` | When deleted (if deleted) | +| Metadata | `getMetadata()` | Custom data attached | +| Tags | `getTags()` | Tags for filtering | + +--- + +## Conversations + +A **Conversation** represents a chat thread and is automatically created when messages are exchanged. -GUID can be alphanumeric with underscore and hyphen. Spaces, punctuation and other special characters are not allowed. +### Conversation Types +```mermaid +graph LR + subgraph "User Conversation" + U1[User A] <-->|1:1 Chat| U2[User B] + end + + subgraph "Group Conversation" + G1[User A] <--> G[Group] + G2[User B] <--> G + G3[User C] <--> G + end +``` + +| Type | Description | Created When | +|------|-------------|--------------| +| **User** | One-on-one chat | First message between two users | +| **Group** | Group chat | User joins or messages a group | + +### Conversation Properties + + + +```javascript +// Fetch conversations +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .build(); + +conversationsRequest.fetchNext().then((conversations) => { + conversations.forEach((conversation) => { + // Conversation details + console.log("ID:", conversation.getConversationId()); + console.log("Type:", conversation.getConversationType()); // "user" or "group" + console.log("Unread:", conversation.getUnreadMessageCount()); + console.log("Updated:", conversation.getUpdatedAt()); + + // Last message + const lastMessage = conversation.getLastMessage(); + console.log("Last message:", lastMessage?.getText()); + + // Conversation partner (user or group) + const partner = conversation.getConversationWith(); + console.log("With:", partner.getName()); + }); +}); +``` + + +```javascript +async function fetchConversations() { + const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .build(); + + try { + const conversations = await conversationsRequest.fetchNext(); + + conversations.forEach((conversation) => { + console.log("ID:", conversation.getConversationId()); + console.log("Type:", conversation.getConversationType()); + console.log("Unread:", conversation.getUnreadMessageCount()); + console.log("Updated:", conversation.getUpdatedAt()); + + const lastMessage = conversation.getLastMessage(); + console.log("Last message:", lastMessage?.getText()); + + const partner = conversation.getConversationWith(); + console.log("With:", partner.getName()); + }); + + return conversations; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +| Property | Method | Description | +|----------|--------|-------------| +| ID | `getConversationId()` | Unique conversation ID | +| Type | `getConversationType()` | `user` or `group` | +| Last Message | `getLastMessage()` | Most recent message | +| Unread Count | `getUnreadMessageCount()` | Number of unread messages | +| Updated At | `getUpdatedAt()` | Last activity timestamp | +| Conversation With | `getConversationWith()` | User or Group object | +| Tags | `getTags()` | Conversation tags | + +### Building a Chat List + +```javascript +// Typical "Recent Chats" implementation +async function loadRecentChats() { + const request = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .build(); + + const conversations = await request.fetchNext(); + + return conversations.map((conv) => ({ + id: conv.getConversationId(), + name: conv.getConversationWith().getName(), + avatar: conv.getConversationWith().getAvatar(), + lastMessage: conv.getLastMessage()?.getText() || "No messages", + unreadCount: conv.getUnreadMessageCount(), + timestamp: conv.getUpdatedAt(), + isGroup: conv.getConversationType() === "group" + })); +} +``` + +--- + +## Real-Time Events + +CometChat uses WebSocket connections to deliver events instantly. You register **listeners** to handle these events. + +### Available Listeners + +```mermaid +graph TD + SDK[CometChat SDK] --> ML[MessageListener] + SDK --> UL[UserListener] + SDK --> GL[GroupListener] + SDK --> CL[CallListener] + SDK --> ConL[ConnectionListener] + + ML --> M1[onTextMessageReceived] + ML --> M2[onMediaMessageReceived] + ML --> M3[onTypingStarted] + ML --> M4[onMessagesRead] + + UL --> U1[onUserOnline] + UL --> U2[onUserOffline] + + GL --> G1[onGroupMemberJoined] + GL --> G2[onGroupMemberLeft] + GL --> G3[onGroupMemberKicked] + + CL --> C1[onIncomingCallReceived] + CL --> C2[onOutgoingCallAccepted] +``` + +| Listener | Events | Use Case | +|----------|--------|----------| +| **MessageListener** | Messages, typing, receipts, reactions | Chat UI updates | +| **UserListener** | Online/offline status | Presence indicators | +| **GroupListener** | Member changes, scope changes | Group roster updates | +| **CallListener** | Incoming/outgoing calls | Call handling | +| **ConnectionListener** | Connected/disconnected | Network status UI | + +### Registering Listeners + + + + ```javascript + const listenerID = "UNIQUE_MESSAGE_LISTENER"; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: (message) => { + console.log("Text received:", message.getText()); + // Update your chat UI + }, + onMediaMessageReceived: (message) => { + console.log("Media received:", message.getAttachment()); + }, + onTypingStarted: (typingIndicator) => { + console.log(typingIndicator.getSender().getName(), "is typing..."); + }, + onTypingEnded: (typingIndicator) => { + console.log(typingIndicator.getSender().getName(), "stopped typing"); + }, + onMessagesDelivered: (receipt) => { + console.log("Message delivered:", receipt.getMessageId()); + }, + onMessagesRead: (receipt) => { + console.log("Message read:", receipt.getMessageId()); + }, + onMessageEdited: (message) => { + console.log("Message edited:", message.getId()); + }, + onMessageDeleted: (message) => { + console.log("Message deleted:", message.getId()); + } + }) + ); + + // Remove when done (e.g., component unmount) + CometChat.removeMessageListener(listenerID); + ``` + + + ```javascript + const listenerID = "UNIQUE_USER_LISTENER"; + + CometChat.addUserListener( + listenerID, + new CometChat.UserListener({ + onUserOnline: (user) => { + console.log(user.getName(), "is now online"); + // Update presence indicator to green + }, + onUserOffline: (user) => { + console.log(user.getName(), "went offline"); + console.log("Last seen:", user.getLastActiveAt()); + // Update presence indicator to gray + } + }) + ); + + // Remove when done + CometChat.removeUserListener(listenerID); + ``` + + + ```javascript + const listenerID = "UNIQUE_GROUP_LISTENER"; + + CometChat.addGroupListener( + listenerID, + new CometChat.GroupListener({ + onGroupMemberJoined: (message, joinedUser, joinedGroup) => { + console.log(joinedUser.getName(), "joined", joinedGroup.getName()); + }, + onGroupMemberLeft: (message, leftUser, leftGroup) => { + console.log(leftUser.getName(), "left", leftGroup.getName()); + }, + onGroupMemberKicked: (message, kickedUser, kickedBy, kickedFrom) => { + console.log(kickedUser.getName(), "was kicked by", kickedBy.getName()); + }, + onGroupMemberBanned: (message, bannedUser, bannedBy, bannedFrom) => { + console.log(bannedUser.getName(), "was banned"); + }, + onGroupMemberScopeChanged: (message, user, newScope, oldScope, group) => { + console.log(user.getName(), "scope changed:", oldScope, "→", newScope); + }, + onMemberAddedToGroup: (message, addedUser, addedBy, addedTo) => { + console.log(addedUser.getName(), "was added by", addedBy.getName()); + } + }) + ); + + // Remove when done + CometChat.removeGroupListener(listenerID); + ``` + + + ```javascript + const listenerID = "UNIQUE_CONNECTION_LISTENER"; + + CometChat.addConnectionListener( + listenerID, + new CometChat.ConnectionListener({ + onConnected: () => { + console.log("Connected to CometChat"); + // Hide offline banner, enable send button + }, + inConnecting: () => { + console.log("Connecting..."); + // Show "Reconnecting..." indicator + }, + onDisconnected: () => { + console.log("Disconnected from CometChat"); + // Show offline banner, disable send button + } + }) + ); + + // Remove when done + CometChat.removeConnectionListener(listenerID); + ``` + + + + +**Important Rules:** +1. Use **unique listener IDs** - duplicate IDs will overwrite previous listeners +2. **Remove listeners** when components unmount to prevent memory leaks +3. Register listeners **after login** - they won't work before authentication -### Types +--- + +## Integration Patterns + +### Pattern 1: User Registration Flow + +```mermaid +sequenceDiagram + participant User + participant App as Your App + participant Server as Your Server + participant CC as CometChat -CometChat supports three different types of groups: + User->>App: Sign up with email/password + App->>Server: Create account request + Server->>Server: Validate & save user + Server->>CC: POST /users (REST API) + CC->>Server: User created + Server->>CC: POST /users/{uid}/auth_tokens + CC->>Server: Auth token + Server->>App: Return auth token + App->>CC: CometChat.login(authToken) + CC->>App: Login successful + App->>User: Welcome to the app! +``` -| Type | Visibility | Participation | -| -------- | ---------------------------- | ------------------------------------------------- | -| Public | All users | Any user can choose to join | -| Password | All users | Any user with a valid password can choose to join | -| Private | Only users part of the group | Invited users will be auto-joined | +### Pattern 2: Existing User Login Flow -### Members +```mermaid +sequenceDiagram + participant User + participant App as Your App + participant Server as Your Server + participant CC as CometChat -Once a participant joins a group, they become a member of the group. Members are part of the group indefinitely i.e. they will keep receiving messages, calls & notifications. To stop, the participant must either be kicked, banned or intentionally leave the group. + User->>App: Login with credentials + App->>Server: Authenticate + Server->>Server: Verify credentials + Server->>CC: POST /users/{uid}/auth_tokens + CC->>Server: Auth token + Server->>App: Return auth token + App->>CC: CometChat.login(authToken) + CC->>App: Login successful +``` -CometChat supports three different types of member scopes in a group: +### Pattern 3: Chat Screen Initialization -| Member | Default | Privileges | -| ----------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Admin | Group creator is assigned Admin scope | - Change scope of Group Members to admin, moderator or participant. - Can add members to a group. - Kick & Ban Participants/Moderators/Admins - Send & Receive Messages & Calls - Update group - Delete group | -| Moderator | - | - Change scope of moderator or participant. - Update group - Kick & Ban Participants - Send & Receive Messages & Calls | -| Participant | Any other user is assigned Participant scope | - Send & Receive Messages & Calls | +```javascript +// Typical chat screen setup +async function initializeChatScreen(conversationId, conversationType) { + // 1. Register message listener + CometChat.addMessageListener( + "CHAT_SCREEN_LISTENER", + new CometChat.MessageListener({ + onTextMessageReceived: (message) => addMessageToUI(message), + onMediaMessageReceived: (message) => addMessageToUI(message), + onTypingStarted: (indicator) => showTypingIndicator(indicator), + onTypingEnded: (indicator) => hideTypingIndicator(indicator), + onMessagesRead: (receipt) => updateReadStatus(receipt) + }) + ); -### Messaging + // 2. Fetch message history + const messagesRequest = new CometChat.MessagesRequestBuilder() + [conversationType === "user" ? "setUID" : "setGUID"](conversationId) + .setLimit(30) + .build(); -Any message in CometChat can belong to either one of the below categories + const messages = await messagesRequest.fetchPrevious(); + displayMessages(messages); + + // 3. Mark conversation as read + if (messages.length > 0) { + CometChat.markAsRead(messages[messages.length - 1]); + } +} + +// Cleanup when leaving chat screen +function cleanupChatScreen() { + CometChat.removeMessageListener("CHAT_SCREEN_LISTENER"); +} +``` + +### Integration Checklist + +| Step | Your App | CometChat | When | +|------|----------|-----------|------| +| User signs up | Save to database | Create user (REST API) | Registration | +| User logs in | Verify credentials | Generate auth token → SDK login | Login | +| Open chat list | - | Fetch conversations | App load | +| Open chat | - | Fetch messages, add listeners | Enter chat | +| Send message | - | SDK handles | User action | +| Receive message | - | Listener callback | Real-time | +| User logs out | Clear session | `CometChat.logout()` | Logout | + +--- + +## Common Patterns & Best Practices + + + + **When to create CometChat users:** + - Create during user registration in your app + - Use the same UID as your database user ID + + ```javascript + // Your server-side code (Node.js example) + async function registerUser(email, password, name) { + // 1. Create user in your database + const user = await db.users.create({ email, password, name }); + + // 2. Create user in CometChat + await fetch(`https://api-${REGION}.cometchat.io/v3/users`, { + method: "POST", + headers: { + "apiKey": REST_API_KEY, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + uid: user.id, // Use same ID + name: name + }) + }); + + return user; + } + ``` + + + + ```javascript + // Track connection status + let isOnline = false; + const pendingMessages = []; + + CometChat.addConnectionListener( + "CONNECTION_HANDLER", + new CometChat.ConnectionListener({ + onConnected: () => { + isOnline = true; + // Send any queued messages + pendingMessages.forEach(msg => CometChat.sendMessage(msg)); + pendingMessages.length = 0; + }, + onDisconnected: () => { + isOnline = false; + } + }) + ); + + // Queue messages when offline + function sendMessage(message) { + if (isOnline) { + return CometChat.sendMessage(message); + } else { + pendingMessages.push(message); + return Promise.resolve(message); // Optimistic UI + } + } + ``` + + + + ```javascript + // React example with cleanup + useEffect(() => { + const listenerID = `chat-${conversationId}`; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: handleNewMessage + }) + ); + + // Cleanup on unmount or conversation change + return () => { + CometChat.removeMessageListener(listenerID); + }; + }, [conversationId]); + ``` + + + + ```javascript + class MessagePaginator { + constructor(uid) { + this.request = new CometChat.MessagesRequestBuilder() + .setUID(uid) + .setLimit(30) + .build(); + this.hasMore = true; + } + + async loadMore() { + if (!this.hasMore) return []; + + const messages = await this.request.fetchPrevious(); + this.hasMore = messages.length === 30; + return messages; + } + } + + // Usage + const paginator = new MessagePaginator("user123"); + const firstPage = await paginator.loadMore(); + // On scroll up... + const secondPage = await paginator.loadMore(); + ``` + + + +--- + +## Quick Reference + +### SDK Constants + +```javascript +// Receiver Types +CometChat.RECEIVER_TYPE.USER +CometChat.RECEIVER_TYPE.GROUP + +// Message Types +CometChat.MESSAGE_TYPE.TEXT +CometChat.MESSAGE_TYPE.IMAGE +CometChat.MESSAGE_TYPE.VIDEO +CometChat.MESSAGE_TYPE.AUDIO +CometChat.MESSAGE_TYPE.FILE + +// Group Types +CometChat.GROUP_TYPE.PUBLIC +CometChat.GROUP_TYPE.PASSWORD +CometChat.GROUP_TYPE.PRIVATE + +// Member Scopes +CometChat.GROUP_MEMBER_SCOPE.ADMIN +CometChat.GROUP_MEMBER_SCOPE.MODERATOR +CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT + +// Call Types +CometChat.CALL_TYPE.AUDIO +CometChat.CALL_TYPE.VIDEO + +// User Status +CometChat.USER_STATUS.ONLINE +CometChat.USER_STATUS.OFFLINE +``` + +### Common Methods Cheat Sheet + +| Action | Method | +|--------|--------| +| Initialize | `CometChat.init(appID, appSettings)` | +| Login | `CometChat.login(uid, authKey)` or `CometChat.login(authToken)` | +| Logout | `CometChat.logout()` | +| Get logged-in user | `CometChat.getLoggedinUser()` | +| Send text message | `CometChat.sendMessage(textMessage)` | +| Send media | `CometChat.sendMediaMessage(mediaMessage)` | +| Fetch messages | `messagesRequest.fetchPrevious()` | +| Fetch conversations | `conversationsRequest.fetchNext()` | +| Fetch users | `usersRequest.fetchNext()` | +| Fetch groups | `groupsRequest.fetchNext()` | +| Join group | `CometChat.joinGroup(guid, type, password?)` | +| Leave group | `CometChat.leaveGroup(guid)` | +| Mark as read | `CometChat.markAsRead(message)` | +| Start typing | `CometChat.startTyping(typingIndicator)` | +| End typing | `CometChat.endTyping(typingIndicator)` | + +--- + +## Glossary + +Quick reference for terms used throughout the CometChat JavaScript SDK documentation. + +| Term | Definition | +|------|-----------| +| **UID** | User Identifier. A unique string you assign to each user. Alphanumeric, underscores, and hyphens only. | +| **GUID** | Group Unique Identifier. A unique string you assign to each group. Same character rules as UID. | +| **App ID** | Your application's unique identifier from the [CometChat Dashboard](https://app.cometchat.com). Safe to include in client code. | +| **Auth Key** | A key for client-side login during development. Never use in production — use Auth Tokens instead. | +| **Auth Token** | A short-lived token generated server-side via REST API. The secure way to authenticate users in production. | +| **REST API Key** | A server-only key with full admin access. Never expose in client-side code. | +| **Region** | The server region your app runs on (`us`, `eu`, or `in`). Set during app creation. | +| **Receiver Type** | Whether a message target is a `USER` or `GROUP`. Set via `CometChat.RECEIVER_TYPE`. | +| **Message Category** | High-level classification: `message`, `custom`, `action`, or `call`. | +| **Message Type** | Specific type within a category: `text`, `image`, `video`, `audio`, `file`, or your custom types. | +| **Scope** | A group member's permission level: `admin`, `moderator`, or `participant`. | +| **Listener** | A callback object registered with the SDK to receive real-time events (messages, presence, group changes, calls). | +| **Conversation** | An auto-created thread between a user pair or within a group. Tracks last message and unread count. | +| **Metadata** | Arbitrary JSON data you can attach to users, groups, or messages for custom use cases. | +| **Tags** | String labels you can attach to users, groups, messages, or conversations for filtering and categorization. | + +--- -| Category | Description | -| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| message | Any message belonging to the category `message` can belong to either one of the below types: 1. text 2. image 3. video 4. audio 5. file | -| custom | Custom messages are an option available for developers to send custom data across to users/groups. To send any additional data that does not fit in the default categories and types provided by CometChat, you can use the custom messages. | -| action | Action messages are system-generated messages. These can belong to either of the below types: 1. groupMember - when the action is performed on a group member 2. message - when the action is performed on a message | -| call | These are call-related messages. These can belong to either one of the two types: 1. audio 2. video | +## Next Steps -For more information, you can refer to the [Message structure and hierarchy guide](/sdk/javascript/message-structure-and-hierarchy). + + + Install and configure the SDK for your framework + + + Learn about Auth Keys vs Auth Tokens + + + Send text, media, and custom messages + + + Handle real-time and historical messages + + + Create and manage users + + + Create and manage group conversations + + diff --git a/sdk/javascript/leave-group.mdx b/sdk/javascript/leave-group.mdx index a9534b8a..56cfa544 100644 --- a/sdk/javascript/leave-group.mdx +++ b/sdk/javascript/leave-group.mdx @@ -1,97 +1,129 @@ --- -title: "Leave A Group" +title: "Leave a Group" +sidebarTitle: "Leave Group" +description: "Leave a group to stop receiving messages and updates" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Leave a group +await CometChat.leaveGroup("group_guid"); -## Leave a Group +// Listen for leave events +CometChat.addGroupListener("GROUP_LISTENER", new CometChat.GroupListener({ + onGroupMemberLeft: (message, leftUser, group) => { + console.log(leftUser.getName(), "left", group.getName()); + } +})); + +// Note: Transfer ownership first if you're the only admin +``` + + +Leave a group when you no longer want to participate in the conversation. + + +**Availability**: SDK, API, UI Kits + +After leaving, you won't receive messages or updates from the group. + + +--- -In order to stop receiving updates and messages for any particular joined group, you will have to leave the group using the `leaveGroup()` method. +## Leave a Group - + ```javascript -var GUID = "GUID"; +const GUID = "group-123"; CometChat.leaveGroup(GUID).then( -hasLeft => { - console.log("Group left successfully:", hasLeft); -}, error => { - console.log("Group leaving failed with exception:", error); -} + (hasLeft) => console.log("Left group:", hasLeft), + (error) => console.log("Failed to leave:", error) ); ``` - - ```typescript -var GUID: string = "GUID"; +const GUID: string = "group-123"; CometChat.leaveGroup(GUID).then( - (hasLeft: boolean) => { - console.log("Group left successfully:", hasLeft); - }, (error: CometChat.CometChatException) => { - console.log("Group leaving failed with exception:", error); - } + (hasLeft: boolean) => console.log("Left group:", hasLeft), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - + +```javascript +const leaveGroup = async () => { + try { + const GUID = "group-123"; + const hasLeft = await CometChat.leaveGroup(GUID); + console.log("Left group:", hasLeft); + } catch (error) { + console.log("Failed to leave:", error); + } +}; +``` + -| Parameter | Description | -| --------- | -------------------------------------------- | -| `GUID` | The UID of the group you would like to leave | + +If you're the only admin, you should transfer ownership before leaving. Otherwise, the group may become unmanageable. + -Once a group is left, the user will no longer receive any updates or messages pertaining to the group. - -## Real-time Group Member Left Events +--- -*In other words, as a member of a group, how do I know if someone has left it?* +## Real-Time Leave Events -If a user leaves any group, The members of the group receive a real-time event in the `onGroupMemberLeft()` method of the `GroupListener` class. +Listen for when users leave groups you're a member of: - - ```javascript -CometChat.addGroupListener( - "UNIQUE_LISTENER_ID", - new CometChat.GroupListener({ - onGroupMemberLeft: (message, leavingUser, group) => { - console.log("User left", { message, leavingUser, group }); - } - }) -); -``` - - +const listenerID = "GROUP_LISTENER"; - -```typescript CometChat.addGroupListener( - "UNIQUE_LISTENER_ID", + listenerID, new CometChat.GroupListener({ - onGroupMemberLeft: (message: CometChat.Action, leavingUser: CometChat.User, group: CometChat.Group) => { - console.log("User left", { message, leavingUser, group }); - } + onGroupMemberLeft: (message, leftUser, group) => { + console.log(`${leftUser.getName()} left ${group.getName()}`); + } }) ); + +// Remove listener when done +CometChat.removeGroupListener(listenerID); ``` - +--- - +## Missed Leave Events -## Missed Group Member Left Events +When fetching message history, leave events appear as `Action` messages: -*In other words, as a member of a group, how do I know if someone has left it when my app is not running?* +```javascript +messages.forEach((message) => { + if (message.getCategory() === "action") { + const action = message.getAction(); + if (action === "left") { + const user = message.getActionBy(); + console.log(`${user.getName()} left the group`); + } + } +}); +``` -When you retrieve the list of previous messages if a member has left any group that the logged-in user is a member of, the list of messages will contain an `Action` message. An `Action` message is a sub-class of `BaseMessage` class. +--- -For the group member left event, in the `Action` object received, the following fields can help you get the relevant information- +## Next Steps -1. `action` - `left` -2. `actionBy` - User object containing the details of the user who left the group -3. `actionFor` - Group object containing the details of the group the user has left + + + Join a group + + + Delete a group (admin only) + + diff --git a/sdk/javascript/login-listener.mdx b/sdk/javascript/login-listener.mdx index 4c98ff4c..f21fc0a1 100644 --- a/sdk/javascript/login-listener.mdx +++ b/sdk/javascript/login-listener.mdx @@ -1,88 +1,304 @@ --- title: "Login Listener" +description: "Monitor authentication state changes in real-time" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Add login listener +CometChat.addLoginListener("AUTH_LISTENER", new CometChat.LoginListener({ + loginSuccess: (user) => console.log("Logged in:", user.getUid()), + logoutSuccess: () => console.log("Logged out") +})); -The CometChat SDK provides you with real-time updates for the `login` and `logout` events. This can be achieved using the `LoginListener` class provided. LoginListener consists of 4 events that can be triggered. These are as follows: +// Remove listener +CometChat.removeLoginListener("AUTH_LISTENER"); +``` + + +The `LoginListener` provides real-time updates for authentication events, enabling you to respond to login/logout across devices and sessions. + +## Use Cases + +- Sync UI state across browser tabs +- Handle session expiration gracefully +- Track authentication analytics +- Implement single-session enforcement -| Delegate Method | Information | -| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| loginSuccess(event) | Informs you that the login was successful and provides you with a user object containing the data for the user that logged in. | -| loginFailure(event) | Informs you about the failure while logging in the user and provides you with the reason for the failure wrapped in an object of the `CometChatException` class. | -| logoutSuccess() | Informs you about the user being logged out successfully. | -| logoutFailure(event) | Informs you about the failure while logging out the user. The reason for the failure can be obtained from the object of the `CometChatException` class. | +## Listener Events -To add the `LoginListener`, you need to use the `addLoginListener()` method provided by the SDK which takes a unique identifier for the listener and of the the `LoginListener` class itself. +| Event | Description | Data | +|-------|-------------|------| +| `loginSuccess` | User logged in successfully | `CometChat.User` | +| `loginFailure` | Login attempt failed | `CometChat.CometChatException` | +| `logoutSuccess` | User logged out successfully | None | +| `logoutFailure` | Logout attempt failed | `CometChat.CometChatException` | + +## Implementation -```js - let listenerID = "UNIQUE_LISTENER_ID"; - CometChat.addLoginListener( - listenerID, - new CometChat.LoginListener({ - loginSuccess: (e) => { - console.log("LoginListener :: loginSuccess", e); - }, - loginFailure: (e) => { - console.log("LoginListener :: loginFailure", e); - }, - logoutSuccess: () => { - console.log("LoginListener :: logoutSuccess"); - }, - logoutFailure: (e) => { - console.log("LoginListener :: logoutFailure", e); - } - }) - ); +```javascript +const listenerID = "AUTH_LISTENER"; + +CometChat.addLoginListener( + listenerID, + new CometChat.LoginListener({ + loginSuccess: (user) => { + console.log("Login successful:", user.getUid()); + // Update UI to logged-in state + // Initialize chat features + }, + loginFailure: (error) => { + console.error("Login failed:", error.message); + // Show error message + // Redirect to login page + }, + logoutSuccess: () => { + console.log("Logout successful"); + // Clear local data + // Redirect to login page + }, + logoutFailure: (error) => { + console.error("Logout failed:", error.message); + // Handle logout error + } + }) +); ``` + + +```typescript +const listenerID: string = "AUTH_LISTENER"; +CometChat.addLoginListener( + listenerID, + new CometChat.LoginListener({ + loginSuccess: (user: CometChat.User): void => { + console.log("Login successful:", user.getUid()); + // Update UI to logged-in state + }, + loginFailure: (error: CometChat.CometChatException): void => { + console.error("Login failed:", error.message); + // Show error message + }, + logoutSuccess: (): void => { + console.log("Logout successful"); + // Clear local data + }, + logoutFailure: (error: CometChat.CometChatException): void => { + console.error("Logout failed:", error.message); + // Handle logout error + } + }) +); +``` + +## Remove Listener + +Remove the listener when it's no longer needed: + + + +```javascript +CometChat.removeLoginListener("AUTH_LISTENER"); +``` + ```typescript - var listenerID: string = "UNIQUE_LISTENER_ID"; - CometChat.addLoginListener( - listenerID, +CometChat.removeLoginListener("AUTH_LISTENER"); +``` + + + +## React Integration + + + +```jsx +import { useEffect, useState } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +function useAuthState() { + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + // Check initial auth state + const checkAuth = async () => { + try { + const loggedInUser = await CometChat.getLoggedinUser(); + setUser(loggedInUser); + } finally { + setLoading(false); + } + }; + + checkAuth(); + + // Listen for auth changes + CometChat.addLoginListener( + "AUTH_STATE_LISTENER", new CometChat.LoginListener({ - loginSuccess: (user: CometChat.User) => { - console.log("LoginListener :: loginSuccess", user); - }, - loginFailure: (error: CometChat.CometChatException) => { - console.log("LoginListener :: loginFailure", error); - }, - logoutSuccess: () => { - console.log("LoginListener :: logoutSuccess"); - }, - logoutFailure: (error: CometChat.CometChatException) => { - console.log("LoginListener :: logoutFailure", error); - } + loginSuccess: (loggedInUser) => { + setUser(loggedInUser); + }, + logoutSuccess: () => { + setUser(null); + } }) - ); -``` + ); + return () => { + CometChat.removeLoginListener("AUTH_STATE_LISTENER"); + }; + }, []); + + return { user, loading }; +} +``` + +```tsx +import { useEffect, useState } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +interface AuthState { + user: CometChat.User | null; + loading: boolean; +} + +function useAuthState(): AuthState { + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + // Check initial auth state + const checkAuth = async () => { + try { + const loggedInUser = await CometChat.getLoggedinUser(); + setUser(loggedInUser); + } finally { + setLoading(false); + } + }; + + checkAuth(); + + // Listen for auth changes + CometChat.addLoginListener( + "AUTH_STATE_LISTENER", + new CometChat.LoginListener({ + loginSuccess: (loggedInUser: CometChat.User): void => { + setUser(loggedInUser); + }, + logoutSuccess: (): void => { + setUser(null); + } + }) + ); + return () => { + CometChat.removeLoginListener("AUTH_STATE_LISTENER"); + }; + }, []); + + return { user, loading }; +} +``` + -In order to stop receiving events related to login and logout you need to use the removeLoginListener() method provided by the SDK and pass the ID of the listener that needs to be removed. +## Multi-Tab Synchronization + +Keep authentication state synchronized across browser tabs: -```js - var listenerID = "UNIQUE_LISTENER_ID"; - CometChat.removeLoginListener(listenerID); +```javascript +// This listener fires when login/logout happens in ANY tab +CometChat.addLoginListener( + "MULTI_TAB_SYNC", + new CometChat.LoginListener({ + loginSuccess: (user) => { + // Another tab logged in + window.location.reload(); // Refresh to sync state + }, + logoutSuccess: () => { + // Another tab logged out + window.location.href = "/login"; + } + }) +); ``` - - ```typescript - var listenerID: string = "UNIQUE_LISTENER_ID"; - CometChat.removeLoginListener(listenerID); +CometChat.addLoginListener( + "MULTI_TAB_SYNC", + new CometChat.LoginListener({ + loginSuccess: (user: CometChat.User): void => { + window.location.reload(); + }, + logoutSuccess: (): void => { + window.location.href = "/login"; + } + }) +); ``` - - + +## Best Practices + + + + Ensure each listener has a unique ID to prevent conflicts. + + ```javascript + // Good + CometChat.addLoginListener("APP_AUTH_LISTENER", ...); + CometChat.addLoginListener("ANALYTICS_AUTH_LISTENER", ...); + ``` + + + + Always remove listeners when components unmount. + + ```javascript + useEffect(() => { + CometChat.addLoginListener("LISTENER_ID", listener); + return () => CometChat.removeLoginListener("LISTENER_ID"); + }, []); + ``` + + + + Implement handlers for both success and failure cases. + + ```javascript + new CometChat.LoginListener({ + loginSuccess: (user) => { /* handle */ }, + loginFailure: (error) => { /* handle */ }, + logoutSuccess: () => { /* handle */ }, + logoutFailure: (error) => { /* handle */ } + }) + ``` + + + +## Next Steps + + + + Learn about login methods + + + Explore all available listeners + + diff --git a/sdk/javascript/managing-web-sockets-connections-manually.mdx b/sdk/javascript/managing-web-sockets-connections-manually.mdx index 90cf107b..bb9fd56d 100644 --- a/sdk/javascript/managing-web-sockets-connections-manually.mdx +++ b/sdk/javascript/managing-web-sockets-connections-manually.mdx @@ -1,100 +1,224 @@ --- -title: "Managing Web Sockets Connections Manually" +title: "Manual WebSocket Management" +sidebarTitle: "WebSocket Management" +description: "Take control of WebSocket connections for advanced use cases" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Disable auto-connect during init +const appSettings = new CometChat.AppSettingsBuilder() + .setRegion("REGION") + .autoEstablishSocketConnection(false) // Manual mode + .build(); -## Default SDK behaviour on login +// Manual connect/disconnect +CometChat.connect(); // Connect WebSocket +CometChat.disconnect(); // Disconnect WebSocket +``` + -When the login method of the SDK is called, the SDK performs the below operations: +By default, CometChat SDK manages WebSocket connections automatically. For advanced use cases, you can take manual control of the connection. -1. Logs the user into the SDK -2. Saves the details of the logged in user locally. -3. Creates a web-socket connection for the logged in user. + +**Default Behavior**: The SDK automatically connects to WebSocket servers on login and reconnects when the app reopens. + -This makes sure that the logged in user starts receiving real-time messages sent to him or any groups that he is a part of as soon as he logs in. +--- -When the app is reopened, and the init() method is called, the web-socket connection to the server is established automatically. +## Default vs Manual Mode -This is the default behaviour of the CometChat SDKs. However, if you wish to take control of the web-socket connection i.e if you wish to connect and disconnect to the web-socket server manually, you can refer to the Managing Web-socket Connection section. +| Aspect | Default (Auto) | Manual | +|--------|----------------|--------| +| Connection on login | Automatic | You control | +| Reconnection | Automatic | You control | +| Use case | Most apps | Battery optimization, background control | -## Managing the Web-socket connections manually +--- -The CometChat SDK also allows you to modify the above default behaviour of the SDK and take the control of the web-socket connection into your own hands. In order to achieve this, you need to follow the below steps: +## Enable Manual Mode -1. While calling the init() function on the app startup, you need to inform the SDK that you will be managing the web socket connect. You can do so by using the `autoEstablishSocketConnection()` method provided by the `AppSettingsBuilder` class. This method takes a boolean value as an input. If set to `true` , the SDK will manage the web-socket connection internally based on the default behaviour mentioned above. If set to `false` , the web socket connection can will not be managed by the SDK and you will have to handle it manually. You can refer to the below code snippet for the same: +Disable automatic WebSocket management during initialization: -```js -let appID = "APP_ID"; -let region = "APP_REGION"; -let appSetting = new CometChat.AppSettingsBuilder() +```javascript +const appID = "APP_ID"; +const region = "APP_REGION"; + +const appSettings = new CometChat.AppSettingsBuilder() .subscribePresenceForAllUsers() .setRegion(region) - .autoEstablishSocketConnection(false) + .autoEstablishSocketConnection(false) // Disable auto-connect .build(); -CometChat.init(appID, appSetting).then( - () => { - console.log("Initialization completed successfully"); - }, - (error) => { - console.log("Initialization failed with error:", error); - } + +CometChat.init(appID, appSettings).then( + () => console.log("Initialized (manual WebSocket mode)"), + (error) => console.log("Init failed:", error) ); ``` - - ```typescript -let appID: string = "APP_ID"; -let region: string = "APP_REGION"; -let appSetting: CometChat.AppSettings = new CometChat.AppSettingsBuilder() +const appID: string = "APP_ID"; +const region: string = "APP_REGION"; + +const appSettings: CometChat.AppSettings = new CometChat.AppSettingsBuilder() .subscribePresenceForAllUsers() .setRegion(region) .autoEstablishSocketConnection(false) .build(); -CometChat.init(appID, appSetting).then( - (isInitialized: boolean) => { - console.log("Initialization completed successfully"); - }, - (error: CometChat.CometChatException) => { - console.log("Initialization failed with error:", error); - } + +CometChat.init(appID, appSettings).then( + () => console.log("Initialized (manual WebSocket mode)"), + (error: CometChat.CometChatException) => console.log("Init failed:", error) ); ``` - - + +```javascript +async function initializeManualMode() { + const appID = "APP_ID"; + const region = "APP_REGION"; + + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(false) + .build(); + + try { + await CometChat.init(appID, appSettings); + console.log("Initialized (manual WebSocket mode)"); + return true; + } catch (error) { + console.log("Init failed:", error); + return false; + } +} +``` + -You can manage the connection to the web-socket server using the `connect()` and `disconnect()` methods provided by the SDK. +--- -1. Connect to the web-socket server +## Connect to WebSocket -You need to use the `connect()` method provided by the `CometChat` class to establish the connection to the web-socket server. Please make sure that the user is logged in to the SDK before calling this method. You can use the CometChat.getLoggedInUser() method to check this. Once the connection is established, you will start receiving all the real-time events for the logged in user. +Manually establish the WebSocket connection: - - ```javascript -CometChat.connect(); +// Ensure user is logged in first +const user = await CometChat.getLoggedinUser(); + +if (user) { + CometChat.connect(); + console.log("WebSocket connection initiated"); +} ``` - + +Only call `connect()` after the user is logged in. Use `CometChat.getLoggedinUser()` to verify. + - +--- -2. Disconnect from the web-socket server +## Disconnect from WebSocket -You can use the `disconnect()` method provided by the `CometChat` class to break the established connection. Once the connection is broken, you will stop receiving all the real-time events for the logged in user. +Manually close the WebSocket connection: - - ```javascript CometChat.disconnect(); +console.log("WebSocket disconnected"); ``` - +--- - +## Use Cases + + + + Disconnect when the app goes to background to save battery, reconnect when foregrounded. + + + Only connect to real-time when user opens chat, disconnect when they leave. + + + Control connections based on network type (WiFi vs cellular). + + + +--- + +## Implementation Example + +```javascript +class WebSocketManager { + constructor() { + this.isConnected = false; + } + + async connect() { + const user = await CometChat.getLoggedinUser(); + if (!user) { + console.log("User not logged in"); + return false; + } + + CometChat.connect(); + this.isConnected = true; + console.log("WebSocket connected"); + return true; + } + + disconnect() { + CometChat.disconnect(); + this.isConnected = false; + console.log("WebSocket disconnected"); + } + + // Call when app goes to background + onAppBackground() { + if (this.isConnected) { + this.disconnect(); + } + } + + // Call when app comes to foreground + async onAppForeground() { + if (!this.isConnected) { + await this.connect(); + } + } +} + +// Usage +const wsManager = new WebSocketManager(); + +// When user opens chat +await wsManager.connect(); + +// When app goes to background +document.addEventListener("visibilitychange", () => { + if (document.hidden) { + wsManager.onAppBackground(); + } else { + wsManager.onAppForeground(); + } +}); +``` + +--- + +## Next Steps + + + + Monitor connection state + + + SDK configuration options + + diff --git a/sdk/javascript/mentions.mdx b/sdk/javascript/mentions.mdx index c3ce4742..4ce1df42 100644 --- a/sdk/javascript/mentions.mdx +++ b/sdk/javascript/mentions.mdx @@ -1,368 +1,532 @@ --- title: "Mentions" +sidebarTitle: "Mentions" +description: "@mention users in messages to get their attention" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Mention format: <@uid:USER_UID> +const messageText = "Hey <@uid:john123>, check this out!"; + +// Send message with mentions +const textMessage = new CometChat.TextMessage(receiverID, messageText, receiverType); +await CometChat.sendMessage(textMessage); + +// Get mentioned users from message +const mentionedUsers = message.getMentionedUsers(); +mentionedUsers.forEach((user) => { + console.log("Mentioned:", user.getName(), user.getUid()); +}); + +// Fetch messages with mention info +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(guid) + .mentionsWithTagInfo(true) + .mentionsWithBlockedInfo(true) + .build(); + +// Display: Replace <@uid:john123> with @John in UI +``` + -Mentions in messages enable users to refer to specific individual within a conversation. This is done by using the `<@uid:UID>` format, where `UID` represents the user’s unique identification. +Mentions let users reference specific people in a conversation using the `<@uid:UID>` format. This is especially useful in group chats to direct messages to specific participants and trigger notifications. -Mentions are a powerful tool for enhancing communication in messaging platforms. They streamline interaction by allowing users to easily engage and collaborate with particular individuals, especially in group conversations. + +**Availability**: SDK, API, UI Kits + +Mentions work in text messages and media message captions. + + +--- -## Send Mentioned Messages +## Mention Format -To send a message with a mentioned user, you must follow a specific format: `<@uid:UID>`. For example, to mention the user with UID `cometchat-uid-1` with the message "`Hello`," your text would be `"Hello, <@uid:cometchat-uid-1>"` +To mention a user, include their UID in this format within your message text: + +``` +<@uid:USER_UID> +``` + +| Example | Result | +|---------|--------| +| `<@uid:john123>` | Mentions user with UID "john123" | +| `Hey <@uid:john123>, check this!` | Message mentioning John | +| `<@uid:user1> and <@uid:user2>` | Multiple mentions | + +--- + +## Send a Message with Mentions - + ```javascript -let receiverID = "UID"; -let messageText = "Hello, <@uid:cometchat-uid-1>"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let textMessage = new CometChat.TextMessage( +const receiverID = "UID"; +const messageText = "Hey <@uid:cometchat-uid-1>, check this out!"; +const receiverType = CometChat.RECEIVER_TYPE.USER; + +const textMessage = new CometChat.TextMessage( receiverID, messageText, receiverType ); CometChat.sendMessage(textMessage).then( - (message) => { - console.log("Message sent successfully:", message); - }, - (error) => { - console.log("Message sending failed with error:", error); - } + (message) => console.log("Message sent:", message), + (error) => console.log("Failed to send:", error) ); ``` - - - + ```javascript -let receiverID = "GUID"; -let messageText = "Hello <@uid:cometchat-uid-1>"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let textMessage = new CometChat.TextMessage( +const receiverID = "GUID"; +const messageText = "Hello <@uid:cometchat-uid-1> and <@uid:cometchat-uid-2>!"; +const receiverType = CometChat.RECEIVER_TYPE.GROUP; + +const textMessage = new CometChat.TextMessage( receiverID, messageText, receiverType ); CometChat.sendMessage(textMessage).then( - (message) => { - console.log("Message sent successfully:", message); - }, - (error) => { - console.log("Message sending failed with error:", error); - } + (message) => console.log("Message sent:", message), + (error) => console.log("Failed to send:", error) ); ``` - - - + ```typescript -let receiverID: string = "UID", - messageText: string = "Hello <@uid:cometchat-uid-1>"; - receiverType: string = CometChat.RECEIVER_TYPE.USER, - textMessage: CometChat.TextMessage = new CometChat.TextMessage(receiverID, messageText, receiverType); +const receiverID: string = "GUID"; +const messageText: string = "Hey <@uid:cometchat-uid-1>, what do you think?"; +const receiverType: string = CometChat.RECEIVER_TYPE.GROUP; + +const textMessage: CometChat.TextMessage = new CometChat.TextMessage( + receiverID, + messageText, + receiverType +); CometChat.sendMessage(textMessage).then( - (message: CometChat.TextMessage) => { - console.log("Message sent successfully:", message); - }, (error: CometChat.CometChatException) => { - console.log("Message sending failed with error:", error); - } + (message: CometChat.TextMessage) => console.log("Message sent:", message), + (error: CometChat.CometChatException) => console.log("Failed to send:", error) ); ``` - - - -```typescript -let receiverID: string = "GUID", - messageText: string = "Hello world!", - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - textMessage: CometChat.TextMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType - ); - -CometChat.sendMessage(textMessage).then( - (message: CometChat.TextMessage) => { - console.log("Message sent successfully:", message); - }, - (error: CometChat.CometChatException) => { - console.log("Message sending failed with error:", error); + +```javascript +const sendMentionMessage = async () => { + try { + const receiverID = "GUID"; + const messageText = "Hey <@uid:cometchat-uid-1>, check this out!"; + const receiverType = CometChat.RECEIVER_TYPE.GROUP; + + const textMessage = new CometChat.TextMessage( + receiverID, + messageText, + receiverType + ); + + const message = await CometChat.sendMessage(textMessage); + console.log("Message sent:", message); + } catch (error) { + console.log("Failed to send:", error); } -); +}; ``` - - - +--- -You can mention user in text message and media messages captions +## Get Mentioned Users - +Retrieve the list of users mentioned in a message: -## Mentioned Messages +```javascript +const mentionedUsers = message.getMentionedUsers(); +// Returns array of User objects (or empty array) + +mentionedUsers.forEach((user) => { + console.log("Mentioned:", user.getName(), user.getUid()); +}); +``` + +--- -By default, the SDK will fetch all the messages irrespective of the fact that the logged-in user is mentioned or not in the message. The SDK has other optional filters such as tags and blocked relationships. +## Fetch Messages with Mention Info -| Setting | Description | -| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| mentionsWithTagInfo(boolean value) | If set to `true`, SDK will fetch a list of messages where users are mentioned & will also fetch the tags of the mentioned users. **Default value = false.** | -| mentionsWithBlockedInfo(boolean value) | If set to `true`, SDK will fetch a list of messages where users are mentioned & will also fetch their blocked relationship with the logged-in user. **Default value = false.** | +When fetching messages, include additional information about mentioned users. -## Mentions With Tag Info +### Builder Options -To get a list of messages in a conversation where users are mentioned along with the user tags of the mentioned users. +| Method | Description | +|--------|-------------| +| `mentionsWithTagInfo(true)` | Include tags of mentioned users | +| `mentionsWithBlockedInfo(true)` | Include blocked relationship info | + +### With Tag Information - + ```javascript -let UID = "UID"; -let limit = 30; +const GUID = "GUID"; +const limit = 30; -var messagesRequest = new CometChat.MessagesRequestBuilder() - .setUID(UID) +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(GUID) .setLimit(limit) .mentionsWithTagInfo(true) .build(); messagesRequest.fetchPrevious().then( (messages) => { - messages.forEach((eachMessage) => { - eachMessage.getMentionedUsers().forEach((eachMentionedUser) => { - console.log(eachMentionedUser.getTags()); + messages.forEach((message) => { + message.getMentionedUsers().forEach((user) => { + console.log("User:", user.getName()); + console.log("Tags:", user.getTags()); }); }); }, - (error) => { - console.log("Message fetching failed with error:", error); - } + (error) => console.log("Failed to fetch:", error) ); ``` - + +```typescript +const GUID: string = "GUID"; +const limit: number = 30; - -```javascript -let GUID = "GUID"; -let limit = 30; - -var messagesRequest = new CometChat.MessagesRequestBuilder() +const messagesRequest: CometChat.MessagesRequest = new CometChat.MessagesRequestBuilder() .setGUID(GUID) .setLimit(limit) .mentionsWithTagInfo(true) .build(); -messagesRequest.fetchPrevious().then( - (messages) => { - messages.forEach((eachMessage) => { - eachMessage.getMentionedUsers().forEach((eachMentionedUser) => { - console.log(eachMentionedUser.getTags()); - }); - }); - }, - (error) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - - -```typescript -let UID: string = "UID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() - .setUID(UID) - .setLimit(limit) - .mentionsWithTagInfo(true) - .build(); - messagesRequest.fetchPrevious().then( (messages: CometChat.BaseMessage[]) => { - messages.forEach((eachMessage: CometChat.BaseMessage) => { - eachMessage - .getMentionedUsers() - .forEach((eachMentionedUser: CometChat.User) => { - console.log(eachMentionedUser.getTags()); - }); + messages.forEach((message) => { + message.getMentionedUsers().forEach((user: CometChat.User) => { + console.log("User:", user.getName()); + console.log("Tags:", user.getTags()); + }); }); }, - (error) => { - console.log("Message fetching failed with error:", error); - } + (error: CometChat.CometChatException) => console.log("Failed to fetch:", error) ); ``` - + +```javascript +const fetchMessagesWithMentions = async () => { + try { + const GUID = "GUID"; + const limit = 30; - -```typescript -let GUID: string = "GUID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() + const messagesRequest = new CometChat.MessagesRequestBuilder() .setGUID(GUID) .setLimit(limit) .mentionsWithTagInfo(true) .build(); -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - messages.forEach((eachMessage: CometChat.BaseMessage) => { - eachMessage - .getMentionedUsers() - .forEach((eachMentionedUser: CometChat.User) => { - console.log(eachMentionedUser.getTags()); - }); + const messages = await messagesRequest.fetchPrevious(); + messages.forEach((message) => { + message.getMentionedUsers().forEach((user) => { + console.log("User:", user.getName()); + console.log("Tags:", user.getTags()); + }); }); - }, - (error) => { - console.log("Message fetching failed with error:", error); + } catch (error) { + console.log("Failed to fetch:", error); } -); +}; ``` - - -## Mentions With Blocked Info - -To get a list of messages in a conversation where users are mentioned along with the blocked relationship of the mentioned users with the logged-in user. +### With Blocked Relationship Info - + ```javascript -let UID = "UID"; -let limit = 30; +const GUID = "GUID"; +const limit = 30; -var messagesRequest = new CometChat.MessagesRequestBuilder() - .setUID(UID) +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(GUID) .setLimit(limit) .mentionsWithBlockedInfo(true) .build(); messagesRequest.fetchPrevious().then( (messages) => { - messages.forEach((eachMessage) => { - eachMessage.getMentionedUsers().forEach((eachMentionedUser) => { - console.log("blockedByMe: " + eachMentionedUser.getBlockedByMe()); - console.log("hasBlockedMe: " + eachMentionedUser.getHasBlockedMe()); + messages.forEach((message) => { + message.getMentionedUsers().forEach((user) => { + console.log("User:", user.getName()); + console.log("Blocked by me:", user.getBlockedByMe()); + console.log("Has blocked me:", user.getHasBlockedMe()); }); }); }, - (error) => { - console.log("Message fetching failed with error:", error); - } + (error) => console.log("Failed to fetch:", error) ); ``` - + +```typescript +const GUID: string = "GUID"; +const limit: number = 30; - -```javascript -let GUID = "GUID"; -let limit = 30; - -var messagesRequest = new CometChat.MessagesRequestBuilder() +const messagesRequest: CometChat.MessagesRequest = new CometChat.MessagesRequestBuilder() .setGUID(GUID) .setLimit(limit) .mentionsWithBlockedInfo(true) .build(); messagesRequest.fetchPrevious().then( - (messages) => { - messages.forEach((eachMessage) => { - eachMessage.getMentionedUsers().forEach((eachMentionedUser) => { - console.log("blockedByMe: " + eachMentionedUser.getBlockedByMe()); - console.log("hasBlockedMe: " + eachMentionedUser.getHasBlockedMe()); + (messages: CometChat.BaseMessage[]) => { + messages.forEach((message) => { + message.getMentionedUsers().forEach((user: CometChat.User) => { + console.log("User:", user.getName()); + console.log("Blocked by me:", user.getBlockedByMe()); + console.log("Has blocked me:", user.getHasBlockedMe()); }); }); }, - (error) => { - console.log("Message fetching failed with error:", error); - } + (error: CometChat.CometChatException) => console.log("Failed to fetch:", error) ); ``` - + +```javascript +const fetchMessagesWithBlockedInfo = async () => { + try { + const GUID = "GUID"; + const limit = 30; - -```typescript -let UID: string = "UID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() - .setUID(UID) + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(GUID) .setLimit(limit) .mentionsWithBlockedInfo(true) .build(); -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - messages.forEach((eachMessage: CometChat.BaseMessage) => { - eachMessage - .getMentionedUsers() - .forEach((eachMentionedUser: CometChat.User) => { - console.log("blockedByMe: " + eachMentionedUser.getBlockedByMe()); - console.log("hasBlockedMe: " + eachMentionedUser.getHasBlockedMe()); - }); + const messages = await messagesRequest.fetchPrevious(); + messages.forEach((message) => { + message.getMentionedUsers().forEach((user) => { + console.log("User:", user.getName()); + console.log("Blocked by me:", user.getBlockedByMe()); + console.log("Has blocked me:", user.getHasBlockedMe()); + }); }); - }, - (error) => { - console.log("Message fetching failed with error:", error); + } catch (error) { + console.log("Failed to fetch:", error); } -); +}; ``` - + - -```typescript -let GUID: string = "GUID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setLimit(limit) - .mentionsWithBlockedInfo(true) +--- + +## Building a Mention Picker + +Here's a practical implementation for mention suggestions: + +```javascript +class MentionHelper { + constructor(groupId) { + this.groupId = groupId; + this.members = []; + } + + // Load group members for mention suggestions + async loadMembers() { + const request = new CometChat.GroupMembersRequestBuilder(this.groupId) + .setLimit(100) .build(); -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - messages.forEach((eachMessage: CometChat.BaseMessage) => { - eachMessage - .getMentionedUsers() - .forEach((eachMentionedUser: CometChat.User) => { - console.log("blockedByMe: " + eachMentionedUser.getBlockedByMe()); - console.log("hasBlockedMe: " + eachMentionedUser.getHasBlockedMe()); - }); + this.members = await request.fetchNext(); + return this.members; + } + + // Filter members based on search query (when user types @...) + searchMembers(query) { + const lowerQuery = query.toLowerCase(); + return this.members.filter((member) => + member.getName().toLowerCase().includes(lowerQuery) + ); + } + + // Convert user to mention format + formatMention(user) { + return `<@uid:${user.getUid()}>`; + } + + // Build message text with mentions + buildMessageWithMentions(text, selectedUsers) { + let messageText = text; + + selectedUsers.forEach((user) => { + const displayPattern = new RegExp(`@${user.getName()}`, "g"); + messageText = messageText.replace(displayPattern, this.formatMention(user)); }); - }, - (error) => { - console.log("Message fetching failed with error:", error); + + return messageText; } +} + +// Usage +const mentionHelper = new MentionHelper("group-123"); +await mentionHelper.loadMembers(); + +// When user types "@jo" +const suggestions = mentionHelper.searchMembers("jo"); + +// When sending message +const messageText = mentionHelper.buildMessageWithMentions( + "Hey @John, check this out!", + [selectedUser] ); +// Result: "Hey <@uid:john123>, check this out!" ``` - +--- - +## Display Mentions in UI + +Convert mention format to readable display: + +```javascript +function renderMessageWithMentions(message) { + let text = message.getText(); + const mentionedUsers = message.getMentionedUsers(); + + mentionedUsers.forEach((user) => { + const mentionPattern = `<@uid:${user.getUid()}>`; + const mentionElement = `@${user.getName()}`; + text = text.replace(mentionPattern, mentionElement); + }); + + return text; +} + +// Input: "Hey <@uid:john123>, check this!" +// Output: "Hey @John, check this!" +``` -## Get Users Mentioned In a Particular Message + +**Styling Tip**: Add CSS to highlight mentions: +```css +.mention { + color: #0066cc; + background-color: #e6f2ff; + padding: 2px 4px; + border-radius: 4px; + cursor: pointer; +} +``` + + +--- -To retrieve the list of users mentioned in the particular message, you can use the message.getMentionedUsers() method. This method will return an array containing the mentioned users, or an empty array if no users were mentioned in the message. +## Complete Implementation Example ```javascript -message.getMentionedUsers() +class MentionManager { + constructor(groupId) { + this.groupId = groupId; + this.members = []; + this.showingSuggestions = false; + this.searchQuery = ""; + } + + async initialize() { + await this.loadMembers(); + } + + async loadMembers() { + const request = new CometChat.GroupMembersRequestBuilder(this.groupId) + .setLimit(100) + .build(); + this.members = await request.fetchNext(); + } + + // Call this on every keystroke in the input + handleInput(text, cursorPosition) { + const beforeCursor = text.substring(0, cursorPosition); + const mentionMatch = beforeCursor.match(/@(\w*)$/); + + if (mentionMatch) { + this.showingSuggestions = true; + this.searchQuery = mentionMatch[1]; + return this.getSuggestions(); + } else { + this.showingSuggestions = false; + return []; + } + } + + getSuggestions() { + if (!this.searchQuery) return this.members.slice(0, 5); + + const query = this.searchQuery.toLowerCase(); + return this.members + .filter((m) => m.getName().toLowerCase().includes(query)) + .slice(0, 5); + } + + // Call when user selects a suggestion + insertMention(text, cursorPosition, user) { + const beforeCursor = text.substring(0, cursorPosition); + const afterCursor = text.substring(cursorPosition); + + // Remove the @query part + const newBefore = beforeCursor.replace(/@\w*$/, `@${user.getName()} `); + + this.showingSuggestions = false; + return newBefore + afterCursor; + } + + // Call before sending to convert display names to mention format + prepareForSend(text) { + let prepared = text; + + this.members.forEach((member) => { + const displayPattern = new RegExp(`@${member.getName()}\\b`, "g"); + prepared = prepared.replace(displayPattern, `<@uid:${member.getUid()}>`); + }); + + return prepared; + } + + // Call when displaying received messages + formatForDisplay(message) { + let text = message.getText(); + const mentionedUsers = message.getMentionedUsers(); + + mentionedUsers.forEach((user) => { + const pattern = `<@uid:${user.getUid()}>`; + const display = `@${user.getName()}`; + text = text.replaceAll(pattern, display); + }); + + return text; + } +} ``` + +--- + +## Next Steps + + + + Create organized conversation threads + + + Add emoji reactions to messages + + diff --git a/sdk/javascript/message-structure-and-hierarchy.mdx b/sdk/javascript/message-structure-and-hierarchy.mdx index 797cb91d..f4d5c521 100644 --- a/sdk/javascript/message-structure-and-hierarchy.mdx +++ b/sdk/javascript/message-structure-and-hierarchy.mdx @@ -1,86 +1,415 @@ --- -title: "Message" -sidebarTitle: "Message Structure And Hierarchy" +title: "Message Structure & Hierarchy" +sidebarTitle: "Message Structure" +description: "Understanding message categories, types, and properties in CometChat" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Message categories +CometChat.CATEGORY_MESSAGE // text, image, video, audio, file +CometChat.CATEGORY_CUSTOM // custom types you define +CometChat.CATEGORY_ACTION // system events (join, leave, kick) +CometChat.CATEGORY_CALL // audio, video calls +CometChat.CATEGORY_INTERACTIVE // form, card, customInteractive -The below diagram helps you better understand the various message categories and types that a CometChat message can belong to. +// Check message type +const category = message.getCategory(); +const type = message.getType(); + +if (category === CometChat.CATEGORY_MESSAGE) { + if (type === CometChat.MESSAGE_TYPE.TEXT) { + console.log(message.getText()); + } +} +``` + + +Every CometChat message belongs to a category and type. Understanding this hierarchy helps you handle messages correctly in your application. + +## Message Hierarchy -As you can see in the above diagram, every message belongs to a particular category. A message can belong to either one of the 4 categories +## Categories Overview -1. Message -2. Custom -3. Action -4. Call +| Category | Description | Types | +|----------|-------------|-------| +| `message` | Standard chat messages | text, image, video, audio, file | +| `custom` | Developer-defined messages | Any custom type | +| `interactive` | Interactive UI elements | form, card, customInteractive | +| `action` | System-generated events | groupMember, message | +| `call` | Call-related messages | audio, video | -Each category can be further be classified into types. +--- -A message belonging to the category `message` can be classified into either 1 of the below types: +## Message Category -1. text - A plain text message -2. image- An image message -3. video- A video message -4. audio- An audio message -5. file- A file message +Standard messages for text and media content. -## Custom +| Type | Description | Use Case | +|------|-------------|----------| +| `text` | Plain text message | Chat messages | +| `image` | Image attachment | Photo sharing | +| `video` | Video attachment | Video sharing | +| `audio` | Audio attachment | Voice messages | +| `file` | File attachment | Document sharing | -In the case of messages that belong to the `custom` category, there are no predefined types. Custom messages can be used by developers to send messages that do not fit in the default category and types provided by CometChat. For messages with the category `custom`, the developers can set their own type to uniquely identify the custom message. A very good example of a custom message would be the sharing of location co-ordinates. In this case, the developer can decide to use the custom message with type set to `location`. + + +```javascript +// Check message category and type +if (message.getCategory() === CometChat.CATEGORY_MESSAGE) { + switch (message.getType()) { + case CometChat.MESSAGE_TYPE.TEXT: + console.log("Text:", message.getText()); + break; + case CometChat.MESSAGE_TYPE.IMAGE: + case CometChat.MESSAGE_TYPE.VIDEO: + case CometChat.MESSAGE_TYPE.AUDIO: + case CometChat.MESSAGE_TYPE.FILE: + console.log("Media:", message.getAttachment()); + break; + } +} +``` + + +```typescript +// Check message category and type +if (message.getCategory() === CometChat.CATEGORY_MESSAGE) { + switch (message.getType()) { + case CometChat.MESSAGE_TYPE.TEXT: + const textMsg = message as CometChat.TextMessage; + console.log("Text:", textMsg.getText()); + break; + case CometChat.MESSAGE_TYPE.IMAGE: + case CometChat.MESSAGE_TYPE.VIDEO: + case CometChat.MESSAGE_TYPE.AUDIO: + case CometChat.MESSAGE_TYPE.FILE: + const mediaMsg = message as CometChat.MediaMessage; + console.log("Media:", mediaMsg.getAttachment()); + break; + } +} +``` + + -## Interactive +--- -An InteractiveMessage is a specialized object that encapsulates an interactive unit within a chat message, such as an embedded form that users can fill out directly within the chat interface. Messages belonging to the interactive category can further be classified into one of the below types: +## Custom Category -1. form- for interactive form -2. card- for interactive card -3. customInteractive- for custom interaction messages +Custom messages allow you to send any data structure that doesn't fit standard message types. - + +Custom messages have no predefined types. You define your own type string to identify different custom message formats. + + +**Common Use Cases:** +- Location sharing (`type: "location"`) +- Polls (`type: "poll"`) +- Product cards (`type: "product"`) +- Meeting invites (`type: "meeting"`) + + + +```javascript +// Send custom location message +const customMessage = new CometChat.CustomMessage( + receiverID, + CometChat.RECEIVER_TYPE.USER, + "location", // Your custom type + { + latitude: 37.7749, + longitude: -122.4194, + address: "San Francisco, CA" + } +); + +await CometChat.sendCustomMessage(customMessage); + +// Handle received custom message +if (message.getCategory() === CometChat.CATEGORY_CUSTOM) { + const type = message.getType(); + const data = message.getCustomData(); + + if (type === "location") { + console.log("Location:", data.latitude, data.longitude); + } +} +``` + + +```typescript +// Send custom location message +const customMessage = new CometChat.CustomMessage( + receiverID, + CometChat.RECEIVER_TYPE.USER, + "location", + { + latitude: 37.7749, + longitude: -122.4194, + address: "San Francisco, CA" + } +); + +await CometChat.sendCustomMessage(customMessage); + +// Handle received custom message +if (message.getCategory() === CometChat.CATEGORY_CUSTOM) { + const customMsg = message as CometChat.CustomMessage; + const type = customMsg.getType(); + const data = customMsg.getCustomData() as { latitude: number; longitude: number }; + + if (type === "location") { + console.log("Location:", data.latitude, data.longitude); + } +} +``` + + + +--- -to know about Interactive messages please [click here](/sdk/javascript/interactive-messages) +## Interactive Category +Interactive messages contain UI elements users can interact with directly in the chat. + +| Type | Description | Use Case | +|------|-------------|----------| +| `form` | Embedded form | Surveys, data collection | +| `card` | Interactive card | Product displays, previews | +| `customInteractive` | Custom interactive element | Any custom UI | + + +For detailed implementation, see [Interactive Messages](/sdk/javascript/interactive-messages). -## Action +--- + +## Action Category + +System-generated messages for group and message events. + +### Group Member Actions -Action messages are system-generated messages. Messages belonging to the `action` category can further be classified into one of the below types: +| Action | Description | +|--------|-------------| +| `joined` | Member joined the group | +| `left` | Member left the group | +| `kicked` | Member was kicked | +| `banned` | Member was banned | +| `unbanned` | Member was unbanned | +| `added` | Member was added | +| `scopeChanged` | Member scope was changed | -1. groupMember - action performed on a group member. -2. message - action performed on a message. +### Message Actions -Action messages hold another property called `action` which actually determine the action that has been performed For the type `groupMember` the action can be either one of the below: +| Action | Description | +|--------|-------------| +| `edited` | Message was edited | +| `deleted` | Message was deleted | -1. joined - when a group member joins a group -2. left - when a group member leaves a group -3. kicked - when a group member is kicked from the group -4. banned - when a group member is banned from the group -5. unbanned - when a group member is unbanned from the group -6. added - when a user is added to the group -7. scopeChanged - When the scope of a group member is changed. + + +```javascript +// Handle action messages +if (message.getCategory() === CometChat.CATEGORY_ACTION) { + const action = message.getAction(); + const actionBy = message.getActionBy(); + const actionOn = message.getActionOn(); + + switch (action) { + case CometChat.ACTION_TYPE.MEMBER_JOINED: + console.log(`${actionOn.getName()} joined the group`); + break; + case CometChat.ACTION_TYPE.MEMBER_KICKED: + console.log(`${actionOn.getName()} was kicked by ${actionBy.getName()}`); + break; + case CometChat.ACTION_TYPE.MEMBER_SCOPE_CHANGED: + console.log(`${actionOn.getName()} scope changed to ${message.getNewScope()}`); + break; + } +} +``` + + +```typescript +// Handle action messages +if (message.getCategory() === CometChat.CATEGORY_ACTION) { + const actionMsg = message as CometChat.Action; + const action = actionMsg.getAction(); + const actionBy = actionMsg.getActionBy() as CometChat.User; + const actionOn = actionMsg.getActionOn() as CometChat.User; + + switch (action) { + case CometChat.ACTION_TYPE.MEMBER_JOINED: + console.log(`${actionOn.getName()} joined the group`); + break; + case CometChat.ACTION_TYPE.MEMBER_KICKED: + console.log(`${actionOn.getName()} was kicked by ${actionBy.getName()}`); + break; + case CometChat.ACTION_TYPE.MEMBER_SCOPE_CHANGED: + console.log(`${actionOn.getName()} scope changed`); + break; + } +} +``` + + -For the type `message`, the action can be either one of the below: +--- + +## Call Category + +Call-related messages with status tracking. + +| Type | Description | +|------|-------------| +| `audio` | Voice call | +| `video` | Video call | -1. edited - when a message is edited. -2. deleted - when a message is deleted. +### Call Status Values -## Call +| Status | Description | +|--------|-------------| +| `initiated` | Call started | +| `ongoing` | Call in progress | +| `canceled` | Caller cancelled | +| `rejected` | Receiver rejected | +| `unanswered` | No answer | +| `busy` | Receiver busy | +| `ended` | Call completed | + + + +```javascript +// Handle call messages +if (message.getCategory() === CometChat.CATEGORY_CALL) { + const callType = message.getType(); // "audio" or "video" + const status = message.getStatus(); + + switch (status) { + case CometChat.CALL_STATUS.INITIATED: + console.log(`${callType} call initiated`); + break; + case CometChat.CALL_STATUS.ONGOING: + console.log("Call in progress"); + break; + case CometChat.CALL_STATUS.ENDED: + console.log("Call ended"); + break; + case CometChat.CALL_STATUS.CANCELLED: + console.log("Call cancelled"); + break; + case CometChat.CALL_STATUS.REJECTED: + console.log("Call rejected"); + break; + case CometChat.CALL_STATUS.UNANSWERED: + console.log("Call unanswered"); + break; + case CometChat.CALL_STATUS.BUSY: + console.log("User busy"); + break; + } +} +``` + + +```typescript +// Handle call messages +if (message.getCategory() === CometChat.CATEGORY_CALL) { + const callMsg = message as CometChat.Call; + const callType = callMsg.getType(); + const status = callMsg.getStatus(); + + switch (status) { + case CometChat.CALL_STATUS.INITIATED: + console.log(`${callType} call initiated`); + break; + case CometChat.CALL_STATUS.ONGOING: + console.log("Call in progress"); + break; + case CometChat.CALL_STATUS.ENDED: + console.log("Call ended"); + break; + // ... handle other statuses + } +} +``` + + + +--- -Messages with the category `call` are Calling related messages. These can belong to either one of the 2 types +## Complete Message Handler -1. audio -2. video + + +```javascript +function handleMessage(message) { + const category = message.getCategory(); + + switch (category) { + case CometChat.CATEGORY_MESSAGE: + handleStandardMessage(message); + break; + case CometChat.CATEGORY_CUSTOM: + handleCustomMessage(message); + break; + case CometChat.CATEGORY_ACTION: + handleActionMessage(message); + break; + case CometChat.CATEGORY_CALL: + handleCallMessage(message); + break; + case CometChat.CATEGORY_INTERACTIVE: + handleInteractiveMessage(message); + break; + } +} +``` + + +```typescript +function handleMessage(message: CometChat.BaseMessage): void { + const category = message.getCategory(); + + switch (category) { + case CometChat.CATEGORY_MESSAGE: + handleStandardMessage(message as CometChat.TextMessage | CometChat.MediaMessage); + break; + case CometChat.CATEGORY_CUSTOM: + handleCustomMessage(message as CometChat.CustomMessage); + break; + case CometChat.CATEGORY_ACTION: + handleActionMessage(message as CometChat.Action); + break; + case CometChat.CATEGORY_CALL: + handleCallMessage(message as CometChat.Call); + break; + case CometChat.CATEGORY_INTERACTIVE: + handleInteractiveMessage(message as CometChat.InteractiveMessage); + break; + } +} +``` + + -The call messages have a property called status that helps you figure out the status of the call. The status can be either one of the below values: +## Next Steps -1. initiated - when a is initiated to a user/group -2. ongoing - when the receiver of the call has accepted the call -3. canceled - when the call has been canceled by the initiator of the call -4. rejected - when the call has been rejected by the receiver of the call -5. unanswered - when the call was not answered by the receiver. -6. busy - when the receiver of the call was busy on another call. -7. ended - when the call was successfully completed and ended by either the initiator or receiver. + + + Learn to send different message types + + + Build interactive chat experiences + + diff --git a/sdk/javascript/messaging-overview.mdx b/sdk/javascript/messaging-overview.mdx index 5a8902b4..ded5cb2a 100644 --- a/sdk/javascript/messaging-overview.mdx +++ b/sdk/javascript/messaging-overview.mdx @@ -1,12 +1,250 @@ --- title: "Messaging" sidebarTitle: "Overview" +description: "Send, receive, and manage messages in your chat application" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Send text message +const textMessage = new CometChat.TextMessage( + "receiver_uid", + "Hello!", + CometChat.RECEIVER_TYPE.USER // or GROUP +); +await CometChat.sendMessage(textMessage); -Messaging is one of the core features of CometChat. We've thoughtfully created methods to help you send, receive and fetch message history. +// Send media message +const mediaMessage = new CometChat.MediaMessage( + "receiver_uid", + file, + CometChat.MESSAGE_TYPE.IMAGE, // IMAGE, VIDEO, AUDIO, FILE + CometChat.RECEIVER_TYPE.USER +); +await CometChat.sendMediaMessage(mediaMessage); -At the minimum, you must add code for [sending messages](/sdk/javascript/send-message) and [receiving messages](/sdk/javascript/receive-message). +// Fetch message history +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID("user_uid") // or .setGUID("group_guid") + .setLimit(30) + .build(); +const messages = await messagesRequest.fetchPrevious(); -Once you've implemented that, you can proceed to more advanced features like [typing indicators](/sdk/javascript/typing-indicators) and [delivery & read receipts](/sdk/javascript/delivery-read-receipts). +// Listen for messages +CometChat.addMessageListener("LISTENER_ID", new CometChat.MessageListener({ + onTextMessageReceived: (msg) => console.log("Text:", msg.getText()), + onMediaMessageReceived: (msg) => console.log("Media:", msg.getAttachment()), + onTypingStarted: (indicator) => console.log("Typing..."), + onMessagesRead: (receipt) => console.log("Read:", receipt.getMessageId()) +})); + +// Edit/Delete +await CometChat.editMessage(editedMessage); +await CometChat.deleteMessage(messageId); +``` + + +Messaging is the core of CometChat. This section covers everything you need to build a complete messaging experience—from sending your first message to implementing advanced features like reactions and threaded conversations. + + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + + +## Getting Started + +At minimum, implement these two features: + + + + Send text, media, and custom messages to users and groups + + + Handle real-time messages and fetch message history + + + +## Message Types + +CometChat supports multiple message types: + +| Type | Description | Use Case | +|------|-------------|----------| +| **Text** | Plain text messages | Standard chat messages | +| **Media** | Images, videos, audio, files | Sharing photos, documents, voice notes | +| **Custom** | Developer-defined JSON payload | Location sharing, polls, custom cards | +| **Interactive** | Forms, cards, buttons | Surveys, bookings, actionable messages | + +```javascript +// Quick example: Send a text message +const textMessage = new CometChat.TextMessage( + receiverID, + "Hello!", + CometChat.RECEIVER_TYPE.USER +); + +CometChat.sendMessage(textMessage).then( + (message) => console.log("Sent:", message), + (error) => console.log("Error:", error) +); +``` + +--- + +## Core Features + + + + Fetch recent chats and build your conversation list + + + Load previous messages with pagination + + + Allow users to edit sent messages + + + Remove messages from conversations + + + +--- + +## Real-Time Features + +Keep your chat experience live and engaging: + + + + Show when users are typing + + + Track message delivery and read status + + + Add emoji reactions to messages + + + Send temporary messages that aren't stored + + + +--- + +## Advanced Features + + + + Create message threads for organized discussions + + + @mention users in conversations + + + Send forms, cards, and actionable content + + + Filter messages by type, category, or custom criteria + + + +--- + +## Conversation Management + + + + Clear conversation history + + + Report inappropriate content + + + +--- + +## Message Listener + +To receive real-time messages, register a `MessageListener`: + +```javascript +const listenerID = "UNIQUE_LISTENER_ID"; + +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: (textMessage) => { + console.log("Text message received:", textMessage); + }, + onMediaMessageReceived: (mediaMessage) => { + console.log("Media message received:", mediaMessage); + }, + onCustomMessageReceived: (customMessage) => { + console.log("Custom message received:", customMessage); + }, + onTypingStarted: (typingIndicator) => { + console.log("Typing started:", typingIndicator); + }, + onTypingEnded: (typingIndicator) => { + console.log("Typing ended:", typingIndicator); + }, + onMessagesDelivered: (messageReceipt) => { + console.log("Message delivered:", messageReceipt); + }, + onMessagesRead: (messageReceipt) => { + console.log("Message read:", messageReceipt); + }, + onMessageEdited: (message) => { + console.log("Message edited:", message); + }, + onMessageDeleted: (message) => { + console.log("Message deleted:", message); + }, + onInteractiveMessageReceived: (message) => { + console.log("Interactive message received:", message); + }, + }) +); + +// Remove listener when done +CometChat.removeMessageListener(listenerID); +``` + +See [All Real-Time Listeners](/sdk/javascript/all-real-time-listeners) for the complete reference. + +--- + +## Quick Reference + +| Task | Method | +|------|--------| +| Send text message | `CometChat.sendMessage(textMessage)` | +| Send media message | `CometChat.sendMediaMessage(mediaMessage)` | +| Send custom message | `CometChat.sendCustomMessage(customMessage)` | +| Fetch messages | `messagesRequest.fetchPrevious()` | +| Edit message | `CometChat.editMessage(message)` | +| Delete message | `CometChat.deleteMessage(messageId)` | +| Mark as read | `CometChat.markAsRead(message)` | +| Start typing | `CometChat.startTyping(typingIndicator)` | +| Get conversations | `conversationsRequest.fetchNext()` | + +--- + +## Next Steps + + + + Learn to send [text, media, and custom messages](/sdk/javascript/send-message) + + + Set up [real-time listeners and fetch history](/sdk/javascript/receive-message) + + + [Retrieve conversations](/sdk/javascript/retrieve-conversations) for your chat UI + + + Implement [typing indicators](/sdk/javascript/typing-indicators) and [read receipts](/sdk/javascript/delivery-read-receipts) + + diff --git a/sdk/javascript/overview.mdx b/sdk/javascript/overview.mdx index f7edcaaa..e86b4db6 100644 --- a/sdk/javascript/overview.mdx +++ b/sdk/javascript/overview.mdx @@ -1,502 +1,495 @@ --- -title: "Overview" +title: "JavaScript SDK" +sidebarTitle: "Overview" +description: "Add real-time chat and calling to your JavaScript application" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** - -This guide demonstrates how to add chat to a JavaScript application using CometChat. Before you begin, we strongly recommend you read the [Key Concepts](/sdk/javascript/key-concepts) guide. - -#### I want to integrate with my app - -1. [Get your application keys](overview#get-your-application-keys) -2. [Add the CometChat dependency](overview#add-the-cometchat-dependency) -3. [Initialize CometChat](overview#initialize-cometchat) -4. [Register and Login your user](overview#register-and-login-your-user) -5. [Integrate our UI Kits](overview#integrate-our-ui-kits) -6. [Integrate our Chat Widget](overview#integrate-our-chat-widget) - -#### I want to explore a sample app (includes UI) - -Open the app folder in your favorite code editor and follow the steps mentioned in the `README.md` file. - -[React Sample App](https://github.com/cometchat-pro/javascript-react-chat-app) - -[Angular Sample App](https://github.com/cometchat-pro/javascript-angular-chat-app) - -[Vue Sample App](https://github.com/cometchat-pro/javascript-vue-chat-app) - -### Get your Application Keys - -[Signup for CometChat](https://app.cometchat.com) and then: - -1. Create a new app -2. Head over to the **API & Auth Keys** section and note the **Auth Key**, **App ID** & **Region** - -## Add the CometChat Dependency - -### NPM - - - -```js - npm install @cometchat/chat-sdk-javascript ``` - - - - - -Then, import the `CometChat` object wherever you want to use CometChat. - - - -```js - import { CometChat } from "@cometchat/chat-sdk-javascript"; +Package: @cometchat/chat-sdk-javascript +Init: CometChat.init(appID, appSettings) +Login: CometChat.login(uid, authKey) or CometChat.login(authToken) +Send: CometChat.sendMessage(textMessage) +Receive: CometChat.addMessageListener(id, listener) +Logout: CometChat.logout() ``` + - - - - -### HTML (via CDN) +Build powerful chat experiences in your web applications using CometChat's JavaScript SDK. Whether you're building with React, Angular, Vue, or vanilla JavaScript, this SDK provides the foundation for real-time messaging, voice, and video calling. -Include the CometChat JavaScript library in your HTML code - - - -```html - -``` - - + +**Choose Your Integration Path** - +CometChat offers multiple ways to add chat to your application: -### Server Side Rendering (SSR) Compatibility +| Approach | Best For | Effort | +|----------|----------|--------| +| [Widget Builder](/widget/html/overview) | Quick embed, minimal coding | No Code | +| [UI Kit Builder](/chat-builder/react/overview) | Visual customization with code export | Low Code | +| [UI Kits](/ui-kit/react/overview) | Pre-built components, full control | Code | +| **SDK** (this guide) | Complete flexibility, custom UI | Code | +| [REST API](https://api-explorer.cometchat.com) | Server-side integration | Code | + -You can use CometChat with SSR frameworks such as [Next.js](https://nextjs.org/) or [NuxtJS](https://nuxtjs.org/) by importing it dynamically on the client side. +## Quick Start + +Get up and running in 4 steps: + + + + [Sign up for CometChat](https://app.cometchat.com) and create a new app. Note your **App ID**, **Region**, and **Auth Key** from the **API & Auth Keys** section. + + + + + ```bash + npm install @cometchat/chat-sdk-javascript + ``` + + + ```bash + yarn add @cometchat/chat-sdk-javascript + ``` + + + ```html + + ``` + + + + + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; + + const appID = "YOUR_APP_ID"; + const region = "YOUR_REGION"; + + const appSetting = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .build(); -#### Next.js + CometChat.init(appID, appSetting).then( + () => console.log("CometChat initialized successfully"), + (error) => console.log("Initialization failed:", error) + ); + ``` + + + `CometChat.init()` must be called before any other SDK method. Call it once at app startup — calling `login()`, `sendMessage()`, or registering listeners before `init()` will fail. + + + + ```javascript + const UID = "cometchat-uid-1"; + const authKey = "YOUR_AUTH_KEY"; + + CometChat.login(UID, authKey).then( + (user) => console.log("Login successful:", user), + (error) => console.log("Login failed:", error) + ); + ``` + + We provide 5 test users: `cometchat-uid-1` through `cometchat-uid-5` + + + -You need to import the CometChat SDK dynamically in the `useEffect` React Hook or `componentDidMount()` lifecycle method. + +**Using Next.js, Nuxt, or another SSR framework?** CometChat requires browser APIs and won't work during server-side rendering. Use dynamic imports and client-only directives. See the [Framework Integration](/sdk/javascript/setup-sdk#framework-integration) section for complete setup guides for React, Next.js, Vue, Nuxt, and Angular. + - - -```javascript -import React from "react"; -import Chat from "./Chat"; +## What's Next? + + + + Detailed configuration options including SSR support for Next.js and Nuxt. + + + Understand users, groups, messages, and how CometChat works. + + + Send text, media, and custom messages to users and groups. + + + Handle real-time messages and fetch message history. + + -export default function Home() { - let [libraryImported, setLibraryImported] = React.useState(false); +--- - React.useEffect(() => { - window.CometChat = require("@cometchat/chat-sdk-javascript").CometChat; - setLibraryImported(true); - }); +## Core Features + +Essential messaging capabilities built into the SDK: + +| Feature | Description | Learn More | +|---------|-------------|------------| +| **Instant Messaging** | Real-time one-on-one and group chat | [Send Message](/sdk/javascript/send-message) | +| **Media Sharing** | Share images, videos, documents, and files | [Media Messages](/sdk/javascript/send-message#media-message) | +| **Read Receipts** | Know when messages are delivered and read | [Delivery & Read Receipts](/sdk/javascript/delivery-read-receipts) | +| **Mark as Unread** | Mark messages as unread to revisit later | [Mark as Unread](/sdk/javascript/delivery-read-receipts#mark-messages-as-unread) | +| **Typing Indicators** | Show when users are typing | [Typing Indicators](/sdk/javascript/typing-indicators) | +| **User Presence** | Real-time online/offline status | [User Presence](/sdk/javascript/user-presence) | +| **Reactions** | React to messages with emojis | [Reactions](/sdk/javascript/reactions) | +| **Mentions** | @mention users in conversations | [Mentions](/sdk/javascript/mentions) | +| **Threaded Conversations** | Create message threads for organized discussions | [Threaded Messages](/sdk/javascript/threaded-messages) | +| **Quoted Replies** | Reply to specific messages with context | [Quoted Messages](/sdk/javascript/send-message#set-quoted-message-id) | +| **Group Chats** | Create and manage group conversations | [Groups](/sdk/javascript/groups-overview) | +| **Report Message** | Allow users to report inappropriate content | [Flag Message](/sdk/javascript/flag-message) | +| **Conversation & Advanced Search** | Search messages by text, file name, mentions, or mime type | [Search Messages](/sdk/javascript/receive-message#search-messages) | - return libraryImported ? :

Loading....

; -} -``` +--- -
+## Extensions + +Enhance your chat with these optional features. Enable them from the [CometChat Dashboard](https://app.cometchat.com) under **Extensions**. + + + + | Extension | Description | + |-----------|-------------| + | **Message Shortcuts** | Quick shortcuts for common messages | + | **Avatars** | Auto-generated avatars for users | + | **Link Preview** | Rich previews for shared URLs | + | **Rich Media Preview** | Enhanced previews for media content | + | **Thumbnail Generation** | Auto-generate thumbnails for images and videos | + | **Pin Message** | Pin important messages in conversations | + | **Save Messages** | Save messages for later reference | + | **TinyURL** | Shorten long URLs automatically | + | **Bitly** | URL shortening via Bitly integration | + | **Voice Transcription** | Transcribe voice messages to text | + + + + | Extension | Description | + |-----------|-------------| + | **Giphy** | Send animated GIFs | + | **Tenor** | Alternative GIF integration | + | **Message Translation** | Translate messages in real-time | + | **Polls** | Create polls for group decisions | + | **Reminders** | Set reminders for messages | + | **Stickers** | Send stickers in conversations | + | **Stipop Stickers** | Premium sticker packs via Stipop | + | **Emojis** | Enhanced emoji support | + + + + | Extension | Description | + |-----------|-------------| + | **Collaborative Document** | Create and share documents in real-time | + | **Collaborative Whiteboard** | Shared whiteboard for visual collaboration | + + + + | Extension | Description | + |-----------|-------------| + | **Disappearing Messages** | Messages that auto-delete after a set time | + | **End-to-End Encryption** | Secure message encryption | + + + + | Extension | Description | + |-----------|-------------| + | **Chatwoot** | Connect with Chatwoot for support workflows | + | **Intercom** | Integrate with Intercom for customer messaging | + + + + | Feature | Description | + |---------|-------------| + | **Conversation Starter** | AI-suggested conversation starters | + | **Smart Replies** | AI-generated reply suggestions | + | **Conversation Summary** | AI-generated summaries of conversations | + + [Learn more about AI User Copilot →](/sdk/javascript/ai-user-copilot-overview) + + - -```javascript -import React from 'react'; -import Chat from './Chat'; +--- -export default class Home extends React.Component { +## Voice & Video Calling -constructor(props) { - super(props); - this.state = { - libraryImported: false - }; -} +Add real-time calling capabilities to your app: -componentDidMount(){ - CometChat = require("@cometchat/chat-sdk-javascript").CometChat; - this.setState({libraryImported: true}); -} + + + Complete calling experience with incoming/outgoing UI, accept/reject, and notifications. + + + Start call sessions directly without the ringing flow. + + + Record calls for playback or compliance. + + + Blur or replace backgrounds during video calls. + + -return( - this.state.libraryImported ? :

Loading....

-) +[Explore all Calling features →](/sdk/javascript/calling-overview) -} -``` +--- -
+## AI Features - -```javascript -import React, { Component } from "react"; +Leverage AI to enhance your chat experience: -import { COMETCHAT_CONSTANTS } from "./CONSTS"; + + + Automatically moderate content for safety + + + Build AI-powered chat agents + + + Create intelligent chatbot experiences + + -export default class Chat extends Component { - constructor(props) { - super(props); - this.state = { - user: undefined, - }; - } +--- - componentDidMount() { - this.init(); - } +## Framework Guides - init() { - CometChat.init( - COMETCHAT_CONSTANTS.APP_ID, - new CometChat.AppSettingsBuilder() - .setRegion(COMETCHAT_CONSTANTS.REGION) - .subscribePresenceForAllUsers() - .build() - ).then( - () => { - this.login(); - }, - (error) => { - console.log("Init failed with exception:", error); - } - ); - } + + + Integration guide for React applications + + + Integration guide for Angular applications + + + Integration guide for Vue.js applications + + - login() { - let UID = "UID"; - CometChat.login(UID, COMETCHAT_CONSTANTS.AUTH_KEY).then( - (user) => { - this.setState({ user }); - }, - (error) => { - console.log("Login failed with exception:", error); - } - ); - } +## Sample Apps - render() { - return this.state.user ? ( -
User logged in
- ) : ( -
User not logged in
- ); - } -} -``` +Explore complete implementations with UI: -
+| Framework | Repository | +|-----------|------------| +| React | [javascript-react-chat-app](https://github.com/cometchat-pro/javascript-react-chat-app) | +| Angular | [javascript-angular-chat-app](https://github.com/cometchat-pro/javascript-angular-chat-app) | +| Vue | [javascript-vue-chat-app](https://github.com/cometchat-pro/javascript-vue-chat-app) | - -```javascript -export const COMETCHAT_CONSTANTS = { - APP_ID: "APP_ID", - REGION: "REGION", - AUTH_KEY: "AUTH_KEY", -}; -``` +--- - +## Need Pre-Built UI? -
+If you prefer ready-to-use components instead of building from scratch: -#### NuxtJS + + + Production-ready React components for chat and calling + + + Embeddable chat widget for any website + + -You need to import the CometChat SDK dynamically in the `mounted` lifecycle hook. +--- - - -```javascript - - - -``` +## Complete Working Example - +Here's a production-ready example that initializes CometChat, logs in, sends a message, and listens for responses: - ```javascript - - - -``` - - - - -```javascript -module.exports = { - APP_ID: "APP_ID", - REGION: "REGION", - AUTH_KEY: "AUTH_KEY", -}; -``` - - - - - -## Initialize CometChat - -The `init()` method initializes the settings required for CometChat. The `init()` method takes the below parameters: - -1. appID - Your CometChat App ID -2. appSettings - An object of the AppSettings class can be created using the AppSettingsBuilder class. The region field is mandatory and can be set using the `setRegion()` method. - -The `AppSettings` class allows you to configure the following settings: - -* **Region**: The region where your app was created. -* [Presence Subscription](/sdk/javascript/user-presence): Represents the subscription type for user presence (real-time online/offline status) -* **autoEstablishSocketConnection(boolean value)**: This property takes a boolean value which when set to `true` informs the SDK to manage the web-socket connection internally. If set to `false`, it informs the SDK that the web-socket connection will be managed manually. The default value for this parameter is true. For more information on this, please check the [Managing Web-Socket connections manually](/sdk/javascript/managing-web-sockets-connections-manually) section. The default value for this property is **true.** -* **overrideAdminHost(adminHost: string)**: This method takes the admin URL as input and uses this admin URL instead of the default admin URL. This can be used in case of dedicated deployment of CometChat. -* **overrideClientHost(clientHost: string)**: This method takes the client URL as input and uses this client URL instead of the default client URL. This can be used in case of dedicated deployment of CometChat. -* **setStorageMode(storageMode)**: This method allows you to configure how CometChat stores data locally. The storageMode parameter can be set to `CometChat.StorageMode.SESSION` to use session storage, which persists data only for the current browser session, or other available storage modes for different persistence behaviors. - -You need to call `init()` before calling any other method from CometChat. We suggest you call the `init()` method on app startup, preferably in the `index.js` file. - - - -```js -let appID = "APP_ID"; -let region = "APP_REGION"; -let appSetting = new CometChat.AppSettingsBuilder() - .subscribePresenceForAllUsers() - .setRegion(region) - .autoEstablishSocketConnection(true) - .setStorageMode(CometChat.StorageMode.SESSION) - .build(); -CometChat.init(appID, appSetting).then( - () => { - console.log("Initialization completed successfully"); - }, - (error) => { - console.log("Initialization failed with error:", error); + return ChatService.instance; } -); -``` - - - -```typescript -let appID: string = "APP_ID", - region: string = "APP_REGION", - appSetting: CometChat.AppSettings = new CometChat.AppSettingsBuilder() + async initialize() { + const appSettings = new CometChat.AppSettingsBuilder() .subscribePresenceForAllUsers() - .setRegion(region) + .setRegion(REGION) .autoEstablishSocketConnection(true) - .setStorageMode(CometChat.StorageMode.SESSION) .build(); -CometChat.init(appID, appSetting).then( - (initialized: boolean) => { - console.log("Initialization completed successfully", initialized); - }, (error: CometChat.CometChatException) => { - console.log("Initialization failed with error:", error); - } -); -``` - - - - - -Make sure you replace the `APP_ID` with your CometChat **App ID** and `APP_REGION` with your **App Region** in the above code. - -## Register and Login your user - -Once initialization is successful, you will need to create a user. To create users on the fly, you can use the `createUser()` method. This method takes a `User` object and the `Auth Key` as input parameters and returns the created `User` object if the request is successful. - - -```js -let authKey = "AUTH_KEY"; -var UID = "user1"; -var name = "Kevin"; - -var user = new CometChat.User(UID); - -user.setName(name); - -CometChat.createUser(user, authKey).then( - (user) => { - console.log("user created", user); - }, - (error) => { - console.log("error", error); + try { + await CometChat.init(APP_ID, appSettings); + console.log("✓ CometChat initialized"); + return true; + } catch (error) { + console.error("✗ Init failed:", error); + return false; + } } -); -``` - - - -```typescript -let authKey: string = "AUTH_KEY", - UID: string = "user1", - name: string = "Kevin"; - -var user = new CometChat.User(UID); - -user.setName(name); + async login(uid) { + try { + // Check if already logged in + let user = await CometChat.getLoggedinUser(); + if (user) { + console.log("✓ Already logged in:", user.getName()); + return user; + } -CometChat.createUser(user, authKey).then( - (user: CometChat.User) => { - console.log("user created", user); - }, - (error: CometChat.CometChatException) => { - console.log("error", error); + // Login + user = await CometChat.login(uid, AUTH_KEY); + console.log("✓ Logged in:", user.getName()); + return user; + } catch (error) { + console.error("✗ Login failed:", error); + throw error; + } } -); -``` - - - - - -Make sure that `UID` and `name` are specified as these are mandatory fields to create a user. - -Once you have created the user successfully, you will need to log the user into CometChat using the `login()` method. - -We recommend you call the CometChat `login()` method once your user logs into your app. The `login()` method needs to be called only once. - - - -This straightforward authentication method is ideal for proof-of-concept (POC) development or during the early stages of application development. For production environments, however, we strongly recommend using an [Auth Token](/sdk/javascript/authentication-overview#login-using-auth-token) instead of an Auth Key to ensure enhanced security. - - - - -```js -var UID = "cometchat-uid-1"; -var authKey = "AUTH_KEY"; + async sendMessage(receiverUID, text) { + const message = new CometChat.TextMessage( + receiverUID, + text, + CometChat.RECEIVER_TYPE.USER + ); -CometChat.getLoggedinUser().then( - (user) => { - if (!user) { - CometChat.login(UID, authKey).then( - (user) => { - console.log("Login Successful:", { user }); - }, - (error) => { - console.log("Login failed with exception:", { error }); - } - ); + try { + const sent = await CometChat.sendMessage(message); + console.log("✓ Message sent:", sent.getId()); + return sent; + } catch (error) { + console.error("✗ Send failed:", error); + throw error; } - }, - (error) => { - console.log("Some Error Occured", { error }); } -); -``` - - - -```typescript -var UID: string = "cometchat-uid-1", - authKey: string = "AUTH_KEY"; - -CometChat.getLoggedinUser().then( - (user: CometChat.User) => { - if (!user) { - CometChat.login(UID, authKey).then( - (user: CometChat.User) => { - console.log("Login Successful:", { user }); + startListening(onMessage) { + const listenerID = "MAIN_LISTENER"; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: (message) => { + console.log("← Received:", message.getText()); + onMessage?.(message); }, - (error: CometChat.CometChatException) => { - console.log("Login failed with exception:", { error }); + onMediaMessageReceived: (message) => { + console.log("← Media received:", message.getAttachment()); + onMessage?.(message); } - ); - } - }, - (error: CometChat.CometChatException) => { - console.log("Some Error Occured", { error }); - } -); -``` - - - - - -Make sure you replace the `AUTH_KEY` with your CometChat **AuthKey** in the above code. - - -Sample Users - -We have set up 5 users for testing having UIDs: `cometchat-uid-1`, `cometchat-uid-2`, `cometchat-uid-3`, `cometchat-uid-4` and `cometchat-uid-5`. - - - -The `login()` method returns the `User` object on `Promise` resolved containing all the information of the logged-in user. + }) + ); - + return () => CometChat.removeMessageListener(listenerID); + } -UID can be alphanumeric with an underscore and hyphen. Spaces, punctuation and other special characters are not allowed. + async logout() { + try { + await CometChat.logout(); + console.log("✓ Logged out"); + } catch (error) { + console.error("✗ Logout failed:", error); + } + } +} - +// Usage +const chat = ChatService.getInstance(); +await chat.initialize(); +await chat.login("cometchat-uid-1"); +chat.startListening((msg) => console.log("New message:", msg)); +await chat.sendMessage("cometchat-uid-2", "Hello from the SDK!"); +``` -## Integrate our UI Kits +--- -* Please refer to the section to integrate [React UI Kit](/ui-kit/react/overview) into your website. -* Please refer to the section to integrate [Angular UI Kit](/ui-kit/angular/overview) into your website. -* Please refer to the section to integrate [Vue UI Kit](/ui-kit/vue/overview) into your website. +## Common Errors & Solutions + + + + **Cause:** The App ID doesn't match any app in your CometChat account. + + **Solution:** + 1. Go to [CometChat Dashboard](https://app.cometchat.com) + 2. Select your app → API & Auth Keys + 3. Copy the exact App ID (case-sensitive) + 4. Ensure no extra spaces when pasting + + + + **Cause:** Using wrong key type or incorrect key. + + **Solution:** + - Use **Auth Key** (not REST API Key) for client-side login + - Auth Key is for development only; use Auth Tokens in production + - Copy directly from Dashboard → API & Auth Keys + + + + **Cause:** Trying to login with a UID that hasn't been created. + + **Solution:** + - Use test users: `cometchat-uid-1` through `cometchat-uid-5` + - Or create users via REST API before login + - Check for typos in the UID + + + + **Cause:** Calling SDK methods before successful login. + + **Solution:** + ```javascript + // Always check login status first + const user = await CometChat.getLoggedinUser(); + if (!user) { + await CometChat.login(uid, authKey); + } + // Now safe to use other methods + ``` + + + + **Cause:** Message listener not registered or registered before login. + + **Solution:** + 1. Register listeners AFTER successful login + 2. Use unique listener IDs + 3. Check WebSocket connection: `CometChat.getConnectionStatus()` + 4. Ensure `autoEstablishSocketConnection(true)` in app settings + + + + **Cause:** Browser security blocking requests. + + **Solution:** + - CometChat handles CORS automatically + - If using a proxy, ensure it forwards headers correctly + - Check browser console for specific blocked URLs + + -## Integrate our Chat Widget +--- -* Please refer to the section to integrate [Chat Widget](/widget/html-bootstrap-jquery) into your Website. +## SDK Method Reference + +Quick lookup for common operations: + +| Operation | Method | Returns | +|-----------|--------|---------| +| Initialize | `CometChat.init(appID, settings)` | `Promise` | +| Login (Auth Key) | `CometChat.login(uid, authKey)` | `Promise` | +| Login (Auth Token) | `CometChat.login(authToken)` | `Promise` | +| Logout | `CometChat.logout()` | `Promise` | +| Get Logged-in User | `CometChat.getLoggedinUser()` | `Promise` | +| Send Text | `CometChat.sendMessage(textMessage)` | `Promise` | +| Send Media | `CometChat.sendMediaMessage(mediaMessage)` | `Promise` | +| Fetch Messages | `messagesRequest.fetchPrevious()` | `Promise` | +| Fetch Conversations | `conversationsRequest.fetchNext()` | `Promise` | +| Get User | `CometChat.getUser(uid)` | `Promise` | +| Get Group | `CometChat.getGroup(guid)` | `Promise` | +| Connection Status | `CometChat.getConnectionStatus()` | `string` | diff --git a/sdk/javascript/presenter-mode.mdx b/sdk/javascript/presenter-mode.mdx index 42b2bdc2..9b2cc5f1 100644 --- a/sdk/javascript/presenter-mode.mdx +++ b/sdk/javascript/presenter-mode.mdx @@ -1,147 +1,347 @@ --- title: "Presenter Mode" +description: "Create webinar-style experiences with presenters and viewers" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Join as presenter +const presenterSettings = new CometChatCalls.PresenterSettingsBuilder() + .setIsPresenter(true) + .enableDefaultLayout(true) + .setCallEventListener(callListener) + .build(); +CometChatCalls.joinPresentation(callToken, presenterSettings, htmlElement); + +// Join as viewer +const viewerSettings = new CometChatCalls.PresenterSettingsBuilder() + .setIsPresenter(false) + .enableDefaultLayout(true) + .setCallEventListener(callListener) + .build(); +CometChatCalls.joinPresentation(callToken, viewerSettings, htmlElement); +``` + +Build webinar-style calling experiences where presenters share content while viewers watch without broadcasting their own media. ## Overview -The Presenter Mode feature allows developers to create a calling service experience in which: +Presenter Mode enables: +- Up to **5 presenters** sharing video, audio, and/or screen +- Up to **100 total participants** (presenters + viewers) +- Viewers consume content without sending their own streams +- Presenters have full control over mute, camera, recording, etc. + +## Use Cases + +- All-hands meetings +- Keynote presentations +- Webinars +- Online classes +- Talk shows +- Product demos + +## Prerequisites -1. There are one or more users who are presenting their video, audio and/or screen (Maximum 5) -2. Viewers who are consumers of that presentation. (They cannot send their audio, video or screen streams out). -3. The total number of presenters and viewers can go up to 100. -4. Features such as mute/unmute audio, show/hide camera capture, recording, etc. will be enabled only for the Presenter in this mode. -5. Other call participants will not get these features. Hence they act like passive viewers in the call. +Before implementing Presenter Mode: +1. Complete the [Calls SDK Setup](/sdk/javascript/calling-setup) +2. Generate a call token using [generateToken()](/sdk/javascript/direct-call#generate-call-token) -Using this feature developers can create experiences such as: +## User Types -1. All hands calls -2. Keynote speeches -3. Webinars -4. Talk shows -5. Online classes -6. and many more... +| Type | Can Send Media | Can Receive Media | Controls | +|------|----------------|-------------------|----------| +| Presenter | ✅ Video, Audio, Screen | ✅ | Full (mute, camera, recording) | +| Viewer | ❌ | ✅ | Limited (volume only) | -### About this guide +## Start Presentation + +Use `PresentationSettingsBuilder` to configure and join a presentation: + + + +```javascript +const presenterSettings = new CometChatCalls.PresenterSettingsBuilder() + .setIsPresenter(true) // Join as presenter + .enableDefaultLayout(true) + .setCallEventListener(callListener) + .build(); + +const htmlElement = document.getElementById("presentation-container"); +CometChatCalls.joinPresentation(callToken, presenterSettings, htmlElement); +``` + + +```javascript +const viewerSettings = new CometChatCalls.PresenterSettingsBuilder() + .setIsPresenter(false) // Join as viewer + .enableDefaultLayout(true) + .setCallEventListener(callListener) + .build(); + +const htmlElement = document.getElementById("presentation-container"); +CometChatCalls.joinPresentation(callToken, viewerSettings, htmlElement); +``` + + +```typescript +const presenterSettings = new CometChatCalls.PresenterSettingsBuilder() + .setIsPresenter(true) + .enableDefaultLayout(true) + .setCallEventListener(callListener) + .build(); + +const htmlElement = document.getElementById("presentation-container") as HTMLElement; +CometChatCalls.joinPresentation(callToken, presenterSettings, htmlElement); +``` + + -This guide demonstrates how to start a presentation into an React Native application. Before you begin, we strongly recommend you read the calling setup guide. +## Presentation Settings -Before starting a call session you have to generate a call token using the generateToken() method of the CometChatCalls SDK as mentioned [here](/sdk/javascript/direct-call#generate-call-token). +| Method | Description | Default | +|--------|-------------|---------| +| `setIsPresenter(boolean)` | `true` = presenter, `false` = viewer | - | +| `enableDefaultLayout(boolean)` | Show/hide default UI controls | `true` | +| `showEndCallButton(boolean)` | Show end call button | `true` | +| `showPauseVideoButton(boolean)` | Show pause video button (presenter only) | `true` | +| `showMuteAudioButton(boolean)` | Show mute audio button (presenter only) | `true` | +| `showSwitchCameraButton(boolean)` | Show camera switch button (presenter only) | `true` | +| `showAudioModeButton(boolean)` | Show audio mode selector | `true` | +| `setIsAudioOnlyCall(boolean)` | Audio-only presentation | `false` | +| `startWithAudioMuted(boolean)` | Start with mic muted | `false` | +| `startWithVideoMuted(boolean)` | Start with camera off | `false` | +| `showRecordingButton(boolean)` | Show recording button (presenter only) | `false` | +| `setDefaultAudioMode(string)` | Default audio output mode | - | -### Start Presentation Session +### Audio Modes -The most important class that will be used in the implementation is the `PresentationSettings` class. This class allows you to set the various parameters for the Presentation Mode. In order to set the various parameters of the `PresentationSettings` class, you need to use the `PresentationSettingsBuilder` class. Below are the various options available with the `PresentationSettings` class. +Available audio output modes: +- `CometChatCalls.AUDIO_MODE.SPEAKER` +- `CometChatCalls.AUDIO_MODE.EARPIECE` +- `CometChatCalls.AUDIO_MODE.BLUETOOTH` +- `CometChatCalls.AUDIO_MODE.HEADPHONES` -You will need to set the User Type, There are 2 type of users in Presenter Mode, `Presenter` & `Participant` , You can set this `PresentationSettingsBuilder` by using the following method `setIsPresenter(true/false)` +## Event Listeners -A basic example of how to start a Presentation: +Register listeners to handle presentation events: -```js -let presenterSettings = new CometChatCalls.PresenterSettingsBuilder() - .setIsPresenter(isPresenter) - .enableDefaultLayout(defaultLayout) - .setCallEventListener(callListener) - .build(); - -let htmlElement = document.getElementById("ELEMENT_ID"); -CometChatCalls.joinPresentation( - callToken, - presenterSettings, - htmlElement -); +```javascript +const callListener = { + onUserJoined: (user) => { + console.log("User joined:", user); + }, + onUserLeft: (user) => { + console.log("User left:", user); + }, + onUserListUpdated: (userList) => { + console.log("Participants:", userList); + }, + onCallEnded: () => { + console.log("Presentation ended"); + }, + onCallEndButtonPressed: () => { + console.log("End button pressed"); + CometChatCalls.endSession(); + }, + onError: (error) => { + console.log("Error:", error); + }, + onAudioModesUpdated: (audioModes) => { + console.log("Audio modes:", audioModes); + }, + onUserMuted: (event) => { + console.log("User muted:", event); + }, + onRecordingStarted: (user) => { + console.log("Recording started by:", user); + }, + onRecordingStopped: (user) => { + console.log("Recording stopped by:", user); + } +}; +``` + + +```typescript +const callListener = { + onUserJoined: (user: any): void => { + console.log("User joined:", user); + }, + onUserLeft: (user: any): void => { + console.log("User left:", user); + }, + onUserListUpdated: (userList: any[]): void => { + console.log("Participants:", userList); + }, + onCallEnded: (): void => { + console.log("Presentation ended"); + }, + onCallEndButtonPressed: (): void => { + console.log("End button pressed"); + CometChatCalls.endSession(); + }, + onError: (error: any): void => { + console.log("Error:", error); + }, + onAudioModesUpdated: (audioModes: any[]): void => { + console.log("Audio modes:", audioModes); + }, + onUserMuted: (event: any): void => { + console.log("User muted:", event); + }, + onRecordingStarted: (user: any): void => { + console.log("Recording started by:", user); + }, + onRecordingStopped: (user: any): void => { + console.log("Recording stopped by:", user); + } +}; ``` - - -## **Listeners** +### Adding/Removing Listeners -Listeners can be added in two ways the first one is to use `.setCallEventListener(listeners : OngoingCallListener)` method in `CallSettingsBuilder` or `PresenterSettingsBuilder` class. The second way is to use `CometChatCalls.addCallEventListener(name: string, callListener: OngoingCallListener)` by this you can add multiple listeners and remove the specific listener by their name `CometChatCalls.removeCallEventListener(name: string)` +You can add multiple listeners and remove them by ID: -```js -useEffect(() => { - CometChatCalls.addCallEventListener('UNIQUE_ID', { - onUserJoined: user => { - console.log("user joined:", user); - }, - onUserLeft: user => { - console.log("user left:", user); - }, - onUserListUpdated: userList => { - console.log("user list:", userList); - }, - onCallEnded: () => { - console.log("Call ended"); - }, - onCallEndButtonPressed: () => { - console.log("End Call button pressed"); - }, - onError: error => { - console.log('Call Error: ', error); - }, - onAudioModesUpdated: (audioModes) => { - console.log("audio modes:", audioModes); - }, - onUserMuted: (event) => { - console.log("user muted:", event); - } - }); - return ()=> CometChatCalls.removeCallEventListener('UNIQUE_ID') -}, []) -``` +```javascript +// Add listener +CometChatCalls.addCallEventListener("PRESENTATION_LISTENER", callListener); +// Remove listener when done +CometChatCalls.removeCallEventListener("PRESENTATION_LISTENER"); +``` + +```typescript +CometChatCalls.addCallEventListener("PRESENTATION_LISTENER", callListener); +CometChatCalls.removeCallEventListener("PRESENTATION_LISTENER"); +``` + + + +## Event Reference +| Event | Description | +|-------|-------------| +| `onCallEnded()` | Presentation ended | +| `onCallEndButtonPressed()` | User clicked end button | +| `onUserJoined(user)` | Participant joined | +| `onUserLeft(user)` | Participant left | +| `onUserListUpdated(users)` | Participant list changed | +| `onAudioModesUpdated(devices)` | Audio devices changed | +| `onUserMuted(event)` | User mute state changed | +| `onRecordingStarted(user)` | Recording started | +| `onRecordingStopped(user)` | Recording stopped | +| `onError(error)` | Error occurred | + +## Complete Example + + + +```javascript +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + +class PresentationManager { + constructor(containerId) { + this.container = document.getElementById(containerId); + this.callToken = null; + } + + async joinAsPresenter(callToken) { + this.callToken = callToken; + + const settings = new CometChatCalls.PresenterSettingsBuilder() + .setIsPresenter(true) + .enableDefaultLayout(true) + .showRecordingButton(true) + .startWithVideoMuted(false) + .startWithAudioMuted(false) + .setCallEventListener(this.getEventListener()) + .build(); + + CometChatCalls.joinPresentation(callToken, settings, this.container); + } + + async joinAsViewer(callToken) { + this.callToken = callToken; + + const settings = new CometChatCalls.PresenterSettingsBuilder() + .setIsPresenter(false) + .enableDefaultLayout(true) + .setCallEventListener(this.getEventListener()) + .build(); + + CometChatCalls.joinPresentation(callToken, settings, this.container); + } + + getEventListener() { + return { + onUserJoined: (user) => { + console.log(`${user.getName()} joined`); + this.updateParticipantCount(); + }, + onUserLeft: (user) => { + console.log(`${user.getName()} left`); + this.updateParticipantCount(); + }, + onUserListUpdated: (users) => { + this.participants = users; + this.updateParticipantCount(); + }, + onCallEnded: () => { + console.log("Presentation ended"); + this.cleanup(); + }, + onCallEndButtonPressed: () => { + CometChatCalls.endSession(); + this.cleanup(); + }, + onError: (error) => { + console.error("Presentation error:", error); + } + }; + } + + updateParticipantCount() { + const count = this.participants?.length || 0; + console.log(`Participants: ${count}`); + } + + cleanup() { + this.callToken = null; + this.participants = []; + } +} + +// Usage +const presentation = new PresentationManager("presentation-container"); + +// Host starts as presenter +await presentation.joinAsPresenter(callToken); + +// Attendees join as viewers +await presentation.joinAsViewer(callToken); +``` + -The `CometChatCallsEventsListener` listener provides you with the below callback methods: - -| Callback Method | Description | -| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| onCallEnded() | This method is called when the call is successfully ended. The call details can be obtained from the `Call` object provided. | -| onCallEndButtonPressed() | This method is called when the user press end call button. | -| onUserJoined(user: RTCUser) | This method is called when any other user joins the call. The user details can be obtained from the `User` object provided. | -| onUserLeft(user: RTCUser) | This method is called when a user leaves the call. The details of the user can be obtained from the provided `User` object. | -| onUserListUpdated(users: Array\) | This method is triggered every time a participant joins or leaves the call providing the list of users active in the call | -| onAudioModesUpdated(devices: Array\) | This callback is triggered if any new audio output source is available or becomes unavailable. | -| onUserMuted(muteObj: RTCMutedUser) | This method is triggered when a user is muted in the ongoing call. | -| onRecordingStarted(user: RTCUser) | This method is triggered when a recording starts. | -| onRecordingStopped(user: RTCUser) | This method is triggered when a recording stops. | -| onError(e: CometChatException) | This method is called when there is some error in establishing the call. | - -## Settings - -The `PresentationSettings` class is the most important class when it comes to the implementation of the Calling feature. This is the class that allows you to customize the overall calling experience. The properties for the call/conference can be set using the `PresentationSettingsBuilder` class. This will eventually give you and object of the `PresentationSettings` class which you can pass to the `joinPresentation()` method to start the call. - -The **mandatory** parameters that are required to be present for any call/conference to work are: - -1. Context - context of the activity/application -2. RelativeLayout - A RelativeLayout object in which the calling UI is loaded. - -The options available for customization of calls are: - -| Parameter | Description | -| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `setIsPresenter(isPresenter: boolean)` | If set to `true` user will join as the presenter. If set to `false` user will join as the viewer. | -| `enableDefaultLayout(defaultLayout: boolean)` | If set to `true` enables the default layout for handling the call operations. If set to `false` it hides the button layout and just displays the Call View. **Default value = true** | -| `showEndCallButton(showEndCallButton: boolean)` | If set to `true` it displays the EndCallButton in Button Layout. If set to `false` it hides the EndCallButton in Button Layout. **Default value = true** | -| `showPauseVideoButton(showPauseVideoButton: boolean)` | If set to `true` it displays the PauseVideoButton in Button Layout. If set to `false` it hides the PauseVideoButton in Button Layout. **Default value = true** | -| `showMuteAudioButton`(showMuteAudioButton: boolean)\`\` | If set to `true` it displays the MuteAudioButton in Button Layout. If set to `false` it hides the MuteAudioButton in Button Layout. **Default value = true** | -| `showSwitchCameraButton`(showSwitchCameraButton: boolean)\`\` | If set to `true` it displays the SwitchCameraButton in Button Layout. If set to `false` it hides the SwitchCameraButton in Button Layout. **Default value = true** | -| `showAudioModeButton`(showAudioModeButton: boolean)\`\` | If set to `true` it displays the AudioModeButton in Button Layout. If set to `false` it hides the AudioModeButton in Button Layout. **Default value = true** | -| `setIsAudioOnlyCall(audioOnly: boolean)` | If set to `true`, the call will be strictly an audio call. If set to `false`, the call will be an audio-video call.**Default value = false** | -| `startWithAudioMuted(audioMuted: boolean)` | This ensures the call is started with the audio muted if set to true. **Default value = false** | -| `startWithVideoMuted(videoMuted: boolean)` | This ensures the call is started with the video paused if set to true. **Default value = false** | -| `startWithVideoMuted(videoMuted: boolean)` | If set to true it displays the Recording in Button Layout. if set to false it hides the Recording in Button Layout. **Default value = false** | -| `setDefaultAudioMode(audioMode: string)` | This method can be used if you wish to start the call with a specific audio mode. The available options are 1. CometChatCalls.AUDIO\_MODE.SPEAKER = "SPEAKER" 2. CometChatCalls.AUDIO\_MODE.EARPIECE = "EARPIECE" 3. CometChatCalls.AUDIO\_MODE.BLUETOOTH = "BLUETOOTH" 4. CometChatCalls.AUDIO\_MODE.HEADPHONES = "HEADPHONES" | -| `setEventListener(new CometChatCallsEventsListener())` | The `CometChatCallsEventsListener` listener provides you callbacks | - -In case you wish to achieve a completely customised UI for the Calling experience, you can do so by embedding default android buttons to the screen as per your requirement and then use the below methods to achieve different functionalities for the embedded buttons. - -For the use case where you wish to align your own custom buttons and not use the default layout provided by CometChat you can embed the buttons in your layout and use the below methods to perform the corresponding operations: +## Next Steps + + + + Record presentations for later viewing + + + Share your screen during presentations + + diff --git a/sdk/javascript/rate-limits.mdx b/sdk/javascript/rate-limits.mdx index 17581b14..24bc8935 100644 --- a/sdk/javascript/rate-limits.mdx +++ b/sdk/javascript/rate-limits.mdx @@ -1,34 +1,232 @@ --- title: "Rate Limits" +description: "Understanding and handling CometChat API rate limits" --- - - -### CometChat REST API Rate Limits +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Handle rate limit errors with retry +async function sendWithRetry(message, maxRetries = 3) { + for (let i = 0; i < maxRetries; i++) { + try { + return await CometChat.sendMessage(message); + } catch (error) { + if (error.code === "ERR_TOO_MANY_REQUESTS") { + const delay = error.details?.retryAfter || Math.pow(2, i) * 1000; + await new Promise(r => setTimeout(r, delay)); + } else throw error; + } + } +} + +// Rate limits: Core ops 10,000/min, Standard ops 20,000/min +// Response headers: X-Rate-Limit, X-Rate-Limit-Remaining, Retry-After +``` + + +CometChat enforces rate limits to ensure platform stability and fair usage across all applications. - -The rate limits below are for general applications. Rate limits can be adjusted on a per need basis, depending on your use-case and plan. The rate limits are cumulative. For example: If the rate limit for core operations is 100 requests per minute, then you can either login a user, add user to a group, remove a user from a group, etc for total 100 requests per minute. - +Rate limits shown below are defaults. Limits can be adjusted based on your use case and plan. Contact [CometChat Support](https://help.cometchat.com) for custom limits. -1. **Core Operations:** Core operations are rate limited to `10,000` requests per minute. Core operations include user login, create/delete user, create/join group cumulatively. -2. **Standard Operations:** Standard operations are rate limited to `20,000` requests per minute. Standard operations include all other operations cumulatively. - -## What happens when rate limit is reached ? - -The request isn't processed and a response is sent containing a 429 response code. Along with the response code there will be couple of headers sent which specifies the time in seconds that you must wait before you can try request again. - -`Retry-After: 15` - -`X-Rate-Limit-Reset: 1625143246` - -## Is there any endpoint that returns rate limit of all resources ? - -No, we don't provide a rate-limit endpoint. - -However, we do provide the following response headers that you can use to confirm the app's current rate limit and monitor the number of requests remaining in the current minute: - -`X-Rate-Limit: 700` - -`X-Rate-Limit-Remaining: 699` +## Rate Limit Overview + +| Operation Type | Limit | Examples | +|----------------|-------|----------| +| Core Operations | 10,000/min | Login, create user, create group, join group | +| Standard Operations | 20,000/min | Send message, fetch users, update profile | + + +Rate limits are **cumulative** within each category. For example, if you login 5,000 users and create 5,000 groups in one minute, you've used your entire core operations quota. + + +## Response Headers + +Every API response includes rate limit information: + +| Header | Description | Example | +|--------|-------------|---------| +| `X-Rate-Limit` | Your total limit per minute | `10000` | +| `X-Rate-Limit-Remaining` | Requests remaining | `9500` | +| `Retry-After` | Seconds until reset (when limited) | `15` | +| `X-Rate-Limit-Reset` | Unix timestamp of reset | `1625143246` | + +## Handling Rate Limits + +When you exceed the rate limit, the API returns a `429 Too Many Requests` response. + + + +```javascript +async function sendMessageWithRetry(message, maxRetries = 3) { + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + return await CometChat.sendMessage(message); + } catch (error) { + if (error.code === "ERR_TOO_MANY_REQUESTS") { + // Get retry delay from error or use exponential backoff + const retryAfter = error.details?.retryAfter || Math.pow(2, attempt) * 1000; + console.log(`Rate limited. Retrying in ${retryAfter}ms...`); + await new Promise(resolve => setTimeout(resolve, retryAfter)); + } else { + throw error; + } + } + } + throw new Error("Max retries exceeded"); +} +``` + + +```typescript +async function sendMessageWithRetry( + message: CometChat.TextMessage, + maxRetries: number = 3 +): Promise { + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + return await CometChat.sendMessage(message); + } catch (error: any) { + if (error.code === "ERR_TOO_MANY_REQUESTS") { + const retryAfter = error.details?.retryAfter || Math.pow(2, attempt) * 1000; + console.log(`Rate limited. Retrying in ${retryAfter}ms...`); + await new Promise(resolve => setTimeout(resolve, retryAfter)); + } else { + throw error; + } + } + } + throw new Error("Max retries exceeded"); +} +``` + + + +## Best Practices + + + + Queue requests and process them at a controlled rate to avoid hitting limits. + + ```javascript + class RequestQueue { + constructor(requestsPerSecond = 100) { + this.queue = []; + this.interval = 1000 / requestsPerSecond; + this.processing = false; + } + + add(request) { + return new Promise((resolve, reject) => { + this.queue.push({ request, resolve, reject }); + this.process(); + }); + } + + async process() { + if (this.processing) return; + this.processing = true; + + while (this.queue.length > 0) { + const { request, resolve, reject } = this.queue.shift(); + try { + resolve(await request()); + } catch (error) { + reject(error); + } + await new Promise(r => setTimeout(r, this.interval)); + } + + this.processing = false; + } + } + ``` + + + + Use batch APIs instead of individual requests: + + ```javascript + // Instead of multiple individual fetches + // Use pagination with larger limits + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(100) // Fetch more per request + .build(); + ``` + + + + Cache user profiles, group info, and other data that doesn't change often: + + ```javascript + const userCache = new Map(); + + async function getUser(uid) { + if (userCache.has(uid)) { + return userCache.get(uid); + } + const user = await CometChat.getUser(uid); + userCache.set(uid, user); + return user; + } + ``` + + + + Track rate limit headers to proactively manage usage: + + ```javascript + function checkRateLimitStatus(response) { + const remaining = response.headers?.["X-Rate-Limit-Remaining"]; + const limit = response.headers?.["X-Rate-Limit"]; + + if (remaining && limit) { + const usagePercent = ((limit - remaining) / limit) * 100; + if (usagePercent > 80) { + console.warn(`Rate limit usage at ${usagePercent.toFixed(1)}%`); + } + } + } + ``` + + + +## Common Scenarios + +| Scenario | Recommendation | +|----------|----------------| +| Bulk user import | Use REST API with batching, implement delays | +| High-traffic chat rooms | Use message pagination, cache messages | +| Presence-heavy apps | Limit presence subscriptions to visible users | +| Notification systems | Queue notifications, use batch sends | + +## FAQ + + + + There's no dedicated endpoint, but every API response includes `X-Rate-Limit` and `X-Rate-Limit-Remaining` headers. + + + + No, rate limits apply to REST API calls only. Real-time messages via WebSocket have separate throttling. + + + + Yes, contact [CometChat Support](https://help.cometchat.com) to discuss your requirements and plan options. + + + +## Next Steps + + + + Handle connection state changes + + + Complete error handling guide + + diff --git a/sdk/javascript/reactions.mdx b/sdk/javascript/reactions.mdx index 8ac8f43f..49f4ba31 100644 --- a/sdk/javascript/reactions.mdx +++ b/sdk/javascript/reactions.mdx @@ -1,363 +1,428 @@ --- title: "Reactions" +description: "Add emoji reactions to messages" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Add reaction +await CometChat.addReaction(messageId, "😊"); + +// Remove reaction +await CometChat.removeReaction(messageId, "😊"); + +// Get reactions from message +const reactions = message.getReactions(); +reactions.forEach((r) => { + console.log(r.getReaction(), r.getCount(), r.getReactedByMe()); +}); + +// Fetch detailed reaction info (who reacted) +const reactionRequest = new CometChat.ReactionRequestBuilder() + .setMessageId(messageId) + .setLimit(10) + .build(); +const reactions = await reactionRequest.fetchNext(); + +// Listen for real-time reactions +CometChat.addMessageListener("REACTION_LISTENER", new CometChat.MessageListener({ + onMessageReactionAdded: (event) => { + console.log(event.getReactedBy().getName(), "reacted with", event.getReaction()); + }, + onMessageReactionRemoved: (event) => { /* handle removal */ } +})); +``` + +Reactions let users express emotions on messages using emojis, enhancing engagement in your chat application. -Enhance user engagement in your chat application with message reactions. Users can express their emotions using reactions to messages. This feature allows users to add or remove reactions, and to fetch all reactions on a message. You can also listen to reaction events in real-time. Let's see how to work with reactions in CometChat's SDK. + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + + +--- ## Add a Reaction -Users can add a reaction to a message by calling `addReaction` with the message ID and the reaction emoji. +Add an emoji reaction to any message: - -```js -let messageId = "1"; -let emoji = "😊"; - -CometChat.addReaction(messageId, emoji) -.then((res) => { - console.log('response', res); -}).catch(err => { - console.log('err', err); -}) -``` - - - - -```typescript -let messageId:string = "1"; -let emoji:string = "😊"; - -CometChat.addReaction(messageId, emoji) -.then((res:CometChat.BaseMessage) => { - console.log('response', res); -}).catch((err:CometChat.CometChatException) => { - console.log('err', err); -}) -``` - - + + ```javascript + const messageId = 123; + const emoji = "😊"; + + CometChat.addReaction(messageId, emoji).then( + (message) => console.log("Reaction added:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```typescript + const messageId: number = 123; + const emoji: string = "😊"; + + CometChat.addReaction(messageId, emoji).then( + (message: CometChat.BaseMessage) => console.log("Reaction added:", message), + (error: CometChat.CometChatException) => console.log("Error:", error) + ); + ``` + + + ```javascript + async function addReaction(messageId, emoji) { + try { + const message = await CometChat.addReaction(messageId, emoji); + console.log("Reaction added:", emoji); + return message; + } catch (error) { + console.error("Failed to add reaction:", error); + throw error; + } + } + // Usage + await addReaction(123, "😊"); + await addReaction(123, "👍"); + ``` + - -You can react on text message, media message and custom message - +You can react to text messages, media messages, and custom messages. +--- + ## Remove a Reaction -Removing a reaction from a message can be done using the `removeReaction` method. +Remove your reaction from a message: - -```js -let messageId = "1"; -let emoji = "😊"; - -CometChat.removeReaction(messageId, emoji) -.then((res) => { - console.log('response', res); -}).catch(err => { - console.log('err', err); -}) -``` - - - - -```typescript -let messageId:string = "1"; -let emoji:string = "😊"; - -CometChat.removeReaction(messageId, emoji) -.then((res:CometChat.BaseMessage) => { - console.log('response', res); -}).catch((err:CometChat.CometChatException) => { - console.log('err', err); -}) -``` - - + + ```javascript + const messageId = 123; + const emoji = "😊"; + + CometChat.removeReaction(messageId, emoji).then( + (message) => console.log("Reaction removed:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```typescript + const messageId: number = 123; + const emoji: string = "😊"; + + CometChat.removeReaction(messageId, emoji).then( + (message: CometChat.BaseMessage) => console.log("Reaction removed:", message), + (error: CometChat.CometChatException) => console.log("Error:", error) + ); + ``` + + + ```javascript + async function removeReaction(messageId, emoji) { + try { + const message = await CometChat.removeReaction(messageId, emoji); + console.log("Reaction removed:", emoji); + return message; + } catch (error) { + console.error("Failed to remove reaction:", error); + throw error; + } + } + // Usage + await removeReaction(123, "😊"); + ``` + -## Fetch Reactions for a Message - -To get all reactions for a specific message, first create a `ReactionRequest` using `ReactionRequestBuilder`. You can specify the number of reactions to fetch with setLimit with max limit 100. For this, you will require the ID of the message. This ID needs to be passed to the `setMessageId()` method of the builder class. The `setReaction()` will allow you to fetch details for specific reaction or emoji. - -| Setting | Description | -| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `setMessageId(value)` | Specifies the unique identifier of the message for which you want to fetch reactions. This parameter is mandatory as it tells the SDK which message's reactions are being requested. | -| `setReaction(value)` | Filters the reactions fetched by the specified reaction type (e.g., "😊", "😂", "👍"). When set, this method will cause the ReactionRequest to only retrieve details of the provided reaction for the given message. | - -*** - -## Fetch Next - -The `fetchNext()` method fetches the next set of reactions for the message. - - - -```js -let limit = 10; -let messageId = 1; - -let reactionRequest = new CometChat.ReactionRequestBuilder() -.setMessageId(messageId) -.setLimit(limit) -.build(); - -reactionRequest.fetchNext().then( - messages => { - console.log("list fetched:", messages); - }, - error => {a - console.log('list fetching failed with error:', error); - }, - ); -``` +--- - +## Get Reactions from Message - -```typescript -let limit:number = 10; -let messageId:number = 1; +Access reactions directly from a message object: -let reactionRequest = new CometChat.ReactionRequestBuilder() -.setMessageId(messageId) -.setLimit(limit) -.build(); +```javascript +const reactions = message.getReactions(); -reactionRequest.fetchNext().then( - (messages: MessageReaction[]) => { - console.log("list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log('list fetching failed with error:', error); - }, - ); +reactions.forEach((reaction) => { + console.log("Emoji:", reaction.getReaction()); + console.log("Count:", reaction.getCount()); + console.log("Reacted by me:", reaction.getReactedByMe()); +}); ``` - +--- - +## Fetch Reaction Details -Fetch Previous The `fetchPrevious()` method fetches the previous set of reactions for the message. +Get detailed information about who reacted to a message: - -```js -let limit = 10; -let messageId = 1; - -let reactionRequest = new CometChat.ReactionRequestBuilder() -.setMessageId(messageId) -.setLimit(limit) -.build(); - -reactionRequest.fetchPrevious().then( - messages => { - console.log("list fetched:", messages); - }, - error => {a - console.log('list fetching failed with error:', error); - }, - ); -``` - - + + ```javascript + const messageId = 123; + const limit = 10; + + const reactionRequest = new CometChat.ReactionRequestBuilder() + .setMessageId(messageId) + .setLimit(limit) + .build(); + + reactionRequest.fetchNext().then( + (reactions) => { + reactions.forEach((reaction) => { + console.log("User:", reaction.getReactedBy().getName()); + console.log("Emoji:", reaction.getReaction()); + }); + }, + (error) => console.log("Error:", error) + ); + ``` + + + ```typescript + const messageId: number = 123; + const limit: number = 10; + + const reactionRequest = new CometChat.ReactionRequestBuilder() + .setMessageId(messageId) + .setLimit(limit) + .build(); + + reactionRequest.fetchNext().then( + (reactions: CometChat.MessageReaction[]) => { + reactions.forEach((reaction) => { + console.log("User:", reaction.getReactedBy().getName()); + console.log("Emoji:", reaction.getReaction()); + }); + }, + (error: CometChat.CometChatException) => console.log("Error:", error) + ); + ``` + + + ```javascript + async function fetchReactionDetails(messageId, limit = 10) { + try { + const reactionRequest = new CometChat.ReactionRequestBuilder() + .setMessageId(messageId) + .setLimit(limit) + .build(); + + const reactions = await reactionRequest.fetchNext(); + reactions.forEach((reaction) => { + console.log("User:", reaction.getReactedBy().getName()); + console.log("Emoji:", reaction.getReaction()); + }); + return reactions; + } catch (error) { + console.error("Failed to fetch reactions:", error); + throw error; + } + } - -```typescript -let limit:number = 10; -let messageId:number = 1; + // Usage + const reactions = await fetchReactionDetails(123); + ``` + + -let reactionRequest = new CometChat.ReactionRequestBuilder() -.setMessageId(messageId) -.setLimit(limit) -.build(); +### Filter by Specific Emoji -reactionRequest.fetchPrevious().then( - (messages: MessageReaction[]) => { - console.log("list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log('list fetching failed with error:', error); - }, - ); +```javascript +const reactionRequest = new CometChat.ReactionRequestBuilder() + .setMessageId(messageId) + .setReaction("😊") // Only fetch this emoji's reactions + .setLimit(10) + .build(); ``` - - - +### ReactionRequestBuilder Options -## Real-time Reaction Events +| Method | Description | +|--------|-------------| +| `setMessageId(id)` | Required. Message to fetch reactions for | +| `setReaction(emoji)` | Filter by specific emoji | +| `setLimit(limit)` | Number of reactions to fetch (max 100) | -Keep the chat interactive with real-time updates for reactions. Register a listener for these events and make your UI responsive. +--- - - -```js -let listenerID = "UNIQUE_LISTENER_ID"; +## Real-Time Reaction Events -CometChat.addMessageListener(listenerID, { - onMessageReactionAdded:(message) => { - console.log("Reaction added", message); - }, - onMessageReactionRemoved:(message) => { - console.log("Reaction removed", message); - } - }) -``` - - +Listen for reactions in real-time: - -```typescript -let listenerID:string = "UNIQUE_LISTENER_ID"; +```javascript +const listenerID = "REACTION_LISTENER"; -CometChat.addMessageListener(listenerID, { - onMessageReactionAdded:(message: Object) => { - console.log("Reaction added", message); +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageReactionAdded: (reactionEvent) => { + console.log("Reaction added:", reactionEvent); + + const messageId = reactionEvent.getMessageId(); + const reaction = reactionEvent.getReaction(); + const reactedBy = reactionEvent.getReactedBy(); + + console.log(`${reactedBy.getName()} reacted with ${reaction}`); }, - onMessageReactionRemoved:(message: Object) => { - console.log("Reaction removed", message); + onMessageReactionRemoved: (reactionEvent) => { + console.log("Reaction removed:", reactionEvent); } - }) -``` - - - - - -## Removing a Reaction Listener - -To stop listening for reaction events, remove the listener as follows: - - - -```js -let listenerID = "UNIQUE_LISTENER_ID"; + }) +); +// Remove listener when done CometChat.removeMessageListener(listenerID); ``` - - - -```typescript -let listenerID:string = "UNIQUE_LISTENER_ID"; - -CometChat.removeMessageReactionListener(listenerID); -``` - - - - - -## Get Reactions List - -To retrieve the list of reactions reacted on particular message, you can use the `message.getReactions()` method. This method will return an array containing the reactions, or an empty array if no one reacted on the message. +--- - - -```js -message.getReactions() -``` +## Update Message with Reaction - +When you receive a real-time reaction event, update your message object: - -```typescript -message.getReactions() +```javascript +// In your reaction event handler +onMessageReactionAdded: (reactionEvent) => { + const action = CometChat.REACTION_ACTION.REACTION_ADDED; + + const updatedMessage = CometChat.CometChatHelper.updateMessageWithReactionInfo( + originalMessage, + reactionEvent, + action + ); + + // Update your UI with the modified message + updateMessageInUI(updatedMessage); +} + +onMessageReactionRemoved: (reactionEvent) => { + const action = CometChat.REACTION_ACTION.REACTION_REMOVED; + + const updatedMessage = CometChat.CometChatHelper.updateMessageWithReactionInfo( + originalMessage, + reactionEvent, + action + ); + + updateMessageInUI(updatedMessage); +} ``` - - - - -## Check if Logged-in User has Reacted on Message +--- -To check if the logged-in user has reacted on a particular message or not, You can use the `getReactedByMe()` method on any `ReactionCount` object instance. This method will return a boolean value, true if the logged-in user has reacted on that message, otherwise false. +## Check if User Reacted - - -```js -let reactions = message.getReactions(); -reactions.forEach((reaction) => { -reaction.getReactedByMe(); //Return true is logged-in user reacted on that message, otherwise false -}) -``` +Check if the logged-in user has reacted to a message: - +```javascript +const reactions = message.getReactions(); - -```typescript -let reactions = message.getReactions(); reactions.forEach((reaction) => { -reaction.getReactedByMe(); //Return true is logged-in user reacted on that message, otherwise false -}) + if (reaction.getReactedByMe()) { + console.log(`You reacted with ${reaction.getReaction()}`); + } +}); ``` - - - - -## Update Message With Reaction Info - -When a user adds or removes a reaction, you will receive a real-time event. Once you receive the real time event you would want to update the message with the latest reaction information. To do so you can use the `updateMessageWithReactionInfo()` method. - -The `updateMessageWithReactionInfo()` method provides a seamless way to update the reactions on a message instance (`BaseMessage`) in real-time. This method ensures that when a reaction is added or removed from a message, the BaseMessage object's `getReactions()` property reflects this change immediately. - -When you receive a real-time reaction event (`MessageReaction`), call the `updateMessageWithReactionInfo()` method, passing the BaseMessage instance (`message`), event data (`MessageReaction`) and reaction event action type (`CometChat.REACTION_ACTION.REACTION_ADDED` or `CometChat.REACTION_ACTION.REACTION_REMOVED`) that corresponds to the message being reacted to. +--- - - -```js -// The message to which the reaction is related -let message = ...; - -// The reaction event data received in real-time -let messageReaction = ...; - -// The recieved reaction event real-time action type. Can be CometChatConstants.REACTION_ADDED or CometChatConstants.REACTION_REMOVED -let action = CometChat.REACTION_ACTION.REACTION_ADDED; - -let modifiedBaseMessage = CometChat.CometChatHelper.updateMessageWithReactionInfo( -baseMessage, -messageReaction, -action -); +## Implementation Example + +```javascript +class ReactionManager { + constructor() { + this.setupListener(); + } + + setupListener() { + CometChat.addMessageListener( + "REACTION_LISTENER", + new CometChat.MessageListener({ + onMessageReactionAdded: (event) => this.handleReactionAdded(event), + onMessageReactionRemoved: (event) => this.handleReactionRemoved(event) + }) + ); + } + + async toggleReaction(messageId, emoji) { + const message = this.getMessage(messageId); + const reactions = message.getReactions(); + const existingReaction = reactions.find( + (r) => r.getReaction() === emoji && r.getReactedByMe() + ); + + if (existingReaction) { + await CometChat.removeReaction(messageId, emoji); + } else { + await CometChat.addReaction(messageId, emoji); + } + } + + handleReactionAdded(event) { + const message = this.getMessage(event.getMessageId()); + const updated = CometChat.CometChatHelper.updateMessageWithReactionInfo( + message, + event, + CometChat.REACTION_ACTION.REACTION_ADDED + ); + this.updateUI(updated); + } + + handleReactionRemoved(event) { + const message = this.getMessage(event.getMessageId()); + const updated = CometChat.CometChatHelper.updateMessageWithReactionInfo( + message, + event, + CometChat.REACTION_ACTION.REACTION_REMOVED + ); + this.updateUI(updated); + } +} ``` - - - -```typescript -// The message to which the reaction is related -let message: CometChat.BaseMessage = ...; - -// The reaction event data received in real-time -let messageReaction: CometChat.MessageReaction = ...; - -// The recieved reaction event real-time action type. Can be CometChatConstants.REACTION_ADDED or CometChatConstants.REACTION_REMOVED -let action: CometChat.REACTION_ACTION = CometChat.REACTION_ACTION.REACTION_ADDED; +--- -let modifiedBaseMessage = CometChat.CometChatHelper.updateMessageWithReactionInfo( -baseMessage, -messageReaction, -action -); +## Display Reactions UI + +```javascript +function renderReactions(message) { + const reactions = message.getReactions(); + + return reactions.map((reaction) => ({ + emoji: reaction.getReaction(), + count: reaction.getCount(), + isSelected: reaction.getReactedByMe() + })); +} + +// Example output: +// [ +// { emoji: "😊", count: 5, isSelected: true }, +// { emoji: "👍", count: 3, isSelected: false }, +// { emoji: "❤️", count: 2, isSelected: false } +// ] ``` - +--- - +## Next Steps -After calling this method, the message instance's reactions are updated. You can then use message.getReactions() to get the latest reactions and refresh your UI accordingly. + + + @mention users in messages + + + Create message threads + + diff --git a/sdk/javascript/receive-message.mdx b/sdk/javascript/receive-message.mdx index a6f9a892..b5633c6b 100644 --- a/sdk/javascript/receive-message.mdx +++ b/sdk/javascript/receive-message.mdx @@ -1,958 +1,670 @@ --- -title: "Receive A Message" +title: "Receive Messages" +description: "Handle real-time messages and fetch message history" --- +{/* Agent-Friendly Quick Reference */} + +**Quick Reference** +```javascript +// Listen for real-time messages (register AFTER login) +CometChat.addMessageListener("LISTENER_ID", new CometChat.MessageListener({ + onTextMessageReceived: (msg) => console.log(msg.getText()), + onMediaMessageReceived: (msg) => console.log(msg.getAttachment()), +})); + +// Fetch message history +const request = new CometChat.MessagesRequestBuilder().setUID("USER_UID").setLimit(30).build(); +const messages = await request.fetchPrevious(); -Receiving messages with CometChat has two parts: +// Cleanup (on component unmount) +CometChat.removeMessageListener("LISTENER_ID"); +``` -1. Adding a listener to receive [real-time messages](/sdk/javascript/receive-message#real-time-messages) when your app is running -2. Calling a method to retrieve [missed messages](/sdk/javascript/receive-message#missed-messages) when your app was not running +**Key Points:** +- Register listeners AFTER successful login +- Use unique listener IDs (duplicates overwrite) +- Always remove listeners on cleanup + -## Real-Time Messages +Receiving messages in CometChat involves two parts. If you're unfamiliar with message categories (message, custom, action, call) and types (text, image, video, etc.), review the [Message Structure & Hierarchy](/sdk/javascript/message-structure-and-hierarchy) guide first. -*In other words, as a recipient, how do I receive messages when my app is running?* + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + -To receive real-time incoming messages, you need to register the `MessageListener` wherever you wish to receive the incoming messages. You can use the `addMessageListener()` method to do so. +1. **Real-time messages** - Listen for new messages while your app is running +2. **Message history** - Fetch previous messages when loading a conversation + +--- + +## Real-Time Messages + +Register a `MessageListener` to receive messages instantly: - - ```javascript -let listenerID = "UNIQUE_LISTENER_ID"; +const listenerID = "UNIQUE_LISTENER_ID"; CometChat.addMessageListener( listenerID, new CometChat.MessageListener({ onTextMessageReceived: (textMessage) => { - console.log("Text message received successfully", textMessage); + console.log("Text message received:", textMessage); }, onMediaMessageReceived: (mediaMessage) => { - console.log("Media message received successfully", mediaMessage); + console.log("Media message received:", mediaMessage); }, onCustomMessageReceived: (customMessage) => { - console.log("Custom message received successfully", customMessage); - }, - }) -); -``` - - - - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; - -CometChat.addMessageListener( - listenerID, - new CometChat.MessageListener({ - onTextMessageReceived: (textMessage: CometChat.TextMessage) => { - console.log("Text message received successfully", textMessage); - }, - onMediaMessageReceived: (mediaMessage: CometChat.MediaMessage) => { - console.log("Media message received successfully", mediaMessage); - }, - onCustomMessageReceived: (customMessage: CometChat.CustomMessage) => { - console.log("Custom message received successfully", customMessage); - }, + console.log("Custom message received:", customMessage); + } }) ); ``` - - - + +As a sender, you won't receive your own messages in real-time events. However, if logged in on multiple devices, other devices will receive the event. + -| Parameter | Description | -| -------------- | --------------------------------------------- | -| **listenerId** | An ID that uniquely identifies that listener. | +### Remove Listener -We recommend you remove the listener once you don't want to receive a message for particular listener. +Always remove listeners when they're no longer needed (e.g., when unmounting a component): - - ```javascript -let listenerID = "UNIQUE_LISTENER_ID"; - CometChat.removeMessageListener(listenerID); ``` - - - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +### All Message Events -CometChat.removeMessageListener(listenerID); +```javascript +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + // Message received + onTextMessageReceived: (textMessage) => {}, + onMediaMessageReceived: (mediaMessage) => {}, + onCustomMessageReceived: (customMessage) => {}, + onInteractiveMessageReceived: (interactiveMessage) => {}, + + // Message updates + onMessageEdited: (message) => {}, + onMessageDeleted: (message) => {}, + + // Typing indicators + onTypingStarted: (typingIndicator) => {}, + onTypingEnded: (typingIndicator) => {}, + + // Read receipts + onMessagesDelivered: (messageReceipt) => {}, + onMessagesRead: (messageReceipt) => {}, + onMessagesDeliveredToAll: (messageReceipt) => {}, // Groups only + onMessagesReadByAll: (messageReceipt) => {}, // Groups only + + // Transient messages + onTransientMessageReceived: (transientMessage) => {} + }) +); ``` - - - - - - -As a sender, you will not receive your own message in a real-time message event. However, if a user is logged-in using multiple devices, they will receive an event for their own message in other devices. - - - -## Missed Messages - -*In other words, as a recipient, how do I receive messages that I missed when my app was not running?* - -For most use cases, you will need to add functionality to load missed messages. If you're building an on-demand or live streaming app, you may choose to skip this and fetch message history instead. - -Using the same `MessagesRequest` class and the filters provided by the `MessagesRequestBuilder` class, you can fetch the message that were sent to the logged-in user but were not delivered to him as he was offline. For this, you will require the id of the last message received. You can either maintain it at your end or use the `getLastDeliveredMessageId()` method provided by the CometChat class. This id needs to be passed to the `setMessageId()` method of the builder class. +--- -Now using the `fetchNext()` method, you can fetch all the messages that were sent to the user when he/she was offline. +## Message History -Calling the `fetchNext()` method on the same object repeatedly allows you to fetch all the offline messages for the logged in user. +Fetch previous messages for a conversation using `MessagesRequest`. -### Fetch Missed Messages of a particular one-on-one conversation +### One-on-One Conversation - -```javascript -let UID = "UID"; -let limit = 30; -let latestId = await CometChat.getLastDeliveredMessageId(); + + ```javascript + const UID = "user_id"; + const limit = 30; -var messagesRequest = new CometChat.MessagesRequestBuilder() - .setUID(UID) - .setMessageId(latestId) - .setLimit(limit) - .build(); - -messagesRequest.fetchNext().then( - (messages) => { - console.log("Message list fetched:", messages); - }, - (error) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - - -```typescript -let UID: string = "UID", - limit: number = 30, - latestId: number = await CometChat.getLastDeliveredMessageId(), - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() + const messagesRequest = new CometChat.MessagesRequestBuilder() .setUID(UID) - .setMessageId(latestId) .setLimit(limit) .build(); -messagesRequest.fetchNext().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Message list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - + messagesRequest.fetchPrevious().then( + (messages) => { + console.log("Messages:", messages); + }, + (error) => { + console.log("Error:", error); + } + ); + ``` + + + ```typescript + const UID: string = "user_id"; + const limit: number = 30; + + const messagesRequest: CometChat.MessagesRequest = + new CometChat.MessagesRequestBuilder() + .setUID(UID) + .setLimit(limit) + .build(); + + messagesRequest.fetchPrevious().then( + (messages: CometChat.BaseMessage[]) => { + console.log("Messages:", messages); + }, + (error: CometChat.CometChatException) => { + console.log("Error:", error); + } + ); + ``` + + + ```javascript + async function fetchMessages(uid, limit = 30) { + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(uid) + .setLimit(limit) + .build(); + + try { + const messages = await messagesRequest.fetchPrevious(); + console.log(`Fetched ${messages.length} messages`); + return messages; + } catch (error) { + console.error("Failed to fetch messages:", error); + throw error; + } + } + + // Usage + const messages = await fetchMessages("user123"); + ``` + -### Fetch Missed Messages of a particular group conversation +### Group Conversation - - ```javascript -let GUID = "GUID"; -let limit = 30; -let latestId = await CometChat.getLastDeliveredMessageId(); +const GUID = "group_id"; +const limit = 30; -var messagesRequest = new CometChat.MessagesRequestBuilder() +const messagesRequest = new CometChat.MessagesRequestBuilder() .setGUID(GUID) - .setMessageId(latestId) .setLimit(limit) .build(); -messagesRequest.fetchNext().then( - (messages) => { - console.log("Message list fetched:", messages); - }, - (error) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - - -```typescript -let GUID: string = "GUID", - limit: number = 30, - latestId: number = await CometChat.getLastDeliveredMessageId(), - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setMessageId(latestId) - .setLimit(limit) - .build(); - -messagesRequest.fetchNext().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Message list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); - } +messagesRequest.fetchPrevious().then( + (messages) => console.log("Messages:", messages), + (error) => console.log("Error:", error) ); ``` - - - - -## Unread Messages - -*In other words, as a logged-in user, how do I fetch the messages I've not read?* +### Pagination -Using the `MessagesRequest` class described above, you can fetch the unread messages for the logged in user. In order to achieve this, you need to set the `unread` variable in the builder to true using the `setUnread()` method so that only the unread messages are fetched. - -### Fetch Unread Messages of a particular one-on-one conversation +Call `fetchPrevious()` repeatedly on the same request object to load older messages: - + ```javascript -let UID = "UID"; -let limit = 30; -let messagesRequest = new CometChat.MessagesRequestBuilder() +// Initial load +const messagesRequest = new CometChat.MessagesRequestBuilder() .setUID(UID) - .setUnread(true) - .setLimit(limit) + .setLimit(30) .build(); -messagesRequest.fetchPrevious().then( - (messages) => { - console.log("Message list fetched:", messages); - }, - (error) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - - -```typescript -let UID: string = "UID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() - .setUID(UID) - .setUnread(true) - .setLimit(limit) - .build(); +// First page +messagesRequest.fetchPrevious().then((messages) => { + displayMessages(messages); +}); -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Message list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); - } -); +// Load more (on scroll up) +function loadMoreMessages() { + messagesRequest.fetchPrevious().then((messages) => { + prependMessages(messages); + }); +} ``` - - - - -### Fetch Unread Messages of a particular group conversation - - - + ```javascript -let GUID = "GUID"; -let limit = 30; -let messagesRequest = new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setUnread(true) - .setLimit(limit) +// Initial load +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(UID) + .setLimit(30) .build(); -messagesRequest.fetchPrevious().then( - (messages) => { - console.log("Message list fetched:", messages); - }, - (error) => { - console.log("Message fetching failed with error:", error); +// First page +async function loadInitialMessages() { + try { + const messages = await messagesRequest.fetchPrevious(); + displayMessages(messages); + return messages; + } catch (error) { + console.log("Error:", error); + throw error; } -); -``` - - - - -```typescript -let GUID: string = "GUID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setUnread(true) - .setLimit(limit) - .build(); - -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Message list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); +} + +// Load more (on scroll up) +async function loadMoreMessages() { + try { + const messages = await messagesRequest.fetchPrevious(); + prependMessages(messages); + return messages; + } catch (error) { + console.log("Error:", error); + throw error; } -); +} ``` - - - -Base Message - -The list of messages received is in the form of objects of `BaseMessage` class. A BaseMessage can either be an object of the `TextMessage`, `MediaMessage`, `CustomMessage`, `Action` or `Call` class. You can use the `instanceOf` operator to check the type of object. - - - -## Message History - -*In other words, as a logged-in user, how do I fetch the complete message history?* +--- -### Fetch Message History of a particular one-on-one conversation +## Missed Messages -Using the `MessagesRequest` class and the filters for the `MessagesRequestBuilder` class as shown in the below code snippet, you can fetch the entire conversation between the logged in user and any particular user. For this use case, it is mandatory to set the UID parameter using the `setUID()` method of the builder. This UID is the unique id of the user for which the conversation needs to be fetched. +Fetch messages that arrived while your app was offline. - + ```javascript -let UID = "UID"; -let limit = 30; -let messagesRequest = new CometChat.MessagesRequestBuilder() +const UID = "user_id"; +const limit = 30; +const latestId = await CometChat.getLastDeliveredMessageId(); + +const messagesRequest = new CometChat.MessagesRequestBuilder() .setUID(UID) + .setMessageId(latestId) .setLimit(limit) .build(); -messagesRequest.fetchPrevious().then( - (messages) => { - console.log("Message list fetched:", messages); - }, - (error) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - - -```typescript -let UID: string = "UID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder().setUID(UID).setLimit(limit).build(); - -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Message list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); - } +messagesRequest.fetchNext().then( + (messages) => console.log("Missed messages:", messages), + (error) => console.log("Error:", error) ); ``` - - - - -Calling the `fetchPrevious()` method on the same object repeatedly allows you to fetch the entire conversation between the logged in user and the specified user. This can be implemented with upward scrolling to display the entire conversation. - -### Fetch Message History of a particular group conversation - -Using the `MessagesRequest` class and the filters for the `MessagesRequestBuilder` class as shown in the below code snippet, you can fetch the entire conversation for any group provided you have joined the group. For this use case, it is mandatory to set the GUID parameter using the `setGUID()` method of the builder. This GUID is the unique identifier of the Group for which the messages are to be fetched. - - - + ```javascript -let GUID = "GUID"; -let limit = 30; -let messagesRequest = new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setLimit(limit) - .build(); +async function fetchMissedMessages(UID) { + try { + const latestId = await CometChat.getLastDeliveredMessageId(); -messagesRequest.fetchPrevious().then( - (messages) => { - console.log("Message list fetched:", messages); - }, - (error) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - - -```typescript -let GUID: string = "GUID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setLimit(limit) + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(UID) + .setMessageId(latestId) + .setLimit(30) .build(); -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Message list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); + const messages = await messagesRequest.fetchNext(); + console.log("Missed messages:", messages); + return messages; + } catch (error) { + console.log("Error:", error); + throw error; } -); +} ``` - - -Calling the `fetchPrevious()` method on the same object repeatedly allows you to fetch the entire conversation for the group. This can be implemented with upward scrolling to display the entire conversation. - -## Search Messages - -In other words, as a logged-in user, how do I search a message? - -In order to do this, you can use the `setSearchKeyword()` method. This method accepts string as input. When set, the SDK will fetch messages which match the `searchKeyword`. - - -By default, the searchKey is searched only in message text. However, if you enable `Conversation & Advanced Search`, the searchKey will be searched in message text, file name, mentions & mime type of the file. - -The `Conversation & Advanced Search` is only available in `Advanced` & `Custom` [plans](https://www.cometchat.com/pricing). If you're already on one of these plans, please enable the `Conversation & Advanced Search` from [CometChat Dashboard](https://app.cometchat.com) (Open your app, navigate to Chats -> Settings -> General Configuration) - +Use `fetchNext()` for missed messages (messages after a specific ID) and `fetchPrevious()` for message history (messages before current view). -| Feature | Basic Search | Advance Search | -| ---------------- | ------------ | -------------- | -| Text search | ✅ | ✅ | -| File name search | ❌ | ✅ | -| Mentions search | ❌ | ✅ | -| Mime type search | ❌ | ✅ | - -### Search Messages in a particular one-on-one conversation +--- - - -```javascript -let UID = "UID"; -let limit = 30; -let searchKeyword = "Hello"; -let messagesRequest = new CometChat.MessagesRequestBuilder() - .setUID(UID) - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); +## Unread Messages -messagesRequest.fetchPrevious().then( - (messages) => { - console.log("Message list fetched:", messages); - }, - (error) => { - console.log("Message fetching failed with error:", error); - } -); -``` +Fetch only unread messages: - - - -```typescript -let UID: string = "UID", - limit: number = 30, - searchKeyword: string = "Hello", - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() + + + ```javascript + const messagesRequest = new CometChat.MessagesRequestBuilder() .setUID(UID) - .setLimit(limit) - .setSearchKeyword(searchKeyword) + .setUnread(true) + .setLimit(30) .build(); -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Message list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - - - -### Search Messages in a particular group conversation - - - -```javascript -let GUID = "GUID"; -let limit = 30; -let searchKeyword = "Hello"; -let messagesRequest = new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); - -messagesRequest.fetchPrevious().then( - (messages) => { - console.log("Message list fetched:", messages); - }, - (error) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - - -```typescript -let GUID: string = "GUID", - limit: number = 30, - searchKeyword: string = "Hello", - messagesRequest: CometChat.MessagesRequest = - new CometChat.MessagesRequestBuilder() + messagesRequest.fetchPrevious().then( + (messages) => console.log("Unread messages:", messages), + (error) => console.log("Error:", error) + ); + ``` + + + ```javascript + const messagesRequest = new CometChat.MessagesRequestBuilder() .setGUID(GUID) - .setLimit(limit) - .setSearchKeyword(searchKeyword) + .setUnread(true) + .setLimit(30) .build(); -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Message list fetched:", messages); - }, - (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); - } -); -``` - - - + messagesRequest.fetchPrevious().then( + (messages) => console.log("Unread messages:", messages), + (error) => console.log("Error:", error) + ); + ``` + -## Unread Message Count - -*In other words, as a logged-in user, how do I find out the number of unread messages that I have?* - -### Fetch Unread Message Count of a particular one-on-one conversation - -*In other words, how do I find out the number of unread messages I have from a particular user?* +--- -In order to get the unread message count for a particular user, you can use the `getUnreadMessageCountForUser()`. +## Search Messages -This method has the below two variants: +Search for messages containing specific text: - - ```javascript -CometChat.getUnreadMessageCountForUser(UID); -``` - - +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(UID) + .setSearchKeyword("hello") + .setLimit(30) + .build(); - -```typescript -let UID: string = "UID"; -CometChat.getUnreadMessageCountForUser(UID); +messagesRequest.fetchPrevious().then( + (messages) => console.log("Search results:", messages), + (error) => console.log("Error:", error) +); ``` - - - + +**Advanced Search** (available in Advanced & Custom plans) searches across message text, file names, mentions, and mime types. Enable it in Dashboard → Chats → Settings → General Configuration. + -If you wish to ignore the messages from blocked users you can use the below syntax setting the boolean parameter to true: +| Feature | Basic Search | Advanced Search | +|---------|--------------|-----------------| +| Text search | ✅ | ✅ | +| File name search | ❌ | ✅ | +| Mentions search | ❌ | ✅ | +| Mime type search | ❌ | ✅ | - - -```javascript -CometChat.getUnreadMessageCountForUser(UID, hideMessagesFromBlockedUsers); -``` - - - - -```typescript -let UID: string = "UID", - hideMessagesFromBlockedUsers: boolean = true; -CometChat.getUnreadMessageCountForUser(UID, hideMessagesFromBlockedUsers); -``` +--- - +## Unread Message Count - +### For a Specific User - - ```javascript -let UID = "UID"; - -CometChat.getUnreadMessageCountForUser(UID).then( - (unreadMessageCountObject) => { - console.log("Unread message count fetched", unreadMessageCountObject); - }, - (error) => { - console.log("Error in getting unread message count", error); - } -); -``` - - - - -```typescript -let UID: string = "UID"; - CometChat.getUnreadMessageCountForUser(UID).then( - (unreadMessageCount: Object) => { - console.log("Unread message count fetched", unreadMessageCount); - }, - (error: CometChat.CometChatException) => { - console.log("Error in getting unread message count", error); - } + (count) => console.log("Unread from user:", count), + (error) => console.log("Error:", error) ); ``` - - - - -It will return an object which will contain the UID as the key and the unread message count as the value. - -### Fetch Unread Message Count of a particular group conversation - -*In other words, how do I find out the number of unread messages I have in a single group?* - -In order to get the unread message count for a particular group, you can use the `getUnreadMessageCountForGroup()`. - -This method has the below two variants: - - - -```javascript -CometChat.getUnreadMessageCountForGroup(GUID); -``` - - - - -```typescript -let GUID: string = "GUID"; -CometChat.getUnreadMessageCountForGroup(GUID); -``` +### For a Specific Group - - - - -If you wish to ignore the messages from blocked users you can use the below syntax setting the boolean parameter to true: - - - ```javascript -CometChat.getUnreadMessageCountForGroup(GUID, hideMessagesFromBlockedUsers); -``` - - - - -```typescript -let GUID: string = "GUID", - hideMessagesFromBlockedUsers: boolean = true; -CometChat.getUnreadMessageCountForGroup(GUID, hideMessagesFromBlockedUsers); -``` - - - - - - - -```javascript -let GUID = "GUID"; - CometChat.getUnreadMessageCountForGroup(GUID).then( - (unreadMessageCountObject) => { - console.log("Unread message count fetched", unreadMessageCountObject); - }, - (error) => { - console.log("Error in getting unread message count", error); - } + (count) => console.log("Unread in group:", count), + (error) => console.log("Error:", error) ); ``` - - - -```typescript -let GUID: string = "GUID"; - -CometChat.getUnreadMessageCountForGroup(GUID).then( - (unreadMessageCount: Object) => { - console.log("Unread message count fetched", unreadMessageCount); - }, - (error: CometChat.CometChatException) => { - console.log("Error in getting unread message count", error); - } -); -``` - - - - - -It will return an object which will contain the GUID as the key and the unread message count as the value. - -### Fetch Unread Message Count of all one-on-one & group conversations - -*In other words, how do I find out the number of unread messages for every one-on-one and group conversation?* - -In order to get all the unread message count combined i.e unread message counts for all the users and groups, you can use the `getUnreadMessageCount()` method. - -This method has two variants: - - - -```javascript -CometChat.getUnreadMessageCount(); -``` - - - - -```typescript -CometChat.getUnreadMessageCount(); -``` - - - - - -If you wish to ignore the messages from blocked users you can use the below syntax setting the boolean parameter to true: - - - -```javascript -CometChat.getUnreadMessageCount(hideMessagesFromBlockedUsers); -``` - - - - -```typescript -let hideMessagesFromBlockedUsers: boolean = true; -CometChat.getUnreadMessageCount(hideMessagesFromBlockedUsers); -``` +### For All Conversations - - - - - - ```javascript CometChat.getUnreadMessageCount().then( - (unreadMessageCountObject) => { - console.log("Unread message count fetched", unreadMessageCountObject); + (count) => { + console.log("Users:", count.users); // { uid1: 5, uid2: 3 } + console.log("Groups:", count.groups); // { guid1: 10 } }, - (error) => { - console.log("Error in getting unread message count", error); - } + (error) => console.log("Error:", error) ); ``` - - - -```typescript -CometChat.getUnreadMessageCount().then( - (unreadMessageCount: Object) => { - console.log("Unread message count fetched", unreadMessageCount); - }, - (error: CometChat.CometChatException) => { - console.log("Error in getting unread message count", error); - } -); -``` - - - - - -It returns an object having two keys: - -1. users - The value for this key holds another object that holds the UID as key and their corresponding unread message count as value. -2. groups - The value for this key holds another object that holds the GUID as key and their corresponding unread message count as value. - -### Fetch Unread Message Count of all one-on-one conversations - -In order to fetch the unread message counts for just the users, you can use the `getUnreadMessageCountForAllUsers()` method. This method just like others has two variants: - - - -```javascript -CometChat.getUnreadMessageCountForAllUsers(); -``` - - - - -```typescript -CometChat.getUnreadMessageCountForAllUsers(); -``` - - - - - -If you wish to ignore the messages from blocked users you can use the below syntax setting the boolean parameter to true: - - - -```javascript -CometChat.getUnreadMessageCountForAllUsers(hideMessagesFromBlockedUsers); -``` - - - - -```typescript -let hideMessagesFromBlockedUsers: boolean = true; -CometChat.getUnreadMessageCountForAllUsers(hideMessagesFromBlockedUsers); -``` - - +### Exclude Blocked Users - - - - ```javascript -CometChat.getUnreadMessageCountForAllUsers().then( - (unreadMessageCountObject) => { - console.log("Unread message count fetched", unreadMessageCountObject); - }, - (error) => { - console.log("Error in getting unread message count", error); - } -); -``` +const hideBlockedUsers = true; - - - -```typescript -CometChat.getUnreadMessageCountForAllUsers().then( - (unreadMessageCount: Object) => { - console.log("Unread message count fetched", unreadMessageCount); - }, - (error: CometChat.CometChatException) => { - console.log("Error in getting unread message count", error); - } +CometChat.getUnreadMessageCount(hideBlockedUsers).then( + (count) => console.log("Unread count:", count) ); ``` - - - - -It returns an object which will contain the UID as the key and the unread message count as the value. - -### Fetch Unread Message Count of all group conversations +--- -In order to fetch the unread message counts for just the groups, you can use the `getUnreadMessageCountForAllGroups()` method. This method just like others has two variants: +## Filter Options + +The `MessagesRequestBuilder` supports various filters: + +| Method | Description | +|--------|-------------| +| `setUID(uid)` | Filter by user conversation | +| `setGUID(guid)` | Filter by group conversation | +| `setLimit(limit)` | Number of messages to fetch (max 100) | +| `setMessageId(id)` | Fetch messages around this ID | +| `setTimestamp(timestamp)` | Fetch messages around this time | +| `setUnread(true)` | Only unread messages | +| `setSearchKeyword(keyword)` | Search in message content | +| `setCategory(category)` | Filter by category (message, action, call, custom) | +| `setType(type)` | Filter by type (text, image, video, etc.) | +| `setTypes(types)` | Filter by multiple types | +| `setCategories(categories)` | Filter by multiple categories | +| `hideReplies(true)` | Exclude threaded replies | +| `hideDeletedMessages(true)` | Exclude deleted messages | +| `setTags(tags)` | Filter by message tags | +| `withTags(true)` | Include tags in response | +| `setMentionsWithTagInfo(true)` | Include mention details | +| `setMentionsWithBlockedInfo(true)` | Include blocked user info in mentions | + +### Example: Filter by Type - - ```javascript -CometChat.getUnreadMessageCountForAllGroups(); -``` - - - - -```typescript -CometChat.getUnreadMessageCountForAllGroups(); +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(UID) + .setLimit(30) + .setTypes(["image", "video"]) + .setCategories(["message"]) + .build(); ``` - - - - -If you wish to ignore the messages from blocked users you can use the below syntax setting the boolean parameter to true: +### Example: Exclude Replies and Deleted - - ```javascript -CometChat.getUnreadMessageCountForAllGroups(hideMessagesFromBlockedUsers); +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID(UID) + .setLimit(30) + .hideReplies(true) + .hideDeletedMessages(true) + .build(); ``` - - - -```typescript -let hideMessagesFromBlockedUsers: boolean = true; -CometChat.getUnreadMessageCountForAllGroups(hideMessagesFromBlockedUsers); -``` +--- - +## Message Object - +Messages are returned as `BaseMessage` objects. Use `instanceof` to determine the type: - - ```javascript -CometChat.getUnreadMessageCountForAllGroups().then( - (unreadMessageCountObject) => { - console.log("Unread message count fetched", unreadMessageCountObject); - }, - (error) => { - console.log("Error in getting unread message count", error); +messages.forEach((message) => { + if (message instanceof CometChat.TextMessage) { + console.log("Text:", message.getText()); + } else if (message instanceof CometChat.MediaMessage) { + console.log("Media URL:", message.getAttachment()?.getUrl()); + } else if (message instanceof CometChat.CustomMessage) { + console.log("Custom data:", message.getCustomData()); + } else if (message instanceof CometChat.Action) { + console.log("Action:", message.getAction()); } -); +}); ``` - +### Common Properties - -```typescript -CometChat.getUnreadMessageCountForAllGroups().then( - (unreadMessageCount: Object) => { - console.log("Unread message count fetched", unreadMessageCount); - }, - (error: CometChat.CometChatException) => { - console.log("Error in getting unread message count", error); - } -); -``` +| Property | Method | Description | +|----------|--------|-------------| +| ID | `getId()` | Unique message identifier | +| Sender | `getSender()` | User object of sender | +| Receiver | `getReceiver()` | User/Group object | +| Sent At | `getSentAt()` | Unix timestamp | +| Type | `getType()` | text, image, video, etc. | +| Category | `getCategory()` | message, action, call, custom | +| Read At | `getReadAt()` | When message was read | +| Delivered At | `getDeliveredAt()` | When message was delivered | +| Edited At | `getEditedAt()` | When message was edited | +| Deleted At | `getDeletedAt()` | When message was deleted | - +--- - +## React Implementation Example + +Here's a complete React hook for handling messages: + +```jsx +import { useEffect, useState, useCallback, useRef } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +export function useMessages(conversationId, conversationType = "user") { + const [messages, setMessages] = useState([]); + const [loading, setLoading] = useState(false); + const [hasMore, setHasMore] = useState(true); + const requestRef = useRef(null); + + // Initialize messages request + useEffect(() => { + const builder = new CometChat.MessagesRequestBuilder() + .setLimit(30); + + if (conversationType === "user") { + builder.setUID(conversationId); + } else { + builder.setGUID(conversationId); + } + + requestRef.current = builder.build(); + setMessages([]); + setHasMore(true); + + // Load initial messages + loadMessages(); + + // Setup real-time listener + const listenerID = `messages_${conversationId}`; + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: (message) => { + if (isRelevantMessage(message)) { + setMessages((prev) => [...prev, message]); + CometChat.markAsRead(message); + } + }, + onMediaMessageReceived: (message) => { + if (isRelevantMessage(message)) { + setMessages((prev) => [...prev, message]); + CometChat.markAsRead(message); + } + }, + onMessageEdited: (message) => { + setMessages((prev) => + prev.map((m) => (m.getId() === message.getId() ? message : m)) + ); + }, + onMessageDeleted: (message) => { + setMessages((prev) => + prev.map((m) => (m.getId() === message.getId() ? message : m)) + ); + } + }) + ); + + return () => { + CometChat.removeMessageListener(listenerID); + }; + }, [conversationId, conversationType]); + + const isRelevantMessage = (message) => { + const sender = message.getSender().getUid(); + const receiver = message.getReceiverId(); + return sender === conversationId || receiver === conversationId; + }; + + const loadMessages = useCallback(async () => { + if (!requestRef.current || loading || !hasMore) return; + + setLoading(true); + try { + const fetchedMessages = await requestRef.current.fetchPrevious(); + setMessages((prev) => [...fetchedMessages, ...prev]); + setHasMore(fetchedMessages.length === 30); + + // Mark last message as read + if (fetchedMessages.length > 0) { + CometChat.markAsRead(fetchedMessages[fetchedMessages.length - 1]); + } + } catch (error) { + console.error("Failed to load messages:", error); + } finally { + setLoading(false); + } + }, [loading, hasMore]); + + const sendMessage = useCallback(async (text) => { + const receiverType = conversationType === "user" + ? CometChat.RECEIVER_TYPE.USER + : CometChat.RECEIVER_TYPE.GROUP; + + const textMessage = new CometChat.TextMessage( + conversationId, + text, + receiverType + ); + + const sentMessage = await CometChat.sendMessage(textMessage); + setMessages((prev) => [...prev, sentMessage]); + return sentMessage; + }, [conversationId, conversationType]); + + return { + messages, + loading, + hasMore, + loadMore: loadMessages, + sendMessage + }; +} + +// Usage in component +function ChatScreen({ conversationId }) { + const { messages, loading, hasMore, loadMore, sendMessage } = useMessages(conversationId); + const [input, setInput] = useState(""); + + const handleSend = async () => { + if (!input.trim()) return; + await sendMessage(input); + setInput(""); + }; + + return ( +
+ {hasMore && } + {loading &&
Loading...
} + {messages.map((msg) => ( +
{msg.getText?.() || "Media message"}
+ ))} + setInput(e.target.value)} /> + +
+ ); +} +``` + +--- -It returns an object which will contain the GUID as the key and the unread message count as the value. +## Next Steps + + + + Send text, media, and custom messages + + + Build your recent chats list + + + Track delivery and read status + + + Organize discussions with threads + + diff --git a/sdk/javascript/recording.mdx b/sdk/javascript/recording.mdx index 214d56bc..7c593e94 100644 --- a/sdk/javascript/recording.mdx +++ b/sdk/javascript/recording.mdx @@ -1,130 +1,183 @@ --- -title: "Recording (Beta)" +title: "Recording" +description: "Record voice and video calls for playback, compliance, or archival" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Enable recording in call settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .showRecordingButton(true) // Show recording button in UI + .startRecordingOnCallStart(true) // Auto-start recording + .setCallListener(new CometChatCalls.OngoingCallListener({ + onRecordingStarted: (event) => console.log("Recording started"), + onRecordingStopped: (event) => console.log("Recording stopped") + })) + .build(); -This section will guide you to implement call recording feature for the voice and video calls. +// Manual recording control +CometChatCalls.startRecording(); +CometChatCalls.stopRecording(); -## Implementation +// Access recordings: Dashboard > Calls > View Recordings +``` + -Once you have decided to implement [Default Calling](/sdk/javascript/default-call) or [Direct Calling](/sdk/javascript/direct-call) calling and followed the steps to implement them. Just few additional listeners and methods will help you quickly implement call recording in your app. + +**Available via**: SDK | Dashboard + -You need to make changes in the CometChat.startCall method and add the required listeners for recording. Please make sure your callSettings is configured accordingly for [Default Calling](/sdk/javascript/default-call) or [Direct Calling](/sdk/javascript/direct-call). +Record your voice and video calls for playback, compliance, training, or archival purposes. -A basic example of how to make changes to implement recording for a direct call/ a default call: + +Recordings are stored and accessible from the [CometChat Dashboard](https://app.cometchat.com) under the Calls section. + + +## Prerequisites + +Before implementing recording, ensure you have: +1. Completed the [Calls SDK Setup](/sdk/javascript/calling-setup) +2. Implemented either [Ringing](/sdk/javascript/default-call) or [Call Session](/sdk/javascript/direct-call) calling + +## Implementation + +Add recording listeners to your call settings to receive recording state updates: -```js -// Add listeners onRecordingStarted and onRecordingStopped to the startCall method -const defaultLayout = true; -const audioOnly = false; - +```javascript const callListener = new CometChatCalls.OngoingCallListener({ - onRecordingStarted: (event) => - console.log("Listener => onRecordingStarted", event.user), - onRecordingStopped: (event) => - console.log("Listener => onRecordingStopped", event.user), + onRecordingStarted: (event) => { + console.log("Recording started by:", event.user.getName()); + // Update UI to show recording indicator + }, + onRecordingStopped: (event) => { + console.log("Recording stopped by:", event.user.getName()); + // Update UI to hide recording indicator + }, + // ... other listeners }); const callSettings = new CometChatCalls.CallSettingsBuilder() - .enableDefaultLayout(defaultLayout) - .setIsAudioOnlyCall(audioOnly) + .enableDefaultLayout(true) + .setIsAudioOnlyCall(false) + .showRecordingButton(true) // Show recording button in UI .setCallListener(callListener) .build(); -const htmlElement = document.getElementById("ELEMENT_ID"); +const htmlElement = document.getElementById("call-container"); CometChatCalls.startSession(callToken, callSettings, htmlElement); ``` - - ```typescript -// Add listeners onRecordingStarted and onRecordingStopped to the startCall method -const defaultLayout = true; -const audioOnly = false; - const callListener = new CometChatCalls.OngoingCallListener({ - onRecordingStarted: (event) => - console.log("Listener => onRecordingStarted", event.user), - onRecordingStopped: (event) => - console.log("Listener => onRecordingStopped", event.user), + onRecordingStarted: (event: any) => { + console.log("Recording started by:", event.user.getName()); + }, + onRecordingStopped: (event: any) => { + console.log("Recording stopped by:", event.user.getName()); + }, + // ... other listeners }); const callSettings = new CometChatCalls.CallSettingsBuilder() - .enableDefaultLayout(defaultLayout) - .setIsAudioOnlyCall(audioOnly) + .enableDefaultLayout(true) + .setIsAudioOnlyCall(false) + .showRecordingButton(true) .setCallListener(callListener) .build(); -const htmlElement = document.getElementById("ELEMENT_ID"); +const htmlElement = document.getElementById("call-container") as HTMLElement; CometChatCalls.startSession(callToken, callSettings, htmlElement); ``` - - -## Settings for call recording +## Recording Settings -The `CallSettings`class allows you to customise the overall calling experience. The properties for the call/conference can be set using the `CallSettingsBuilder` class. This will eventually give you and object of the `CallSettings` class which you can pass to the `startSession()` method to start the call. +Configure recording behavior using `CallSettingsBuilder`: -The options available for recording of calls are: +| Method | Description | Default | +|--------|-------------|---------| +| `showRecordingButton(boolean)` | Show/hide the recording button in the call UI | `false` | +| `startRecordingOnCallStart(boolean)` | Automatically start recording when call begins | `false` | -| Setting | Description | -| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `showRecordingButton(showRecordingButton: boolean)` | If set to `true` it displays the Recording button in the button Layout. if set to `false` it hides the Recording button in the button Layout. **Default value = false** | -| `startRecordingOnCallStart(startRecordingOnCallStart: boolean)` | If set to `true` call recording will start as soon as the call is started. if set to `false` call recording will not start as soon as the call is started. **Default value = false** | + + +```javascript +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .showRecordingButton(true) // Show recording button + .startRecordingOnCallStart(true) // Auto-start recording + .setCallListener(callListener) + .build(); +``` + + +```typescript +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .showRecordingButton(true) + .startRecordingOnCallStart(true) + .setCallListener(callListener) + .build(); +``` + + -For the use case where you wish to align your own custom buttons and not use the default layout provided by CometChat, you can embed the buttons in your layout and use the below methods to perform the corresponding operations: +## Manual Recording Control -### Start Recording +For custom UI implementations, use these methods to control recording programmatically: -You can use the startRecording() method to start call recording. +### Start Recording - + ```javascript CometChatCalls.startRecording(); ``` - - ```typescript CometChatCalls.startRecording(); ``` - - ### Stop Recording -You can use the stopRecording() method to stop call recording. - - + ```javascript CometChatCalls.stopRecording(); ``` - - ```typescript CometChatCalls.stopRecording(); ``` - - -## Downloading Recording +## Accessing Recordings -Currently, the call recordings are available on the [CometChat Dashboard](https://app.cometchat.com/signup) under the Calls Section. Recordings can be accessed after clicking on the three dots menu icon to expand the menu and then select "View Recordings". You can refer to the below screenshot. You can refer to the below screenshot. +Recordings are available in the [CometChat Dashboard](https://app.cometchat.com): + + + + Go to the Calls section in your dashboard + + + Locate the call you want to access recordings for + + + Click the three-dot menu icon and select "View Recordings" + + @@ -137,3 +190,14 @@ Currently, the call recordings are available on the [CometChat Dashboard](https: + +## Next Steps + + + + Retrieve call history and recordings programmatically + + + Add blur or custom backgrounds to video calls + + diff --git a/sdk/javascript/research.md b/sdk/javascript/research.md new file mode 100644 index 00000000..b10d4548 --- /dev/null +++ b/sdk/javascript/research.md @@ -0,0 +1,56 @@ +Making CometChat JavaScript SDK Docs AI‑Friendly & Developer‑Friendly + +This research compiles best practices for structuring and improving the CometChat JavaScript SDK documentation so that both novice developers and AI-powered coding assistants (GitHub Copilot, ChatGPT, Claude, etc.) can follow it smoothly. The recommendations below are grounded in evidence from the CometChat documentation. + +Provide a Clear, Linear “Happy Path” + +Developers and AI assistants need a predictable sequence to get a chat app running. The existing overview page presents a six‑step journey—get application keys, install the SDK, initialize it, create a user, log in, and optionally integrate UI kits or the chat widget . Preserve this linear outline and make each step explicit: + • Prerequisites and key concepts: Encourage readers to read the key concepts page first . Explain that only one app should be created for development and another for production, and that using different apps per platform prevents cross‑platform communication . + • Installation: Show how to install via npm install @cometchat/chat-sdk-javascript and import the SDK  or load it via a CDN script tag . Provide examples for both JavaScript and TypeScript. + • Initialization: Describe calling CometChat.init() and its required parameters (App ID and Region). Note when to call it (on app startup) and show handling success and failure  . + • User registration and login: Explain that CometChat doesn’t handle user management; you must create users via your own backend and then add them to CometChat . Provide code to create a user with createUser() , then log in once with login() . Highlight using CometChat.getLoggedinUser() to check if a session already exists . + • Messaging: Demonstrate sending text, media and custom messages using sendMessage() with the appropriate message objects . Include parameter tables so readers know what receiverID, messageText and receiverType mean . Show how to attach metadata to a message  and note that a TextMessage object is returned on success . For receiving messages, explain how to add and remove MessageListener objects   and how to fetch missed messages using MessagesRequestBuilder . + • Calling and UI kits: If documenting calling features, include steps for installing @cometchat/calls-sdk-javascript, initializing CometChatCalls, and passing App ID, Region and host . Show code for integrating UI kits or chat widgets and link to those sections. + +This “happy path” ensures that neither developers nor AI assistants have to guess the next step. + +Use Consistent Headings and Terminology + +AI assistants often navigate documentation via headings, so clear and consistent titles are essential. Use the same section names everywhere (e.g., “Overview,” “Get Your Application Keys,” “Initialize CometChat,” “Create User,” “Log In,” “Send Messages”). The existing overview page demonstrates this pattern ; apply it to all pages. Use the same terminology throughout—for instance, consistently refer to the Auth Token as “Auth Token” and the Auth Key as “Auth Key,” and avoid synonyms. Define acronyms (UID, GUID) once and link back whenever they appear . + +Emphasize Security and Best Practices + +AI assistants will relay whatever guidance appears in the docs, so be explicit about security and correct usage: + • Auth keys vs. Auth tokens: Describe the difference. Auth Keys are intended for development; Auth Tokens, generated via API, should be used in production . Provide steps for creating Auth Tokens on the server . + • UID/GUID formats: State that user IDs and group IDs may only contain alphanumeric characters, underscores and hyphens  ; they cannot contain spaces or other special characters. + • Rate limits: Include a clear explanation of rate limits. CometChat rate‑limits core operations (login, create/delete user, etc.) to 10 000 requests per minute and other operations to 20 000 per minute . Explain that exceeding the limit returns HTTP 429 with Retry‑After headers , and advise handling these errors gracefully. + • Session management: Remind readers to log in once per user session and to call CometChat.getLoggedinUser() before logging in again . Warn against storing the Auth Key in client‑side production code. + +Provide Complete, Copy‑Pasty Code Examples + +Every major method (initialization, user creation, login, sending messages, etc.) should come with complete code samples. The existing docs include both JavaScript and TypeScript examples for creating a user  and logging in . Always include placeholders (APP_ID, AUTH_KEY, UID, etc.) and comments explaining where to substitute real values . For frameworks like Next.js or NuxtJS, show how to dynamically import the SDK in a useEffect hook . Providing ready‑to‑copy snippets ensures AI tools reproduce the correct code. + +Include Parameter Tables and Callouts + +Follow each code example with a concise table describing each parameter and its constraints (as done in the messaging docs ). Use callouts (e.g., Note: or Warning:) for critical reminders, such as: + • Replace placeholders like APP_ID and REGION with your actual credentials . + • Call init() before any other SDK method . + • Remove listeners once you no longer need them . + +These explicit notes prevent misunderstandings and ensure AI assistants pass along correct practices. + +Interlink Related Pages and Provide a “What’s Next” Trail + +At the end of each page, link to the next logical topic. The overview page already lists follow‑up topics such as “Get your application keys,” “Add the dependency,” and so on . Extend this practice across messaging, calling and UI kit pages: after showing how to send a message, link to receiving or editing messages; after explaining how to create a user, link to group creation or user presence. Internal links help both humans and AI agents navigate the documentation. + +Document AI‑Agent‑Specific Features + +If your product includes AI agents or bots, dedicate a section to them. The AI Agents page explains that agents process user text, may invoke tools, and return structured agentic messages . It describes the event flow: a run starts, optional tool calls occur, the assistant reply is streamed, and the run finishes . It lists event types such as Run Start, Tool Call Start/End, Text Message Content, and Run Finished . Provide code showing how to register an AIAssistantListener and a MessageListener  . Include these details so AI assistants can correctly simulate agent interactions and developers can implement them. + +Explain Typical Workflows and Context + +Misunderstandings often arise when documentation omits the bigger picture. The key concepts page outlines a typical workflow: a user registers in your app, your server stores their data, you add them to CometChat via the API, then the user logs in to CometChat using the same UID . It also warns against creating separate apps per platform . Summarize these flows in diagrams or numbered lists so that both human readers and AI tools understand the full context. + +Conclusion + +Great documentation benefits both humans and AI. By structuring the CometChat JavaScript SDK docs with a clear step‑by‑step path, consistent headings and terminology, comprehensive code examples, explicit parameter descriptions, security warnings, internal links, AI‑specific guidance and contextual workflows, you ensure that novice developers and AI assistants can follow the documentation without confusion. This reduces support requests, shortens onboarding time, and enables correct integration on the first try. \ No newline at end of file diff --git a/sdk/javascript/resources-overview.mdx b/sdk/javascript/resources-overview.mdx index ea0d211b..bd1d7420 100644 --- a/sdk/javascript/resources-overview.mdx +++ b/sdk/javascript/resources-overview.mdx @@ -1,12 +1,103 @@ --- title: "Resources" sidebarTitle: "Overview" +description: "Essential references, guides, and tools for JavaScript SDK development" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Key listener types +CometChat.addMessageListener(id, listener); // Messages, typing, receipts +CometChat.addUserListener(id, listener); // User presence +CometChat.addGroupListener(id, listener); // Group events +CometChat.addCallListener(id, listener); // Call events +CometChat.addConnectionListener(id, listener); // WebSocket status +CometChat.addLoginListener(id, listener); // Auth state -We have a number of resources that will help you while integrating CometChat in your app. +// Message categories +CometChat.CATEGORY_MESSAGE // text, image, video, audio, file +CometChat.CATEGORY_CUSTOM // custom types +CometChat.CATEGORY_ACTION // system events +CometChat.CATEGORY_CALL // call messages +CometChat.CATEGORY_INTERACTIVE // forms, cards +``` + -You can begin with the [all real-time listeners](/sdk/javascript/all-real-time-listeners) guide. +Access comprehensive resources to help you build, debug, and optimize your CometChat integration. -If you're upgrading from v2, we recommend reading our [Upgrading from v3](/sdk/javascript/upgrading-from-v3) guide. +## Quick Reference + + + + Complete reference for all event listeners available in the SDK + + + Understand message types, properties, and hierarchy + + + API rate limits and best practices for high-volume apps + + + Latest SDK updates, features, and bug fixes + + + +## Migration & Upgrades + + + Step-by-step guide to migrate from SDK v3 to v4 + + +## Event Listeners Reference + +The SDK provides real-time listeners for all chat events: + +| Listener Type | Purpose | Key Events | +|---------------|---------|------------| +| Message Listener | Incoming messages | `onTextMessageReceived`, `onMediaMessageReceived` | +| User Listener | User status changes | `onUserOnline`, `onUserOffline` | +| Group Listener | Group updates | `onGroupMemberJoined`, `onGroupMemberLeft` | +| Call Listener | Call events | `onIncomingCallReceived`, `onOutgoingCallAccepted` | +| Connection Listener | WebSocket status | `onConnected`, `onDisconnected` | +| Login Listener | Auth state | `onLoginSuccess`, `onLogout` | + +## External Resources + + + + Source code, issues, and contributions + + + Package details and version history + + + +## Getting Help + + + + Start with the [SDK Overview](/sdk/javascript/overview) for a complete guide to all features. + + + + Explore our [sample applications](https://github.com/cometchat) on GitHub for working implementations. + + + + Contact [CometChat Support](https://help.cometchat.com) for technical assistance. + + + +## Next Steps + + + + Master all event listeners + + + Understand message hierarchy + + diff --git a/sdk/javascript/retrieve-conversations.mdx b/sdk/javascript/retrieve-conversations.mdx index a58ef59d..c6cb78cf 100644 --- a/sdk/javascript/retrieve-conversations.mdx +++ b/sdk/javascript/retrieve-conversations.mdx @@ -1,624 +1,710 @@ --- title: "Retrieve Conversations" +description: "Fetch and manage conversation lists for your chat UI" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Fetch conversations (recent chats) +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .build(); +const conversations = await conversationsRequest.fetchNext(); -Conversations provide the last messages for every one-on-one and group conversation the logged-in user is a part of. This makes it easy for you to build a **Recent Chat** list. +// Get single conversation +const conversation = await CometChat.getConversation("user_uid", "user"); -## Retrieve List of Conversations +// Filter by type (user or group) +const request = new CometChat.ConversationsRequestBuilder() + .setConversationType("user") // or "group" + .build(); -*In other words, as a logged-in user, how do I retrieve the latest conversations that I've been a part of?* +// Unread conversations only +const request = new CometChat.ConversationsRequestBuilder() + .setUnread(true) + .build(); -To fetch the list of conversations, you can use the `ConversationsRequest` class. To use this class i.e. to create an object of the `ConversationsRequest` class, you need to use the `ConversationsRequestBuilder` class. The `ConversationsRequestBuilder` class allows you to set the parameters based on which the conversations are to be fetched. +// Search conversations +const request = new CometChat.ConversationsRequestBuilder() + .setSearchKeyword("John") + .build(); -The `ConversationsRequestBuilder` class allows you to set the below parameters: +// Tag a conversation +await CometChat.tagConversation("user_uid", "user", ["archived", "important"]); -### Set Limit +// Convert message to conversation (for real-time updates) +const conversation = await CometChat.CometChatHelper + .getConversationFromMessage(message); +``` + -This method sets the limit i.e. the number of conversations that should be fetched in a single iteration. + +**Available via**: SDK | REST API | UI Kits + - - -```javascript -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .build(); -``` +Conversations represent chat threads between users or within groups. Use them to build your "Recent Chats" or "Inbox" view. - +--- - -```typescript -let limit: number = 30, - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .build(); -``` +## Fetch Conversations - +Use `ConversationsRequest` to retrieve the logged-in user's conversations: + + + ```javascript + const limit = 30; + + const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(limit) + .build(); + + conversationsRequest.fetchNext().then( + (conversations) => { + console.log("Conversations:", conversations); + }, + (error) => { + console.log("Error:", error); + } + ); + ``` + + + ```typescript + const limit: number = 30; + + const conversationsRequest: CometChat.ConversationsRequest = + new CometChat.ConversationsRequestBuilder() + .setLimit(limit) + .build(); + + conversationsRequest.fetchNext().then( + (conversations: CometChat.Conversation[]) => { + console.log("Conversations:", conversations); + }, + (error: CometChat.CometChatException) => { + console.log("Error:", error); + } + ); + ``` + + + ```javascript + async function fetchConversations(limit = 30) { + const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(limit) + .build(); + + try { + const conversations = await conversationsRequest.fetchNext(); + console.log(`Fetched ${conversations.length} conversations`); + return conversations; + } catch (error) { + console.error("Failed to fetch conversations:", error); + throw error; + } + } + + // Usage + const conversations = await fetchConversations(); + ``` + -### Set Conversation Type - -This method can be used to fetch user or group conversations specifically. The `conversationType` variable can hold one of the below two values: + +Maximum of 50 conversations can be fetched at once. + -* user - Only fetches user conversation. -* group - Only fetches group conversations. +### Pagination -If none is set, the list of conversations will include both user and group conversations. +Call `fetchNext()` repeatedly to load more conversations: - + ```javascript -let limit = 30; -let conversationType = "group"; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setConversationType(conversationType) +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) .build(); -``` - +// Initial load +conversationsRequest.fetchNext().then((conversations) => { + displayConversations(conversations); +}); - -```typescript -let limit: number = 30, - conversationType: string = "group", - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setConversationType(conversationType) - .build(); +// Load more (on scroll) +function loadMore() { + conversationsRequest.fetchNext().then((conversations) => { + appendConversations(conversations); + }); +} ``` - - - - -### With User and Group Tags - -This method can be used to fetch the user/group tags in the `Conversation` Object. By default the value is `false`. - - - + ```javascript -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .withUserAndGroupTags(true) +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) .build(); -``` - - - -```typescript -let limit: number = 30, - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .withUserAndGroupTags(true) - .build(); +// Initial load +async function loadInitialConversations() { + try { + const conversations = await conversationsRequest.fetchNext(); + displayConversations(conversations); + return conversations; + } catch (error) { + console.log("Error:", error); + throw error; + } +} + +// Load more (on scroll) +async function loadMore() { + try { + const conversations = await conversationsRequest.fetchNext(); + appendConversations(conversations); + return conversations; + } catch (error) { + console.log("Error:", error); + throw error; + } +} ``` - - -### Set User Tags - -This method fetches user conversations that have the specified tags. - - - -```js -let limit = 30; -let userTags = ["tag1"]; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setUserTags(userTags) - .build(); -``` - - - - -```typescript -let limit: number = 30, - userTags: Array = ["tag1"], - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setUserTags(userTags) - .build(); -``` - - +--- - +## Filter Options -### Set Group Tags +### By Conversation Type -This method fetches group conversations that have the specified tags. +Fetch only user or group conversations: - -```js -let limit = 30; -let groupTags = ["tag1"]; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setGroupTags(groupTags) - .build(); -``` - - - - -```typescript -let limit: number = 30, - groupTags: Array = ["tag1"], - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setGroupTags(groupTags) - .build(); -``` - - - + + ```javascript + const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setConversationType("user") + .build(); + ``` + + + ```javascript + const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setConversationType("group") + .build(); + ``` + -### With Tags +### By Tags -This method makes sure that the tags associated with the conversations are returned along with the other details of the conversations. The default value for this parameter is `false` +Filter conversations by tags: - - ```javascript -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .withTags(true) +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setTags(["archived", "important"]) .build(); ``` - - - -```typescript -let limit: number = 30, -conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .withTags(true) - .build(); -``` - - - - - -### Set Tags +### By User Tags -This method helps you fetch the conversations based on the specified tags. +Filter user conversations by user tags: - - ```javascript -let limit = 30; -let tags = ["archivedChat"]; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setTags(tags) +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setUserTags(["premium", "verified"]) .build(); ``` - +### By Group Tags - -```typescript -let limit: number = 30, - tags: Array = ["archivedChat"], - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setTags(tags) - .build(); -``` - - - - +Filter group conversations by group tags: -### Include Blocked Users - -This method helps you fetch the conversations of users whom the logged-in user has blocked. - - - -```js -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setIncludeBlockedUsers(true) +```javascript +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setGroupTags(["public", "official"]) .build(); ``` - +### Unread Only - -```typescript -let limit: number = 30, - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setIncludeBlockedUsers(true) - .build(); -``` + +Requires **Conversation & Advanced Search** feature (Advanced & Custom plans). Enable in Dashboard → Chats → Settings → General Configuration. + - - - - -### With Blocked Info - -This method can be used to fetch the blocked information of the blocked user in the `ConversationWith` object. - - - -```js -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setWithBlockedInfo(true) +```javascript +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setUnread(true) .build(); ``` - - - -```typescript -let limit: number = 30, - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setWithBlockedInfo(true) - .build(); -``` - - - - - ### Search Conversations -This method helps you search a conversation based on User or Group name. + +Requires **Conversation & Advanced Search** feature. + - - -This feature is only available with `Conversation & Advanced Search`. The `Conversation & Advanced Search` is only available in `Advanced` & `Custom` [plans](https://www.cometchat.com/pricing). If you're already on one of these plans, please enable the `Conversation & Advanced Search` from [CometChat Dashboard](https://app.cometchat.com) (Open your app, navigate to Chats -> Settings -> General Configuration) - - +Search by user or group name: - - -```js -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setSearchKeyword("Hiking") +```javascript +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setSearchKeyword("John") .build(); ``` - - - -```typescript -let limit: number = 30, - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setSearchKeyword("Hiking") - .build(); -``` - - - - - -### Unread Conversations - -This method helps you fetch unread conversations. - - - -This feature is only available with `Conversation & Advanced Search`. The `Conversation & Advanced Search` is only available in `Advanced` & `Custom` [plans](https://www.cometchat.com/pricing). If you're already on one of these plans, please enable the `Conversation & Advanced Search` from [CometChat Dashboard](https://app.cometchat.com) (Open your app, navigate to Chats -> Settings -> General Configuration) +### Include Blocked Users - +By default, conversations with blocked users are hidden: - - -```js -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setUnread(true) +```javascript +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setIncludeBlockedUsers(true) .build(); ``` - - - -```typescript -let limit: number = 30, - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setUnread(true) - .build(); -``` - - - - - -### Hide Agentic Conversations +### With Blocked Info -This method allows you to exclude agent conversations from the conversation list. When set to `true`, conversations with AI agents will be filtered out. +Include block status in the response: - - -```js -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setHideAgentic(true) +```javascript +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setWithBlockedInfo(true) .build(); ``` - +### Include Tags in Response - -```typescript -let limit: number = 30, - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setHideAgentic(true) - .build(); -``` - - - - - -### Only Agentic Conversations - -This method allows you to fetch only agent conversations. When set to `true`, only conversations with AI agents will be returned in the list. - - - -```js -let limit = 30; -let conversationRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setOnlyAgentic(true) +```javascript +const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .withTags(true) + .withUserAndGroupTags(true) .build(); ``` - - - -```typescript -let limit: number = 30, - conversationRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .setOnlyAgentic(true) - .build(); -``` +### AI Agent Conversations - +Filter or exclude AI agent conversations: + + + ```javascript + const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setHideAgentic(true) + .build(); + ``` + + + ```javascript + const conversationsRequest = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .setOnlyAgentic(true) + .build(); + ``` + - + +`setHideAgentic()` and `setOnlyAgentic()` are mutually exclusive. Use only one per request. + -The `setHideAgentic()` and `setOnlyAgentic()` methods are mutually exclusive. You should only use one of them in a single request builder instance. - - - -Finally, once all the parameters are set to the builder class, you need to call the `build()` method to get the object of the `ConversationsRequest` class. +--- -Once you have the object of the `ConversationsRequest` class, you need to call the `fetchNext()` method. Calling this method will return a list of `Conversation` objects containing X number of users depending on the limit set. +## Get Single Conversation -A Maximum of only 50 Conversations can be fetched at once. +Fetch a specific conversation: - -```javascript -let limit = 30; -let conversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .build(); - -conversationsRequest.fetchNext().then( - (conversationList) => { - console.log("Conversations list received:", conversationList); - }, - (error) => { - console.log("Conversations list fetching failed with error:", error); - } -); -``` - - - - -```typescript -let limit: number = 30, - conversationsRequest: CometChat.ConversationsRequest = new CometChat.ConversationsRequestBuilder() - .setLimit(limit) - .build(); - -conversationsRequest.fetchNext().then( - (conversationList: CometChat.Conversation[]) => { - console.log("Conversations list received:", conversationList); - }, - (error: CometChat.CometChatException) => { - console.log("Conversations list fetching failed with error:", error); - } -); -``` - - - + + ```javascript + const conversationWith = "user_uid"; + const conversationType = "user"; + + CometChat.getConversation(conversationWith, conversationType).then( + (conversation) => { + console.log("Conversation:", conversation); + }, + (error) => { + console.log("Error:", error); + } + ); + ``` + + + ```javascript + const conversationWith = "group_guid"; + const conversationType = "group"; + + CometChat.getConversation(conversationWith, conversationType).then( + (conversation) => { + console.log("Conversation:", conversation); + }, + (error) => { + console.log("Error:", error); + } + ); + ``` + + + ```javascript + async function getConversation(conversationWith, conversationType) { + try { + const conversation = await CometChat.getConversation( + conversationWith, + conversationType + ); + console.log("Conversation:", conversation); + return conversation; + } catch (error) { + console.error("Failed to get conversation:", error); + throw error; + } + } + + // Usage + const userConversation = await getConversation("user_uid", "user"); + const groupConversation = await getConversation("group_guid", "group"); + ``` + -The `Conversation` Object consists of the following fields: - -| Field | Information | -| ------------------ | ----------------------------------------------------------------- | -| conversationId | ID of the conversation. | -| conversationType | Type of conversation. (user/group) | -| lastMessage | Last message the conversation. | -| conversationWith | User or Group object containing the details of the user or group. | -| unreadMessageCount | Unread message count for the conversation. | - -## Tag Conversation - -*In other words, as a logged-in user, how do I tag a conversation?* - -To tag a specific conversation, you can use the `tagConversation()` method. The `tagConversation()` method accepts three parameters. - -1. `conversationWith`: UID/GUID of the user/group whose conversation you want to fetch. - -2. `conversationType`: The `conversationType` variable can hold one of the below two values: +--- - 1. user - Only fetches user conversation. - 2. group - Only fetches group conversations. +## Tag a Conversation -3. `tags`: The `tags` variable will be a list of tags you want to add to a conversation. +Add tags to organize conversations (e.g., archive, pin, categorize): - + ```javascript -let tags = ["archivedChat"]; +const conversationWith = "user_uid"; +const conversationType = "user"; +const tags = ["archived", "important"]; -CometChat.tagConversation("conversationWith", "conversationType", tags).then( +CometChat.tagConversation(conversationWith, conversationType, tags).then( (conversation) => { - console.log("conversation", conversation); + console.log("Tagged conversation:", conversation); }, (error) => { - console.log("error while fetching a conversation", error); + console.log("Error:", error); } ); ``` - - ```typescript -let conversationWith: string = "UID", - tags: Array = ["archivedChat"], - conversationType: string = "user"; +const conversationWith: string = "user_uid"; +const conversationType: string = "user"; +const tags: string[] = ["archived", "important"]; CometChat.tagConversation(conversationWith, conversationType, tags).then( (conversation: CometChat.Conversation) => { - console.log("conversation", conversation); + console.log("Tagged conversation:", conversation); }, (error: CometChat.CometChatException) => { - console.log("error while fetching a conversation", error); + console.log("Error:", error); } ); ``` - + +```javascript +async function tagConversation(conversationWith, conversationType, tags) { + try { + const conversation = await CometChat.tagConversation( + conversationWith, + conversationType, + tags + ); + console.log("Tagged conversation:", conversation); + return conversation; + } catch (error) { + console.error("Failed to tag conversation:", error); + throw error; + } +} +// Usage +await tagConversation("user_uid", "user", ["archived", "important"]); +``` + - -The tags for conversations are one-way. This means that if user A tags a conversation with user B, that tag will be applied to that conversation only for user A. - +Conversation tags are user-specific. If User A tags a conversation with User B, only User A sees that tag. -## Retrieve Single Conversation - -*In other words, as a logged-in user, how do I retrieve a specific conversation?* - -To fetch a specific conversation, you can use the `getConversation` method. The `getConversation` method accepts two parameters. - -1. `conversationWith`: UID/GUID of the user/group whose conversation you want to fetch. +--- -2. `conversationType`: The `conversationType` variable can hold one of the below two values: +## Convert Message to Conversation - 1. user - Only fetches user conversation. - 2. group - Only fetches group conversations. +When receiving real-time messages, convert them to conversation objects for your UI: - + ```javascript -CometChat.getConversation("conversationWith", "conversationType").then( +CometChat.CometChatHelper.getConversationFromMessage(message).then( (conversation) => { - console.log("conversation", conversation); + console.log("Conversation:", conversation); + // Update your conversation list }, (error) => { - console.log("error while fetching a conversation", error); + console.log("Error:", error); } ); ``` - - ```typescript -let conversationWith: string = "UID", - conversationType: string = "user"; - -CometChat.getConversation(conversationWith, conversationType).then( +CometChat.CometChatHelper.getConversationFromMessage(message).then( (conversation: CometChat.Conversation) => { - console.log("conversation", conversation); + console.log("Conversation:", conversation); }, (error: CometChat.CometChatException) => { - console.log("error while fetching a conversation", error); + console.log("Error:", error); } ); ``` - + +```javascript +async function convertMessageToConversation(message) { + try { + const conversation = await CometChat.CometChatHelper + .getConversationFromMessage(message); + console.log("Conversation:", conversation); + return conversation; + } catch (error) { + console.error("Failed to convert message:", error); + throw error; + } +} +// Usage in message listener +const conversation = await convertMessageToConversation(receivedMessage); +``` + -## Convert Messages to Conversations + +The converted conversation won't include `unreadMessageCount` or `tags`. Manage unread counts client-side. + -As per our [receive messages](/sdk/javascript/receive-message) guide, for real-time messages, you will always receive `Message` objects and not `Conversation` objects. Thus, you will need a mechanism to convert the Message object to the `Conversation` object. You can use the `getConversationFromMessage(BaseMessage message)` of the `CometChatHelper` class. +--- - - -```javascript -CometChat.CometChatHelper.getConversationFromMessage(message).then( - (conversation) => { - console.log("Conversation Object", conversation); - }, (error) => { - console.log("Error while converting message object", error); - } -); -``` +## Conversation Object - +| Property | Method | Description | +|----------|--------|-------------| +| ID | `getConversationId()` | Unique conversation identifier | +| Type | `getConversationType()` | `user` or `group` | +| Last Message | `getLastMessage()` | Most recent message object | +| Conversation With | `getConversationWith()` | User or Group object | +| Unread Count | `getUnreadMessageCount()` | Number of unread messages | +| Tags | `getTags()` | Array of conversation tags | +| Updated At | `getUpdatedAt()` | Last activity timestamp | - -```typescript -let message: CometChat.TextMessage | CometChat.MediaMessage | CometChat.CustomMessage; +### Example: Display Conversation List -CometChat.CometChatHelper.getConversationFromMessage(message).then( - (conversation: CometChat.Conversation) => { - console.log("Conversation Object", conversation); - },(error: CometChat.CometChatException) => { - console.log("Error while converting message object", error); - } -); +```javascript +conversations.forEach((conversation) => { + const name = conversation.getConversationType() === "user" + ? conversation.getConversationWith().getName() + : conversation.getConversationWith().getName(); + + const lastMessage = conversation.getLastMessage(); + const unreadCount = conversation.getUnreadMessageCount(); + + console.log(`${name}: ${lastMessage?.getText()} (${unreadCount} unread)`); +}); ``` - +--- - +## All Filter Options + +| Method | Description | +|--------|-------------| +| `setLimit(limit)` | Number of conversations (max 50) | +| `setConversationType(type)` | `user` or `group` | +| `setTags(tags)` | Filter by conversation tags | +| `setUserTags(tags)` | Filter by user tags | +| `setGroupTags(tags)` | Filter by group tags | +| `withTags(true)` | Include tags in response | +| `withUserAndGroupTags(true)` | Include user/group tags | +| `setUnread(true)` | Only unread conversations | +| `setSearchKeyword(keyword)` | Search by name | +| `setIncludeBlockedUsers(true)` | Include blocked users | +| `setWithBlockedInfo(true)` | Include block status | +| `setHideAgentic(true)` | Exclude AI agent conversations | +| `setOnlyAgentic(true)` | Only AI agent conversations | - +--- -While converting the `Message` object to the `Conversation` object, the `unreadMessageCount` & `tags` will not be available in the `Conversation` object. The unread message count needs to be managed in your client-side code. +## React Implementation Example + +Here's a complete React hook for managing conversations: + +```jsx +import { useEffect, useState, useCallback, useRef } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +export function useConversations() { + const [conversations, setConversations] = useState([]); + const [loading, setLoading] = useState(false); + const [hasMore, setHasMore] = useState(true); + const requestRef = useRef(null); + + // Initialize and load conversations + useEffect(() => { + requestRef.current = new CometChat.ConversationsRequestBuilder() + .setLimit(30) + .build(); + + loadConversations(); + + // Listen for new messages to update conversation list + const listenerID = "CONVERSATION_LISTENER"; + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: updateConversationFromMessage, + onMediaMessageReceived: updateConversationFromMessage, + onCustomMessageReceived: updateConversationFromMessage + }) + ); + + return () => { + CometChat.removeMessageListener(listenerID); + }; + }, []); + + const updateConversationFromMessage = async (message) => { + try { + const conversation = await CometChat.CometChatHelper + .getConversationFromMessage(message); + + setConversations((prev) => { + // Remove existing conversation if present + const filtered = prev.filter( + (c) => c.getConversationId() !== conversation.getConversationId() + ); + // Add updated conversation at the top + return [conversation, ...filtered]; + }); + } catch (error) { + console.error("Failed to update conversation:", error); + } + }; + + const loadConversations = useCallback(async () => { + if (!requestRef.current || loading || !hasMore) return; + + setLoading(true); + try { + const fetched = await requestRef.current.fetchNext(); + setConversations((prev) => [...prev, ...fetched]); + setHasMore(fetched.length === 30); + } catch (error) { + console.error("Failed to load conversations:", error); + } finally { + setLoading(false); + } + }, [loading, hasMore]); + + const markAsRead = useCallback(async (conversation) => { + const conversationWith = conversation.getConversationType() === "user" + ? conversation.getConversationWith().getUid() + : conversation.getConversationWith().getGuid(); + + await CometChat.markConversationAsRead( + conversationWith, + conversation.getConversationType() + ); + + // Update local state + setConversations((prev) => + prev.map((c) => { + if (c.getConversationId() === conversation.getConversationId()) { + // Create updated conversation with 0 unread count + // Note: In practice, you'd refetch or update the object + return c; + } + return c; + }) + ); + }, []); + + return { + conversations, + loading, + hasMore, + loadMore: loadConversations, + markAsRead + }; +} + +// Usage in component +function ConversationList({ onSelect }) { + const { conversations, loading, hasMore, loadMore } = useConversations(); + + return ( +
+ {conversations.map((conv) => { + const partner = conv.getConversationWith(); + const lastMessage = conv.getLastMessage(); + const unread = conv.getUnreadMessageCount(); + + return ( +
onSelect(conv)}> + {partner.getName()} +
+ {partner.getName()} +

{lastMessage?.getText?.() || "No messages"}

+
+ {unread > 0 && {unread}} +
+ ); + })} + {hasMore && ( + + )} +
+ ); +} +``` -
+--- + +## Next Steps + + + + Handle real-time and historical messages + + + Clear conversation history + + + Show when users are typing + + + Track message delivery and read status + + diff --git a/sdk/javascript/retrieve-group-members.mdx b/sdk/javascript/retrieve-group-members.mdx index 3e21b909..d926945c 100644 --- a/sdk/javascript/retrieve-group-members.mdx +++ b/sdk/javascript/retrieve-group-members.mdx @@ -1,189 +1,206 @@ --- title: "Retrieve Group Members" +sidebarTitle: "Retrieve Members" +description: "Fetch and search members of a group" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Fetch group members +const membersRequest = new CometChat.GroupMembersRequestBuilder("group_guid") + .setLimit(30) + .build(); +const members = await membersRequest.fetchNext(); -## Retrieve the List of Group Members - -In order to fetch the list of groups members for a group, you can use the `GroupMembersRequest` class. To use this class i.e to create an object of the GroupMembersRequest class, you need to use the `GroupMembersRequestBuilder` class. The `GroupMembersRequestBuilder` class allows you to set the parameters based on which the groups are to be fetched. - -The `GroupMembersRequestBuilder` class allows you to set the below parameters: - -The GUID of the group for which the members are to be fetched must be specified in the constructor of the `GroupMembersRequestBuilder` class. +// Search members +const membersRequest = new CometChat.GroupMembersRequestBuilder("group_guid") + .setSearchKeyword("john") + .build(); -### Set Limit +// Filter by scope (admin, moderator, participant) +const membersRequest = new CometChat.GroupMembersRequestBuilder("group_guid") + .setScopes(["admin", "moderator"]) + .build(); -This method sets the limit i.e. the number of members that should be fetched in a single iteration. +// Filter online members +const membersRequest = new CometChat.GroupMembersRequestBuilder("group_guid") + .setStatus(CometChat.USER_STATUS.ONLINE) + .build(); - - -```javascript -let GUID = "GUID"; -let limit = 30; -let groupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .build(); +// Member properties: uid, name, avatar, scope, status, joinedAt ``` + - - - -```typescript -let GUID: string = "GUID"; -let limit: number = 30; -let groupMembersRequest: CometChat.GroupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .build(); -``` +Retrieve the list of members in a group with various filtering options. - + +**Availability**: SDK, API, UI Kits + -
+--- -### Set Search Keyword +## Fetch Group Members -This method allows you to set the search string based on which the group members are to be fetched. +Use `GroupMembersRequestBuilder` to fetch members: - + ```javascript -let GUID = "GUID"; -let limit = 30; -let searchKeyword = "super"; -let groupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); -``` +const GUID = "group-123"; +const limit = 30; - - - -```typescript -let GUID: string = "GUID"; -let limit: number = 30; -let searchKeyword: string = "super"; -let groupMembersRequest: CometChat.GroupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) +const membersRequest = new CometChat.GroupMembersRequestBuilder(GUID) .setLimit(limit) - .setSearchKeyword(searchKeyword) .build(); -``` - - - - -### Set Scopes - -This method allows you to fetch group members based on multiple scopes. - - - -```javascript -let GUID = "GUID"; -let limit = 30; -let scopes = ["admin", "moderator"]; -let groupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .setScopes(scopes) - .build(); +membersRequest.fetchNext().then( + (members) => { + members.forEach((member) => { + console.log("Name:", member.getName()); + console.log("Scope:", member.getScope()); + }); + }, + (error) => console.log("Failed:", error) +); ``` - - ```typescript -let GUID: string = "GUID"; -let limit: number = 30; -let scopes: Array = ["admin", "moderator"]; -let groupMembersRequest: CometChat.GroupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .setScopes(scopes) - .build(); +const GUID: string = "group-123"; +const limit: number = 30; + +const membersRequest: CometChat.GroupMembersRequest = + new CometChat.GroupMembersRequestBuilder(GUID) + .setLimit(limit) + .build(); + +membersRequest.fetchNext().then( + (members: CometChat.GroupMember[]) => { + members.forEach((member) => { + console.log("Name:", member.getName()); + console.log("Scope:", member.getScope()); + }); + }, + (error: CometChat.CometChatException) => console.log("Failed:", error) +); +``` + + +```javascript +const getGroupMembers = async () => { + try { + const GUID = "group-123"; + const limit = 30; + + const membersRequest = new CometChat.GroupMembersRequestBuilder(GUID) + .setLimit(limit) + .build(); + + const members = await membersRequest.fetchNext(); + members.forEach((member) => { + console.log("Name:", member.getName()); + console.log("Scope:", member.getScope()); + }); + } catch (error) { + console.log("Failed:", error); + } +}; ``` - - -### Set Status +### Builder Options -The status based on which the group members are to be fetched. The status parameter can contain one of the below two values: +| Method | Description | +|--------|-------------| +| `setLimit(limit)` | Number of members per request (max 100) | +| `setSearchKeyword(keyword)` | Search members by name | +| `setScopes(scopes)` | Filter by member scopes | +| `setStatus(status)` | Filter by online/offline status | -* CometChat.USER_STATUS.ONLINE - will return the list of only online group members. -* CometChat.USER_STATUS.OFFLINE - will return the list of only offline group members. +--- -If this parameter is not set, will return all the group members regardless of their status. +## Search Members - - ```javascript -let GUID = "GUID"; -let limit = 30; -let groupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .setStatus(CometChat.USER_STATUS.ONLINE) - .build(); +const membersRequest = new CometChat.GroupMembersRequestBuilder("group-123") + .setLimit(30) + .setSearchKeyword("john") + .build(); + +membersRequest.fetchNext().then( + (members) => console.log("Search results:", members), + (error) => console.log("Failed:", error) +); ``` - +--- - -```typescript -let GUID: string = "GUID"; -let limit: number = 30; -let groupMembersRequest: CometChat.GroupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .setStatus(CometChat.USER_STATUS.ONLINE) +## Filter by Scope + +Get only admins and moderators: + +```javascript +const membersRequest = new CometChat.GroupMembersRequestBuilder("group-123") + .setLimit(30) + .setScopes(["admin", "moderator"]) .build(); -``` - +membersRequest.fetchNext().then( + (members) => console.log("Admins and moderators:", members), + (error) => console.log("Failed:", error) +); +``` - +--- -Finally, once all the parameters are set to the builder class, you need to call the build() method to get the object of the `GroupMembersRequest` class. +## Filter by Status -Once you have the object of the `GroupMembersRequest` class, you need to call the `fetchNext()` method. Calling this method will return a list of `GroupMember` objects containing n number of members where n is the limit set in the builder class. +Get only online members: - - ```javascript -let GUID = "GUID"; -let limit = 30; -let groupMemberRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .build(); - -groupMemberRequest.fetchNext().then( -groupMembers => { - console.log("Group Member list fetched successfully:", groupMembers); -}, error => { - console.log("Group Member list fetching failed with exception:", error); -} -); +const membersRequest = new CometChat.GroupMembersRequestBuilder("group-123") + .setLimit(30) + .setStatus(CometChat.USER_STATUS.ONLINE) + .build(); + +membersRequest.fetchNext().then( + (members) => console.log("Online members:", members), + (error) => console.log("Failed:", error) +); ``` - +--- - -```typescript -let GUID: string = "GUID"; -let limit: number = 30; -let groupMembersRequest: CometChat.GroupMembersRequest = new CometChat.GroupMembersRequestBuilder(GUID) - .setLimit(limit) - .build(); +## Member Properties -groupMembersRequest.fetchNext().then( - (groupMembers: CometChat.GroupMember[]) => { - console.log("Group Member list fetched successfully:", groupMembers); - }, (error: CometChat.CometChatException) => { - console.log("Group Member list fetching failed with exception:", error); - } -); -``` +| Property | Description | +|----------|-------------| +| `uid` | User's unique identifier | +| `name` | Display name | +| `avatar` | Profile picture URL | +| `scope` | ADMIN, MODERATOR, or PARTICIPANT | +| `status` | online or offline | +| `joinedAt` | When user joined the group | - +--- - +## Next Steps + + + + Add members to a group + + + Remove members from a group + + + Update member permissions + + + Transfer group ownership + + diff --git a/sdk/javascript/retrieve-groups.mdx b/sdk/javascript/retrieve-groups.mdx index 92a074c0..2dc63318 100644 --- a/sdk/javascript/retrieve-groups.mdx +++ b/sdk/javascript/retrieve-groups.mdx @@ -1,285 +1,300 @@ --- title: "Retrieve Groups" +sidebarTitle: "Retrieve Groups" +description: "Fetch and search groups in your CometChat application" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Fetch groups list +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .build(); +const groups = await groupsRequest.fetchNext(); -## Retrieve List of Groups - -*In other words, as a logged-in user, how do I retrieve the list of groups I've joined and groups that are available?* - -In order to fetch the list of groups, you can use the `GroupsRequest` class. To use this class i.e to create an object of the `GroupsRequest` class, you need to use the `GroupsRequestBuilder` class. The `GroupsRequestBuilder` class allows you to set the parameters based on which the groups are to be fetched. +// Get joined groups only +const groupsRequest = new CometChat.GroupsRequestBuilder() + .joinedOnly(true) + .build(); -The `GroupsRequestBuilder` class allows you to set the below parameters: +// Search groups +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setSearchKeyword("team") + .build(); -### Set Limit +// Filter by tags +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setTags(["engineering", "product"]) + .withTags(true) + .build(); -This method sets the limit i.e. the number of groups that should be fetched in a single iteration. +// Get specific group +const group = await CometChat.getGroup("group_guid"); - - -```javascript -let limit = 30; -let groupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .build(); +// Get online member count +const counts = await CometChat.getOnlineGroupMemberCount(["guid1", "guid2"]); ``` + - +Retrieve group information including group lists, individual group details, and online member counts. - -```typescript -let limit = 30; -let groupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .build(); -``` + +**Availability**: SDK, API, UI Kits - +Public and password groups are visible to all users. Private groups are only visible to members. + -
+--- -### Set Search Keyword +## Fetch Group List -This method allows you to set the search string based on which the groups are to be fetched. +Use `GroupsRequestBuilder` to fetch groups with various filters: - + ```javascript -let limit = 30; -let searchKeyword = "group"; -let groupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); -``` - - +const limit = 30; - -```typescript -let limit: number = 30; -let searchKeyword: string = "group"; -let groupsRequest: CometChat.GroupsRequest = new CometChat.GroupsRequestBuilder() +const groupsRequest = new CometChat.GroupsRequestBuilder() .setLimit(limit) - .setSearchKeyword(searchKeyword) .build(); -``` - - - - - -### Joined Only -This method when used, will ask the SDK to only return the groups that the user has joined or is a part of. - - - -```javascript -let limit = 30; -let groupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .joinedOnly(true) - .build(); +groupsRequest.fetchNext().then( + (groupList) => console.log("Groups:", groupList), + (error) => console.log("Failed:", error) +); ``` - - ```typescript -let limit: number = 30; -let groupsRequest: CometChat.GroupsRequest = new CometChat.GroupsRequestBuilder() +const limit: number = 30; + +const groupsRequest: CometChat.GroupsRequest = new CometChat.GroupsRequestBuilder() .setLimit(limit) - .joinedOnly(true) .build(); -``` - - - - -### Set Tags - -This method accepts a list of tags based on which the list of groups is to be fetched. The list fetched will only contain the groups that have been tagged with the specified tags. - - - -```javascript -let limit = 30; -let tags = ["tag1", "tag2"]; -let groupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .setTags(tags) - .build(); +groupsRequest.fetchNext().then( + (groupList: CometChat.Group[]) => console.log("Groups:", groupList), + (error: CometChat.CometChatException) => console.log("Failed:", error) +); ``` - + +```javascript +async function fetchGroups(limit = 30) { + const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(limit) + .build(); + + try { + const groupList = await groupsRequest.fetchNext(); + console.log(`Fetched ${groupList.length} groups`); + return groupList; + } catch (error) { + console.error("Failed to fetch groups:", error); + throw error; + } +} - -```typescript -let limit: number = 30; -let tags: Array = ["tag1", "tag2"]; -let groupsRequest: CometChat.GroupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .setTags(tags) - .build(); +// Usage +const groups = await fetchGroups(); ``` - - -### With Tags +### Builder Options -This property when set to true will fetch tags data along with the list of groups. +| Method | Description | +|--------|-------------| +| `setLimit(limit)` | Number of groups per request (max 100) | +| `setSearchKeyword(keyword)` | Search groups by name | +| `joinedOnly(true)` | Only return groups user has joined | +| `setTags(tags)` | Filter by group tags | +| `withTags(true)` | Include tags in response | - - -```javascript -let limit = 30; -let groupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .withTags(true) - .build(); -``` +--- - +## Get Joined Groups Only - -```typescript -let limit: number = 30; -let groupsRequest: CometChat.GroupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .withTags(true) - .build(); -``` - - +Fetch only groups the user is a member of: - +```javascript +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .joinedOnly(true) + .build(); -Finally, once all the parameters are set to the builder class, you need to call the build() method to get the object of the `GroupsRequest` class. +groupsRequest.fetchNext().then( + (groupList) => console.log("My groups:", groupList), + (error) => console.log("Failed:", error) +); +``` -Once you have the object of the `GroupsRequest` class, you need to call the `fetchNext()` method. Calling this method will return a list of `Group` objects containing n number of groups where n is the limit set in the builder class. +--- -The list of groups fetched will only have the public and password type groups. The private groups will only be available if the user is a member of the group. +## Search Groups - - ```javascript -let limit = 30; -let groupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) - .build(); +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .setSearchKeyword("team") + .build(); groupsRequest.fetchNext().then( -groupList => { - console.log("Groups list fetched successfully", groupList); -}, error => { - console.log("Groups list fetching failed with error", error); -} + (groupList) => console.log("Search results:", groupList), + (error) => console.log("Failed:", error) ); ``` - - -```typescript -let limit: number = 30; -let groupsRequest: CometChat.GroupsRequest = new CometChat.GroupsRequestBuilder() - .setLimit(limit) +--- + +## Filter by Tags + +```javascript +const groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .setTags(["engineering", "product"]) + .withTags(true) // Include tags in response .build(); groupsRequest.fetchNext().then( - (groupList: CometChat.Group[]) => { - console.log("Groups list fetched successfully", groupList); - }, (error: CometChat.CometChatException) => { - console.log("Groups list fetching failed with error", error); - } + (groupList) => { + groupList.forEach((group) => { + console.log(group.getName(), "Tags:", group.getTags()); + }); + }, + (error) => console.log("Failed:", error) ); ``` - - - - -## Retrieve Particular Group Details +--- -*In other words, as a logged-in user, how do I retrieve information for a specific group?* +## Get Single Group -To get the information of a group, you can use the `getGroup()` method. +Fetch details for a specific group: - + ```javascript -var GUID = "GUID"; +const GUID = "group-123"; + CometChat.getGroup(GUID).then( -group => { - console.log("Group details fetched successfully:", group); -}, error => { - console.log("Group details fetching failed with exception:", error); -} -); + (group) => { + console.log("Name:", group.getName()); + console.log("Type:", group.getType()); + console.log("Members:", group.getMembersCount()); + console.log("Has Joined:", group.getHasJoined()); + }, + (error) => console.log("Failed:", error) +); ``` - - ```typescript -var GUID: string = "GUID"; +const GUID: string = "group-123"; + CometChat.getGroup(GUID).then( (group: CometChat.Group) => { - console.log("Group details fetched successfully:", group); - }, (error: CometChat.CometChatException) => { - console.log("Group details fetching failed with exception:", error); - } + console.log("Name:", group.getName()); + console.log("Type:", group.getType()); + console.log("Members:", group.getMembersCount()); + }, + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - -| Parameter | Description | -| --------- | ------------------------------------------------------------ | -| `GUID` | The GUID of the group for whom the details are to be fetched | - -It returns `Group` object containing the details of the group. +--- -## Get online group member count +## Get Online Member Count -To get the total count of online users in particular groups, you can use the `getOnlineGroupMemberCount()` method. +Get the count of online members in specific groups: - - ```javascript -let guids = ["cometchat-guid-1"]; +const guids = ["group-123", "group-456"]; + CometChat.getOnlineGroupMemberCount(guids).then( -groupMemberCount => { - console.log("Total online user for specified groups:", groupMemberCount); -}, error => { - console.log("Online group member count fetching failed with error:", error); -} + (counts) => { + console.log("Online counts:", counts); + // { "group-123": 5, "group-456": 12 } + }, + (error) => console.log("Failed:", error) ); ``` - +--- - -```typescript -let guids: String[] = ["cometchat-guid-1"]; -CometChat.getOnlineGroupMemberCount(guids).then( - (groupMemberCount: number) => { - console.log("Total online user for specified groups:", groupMemberCount); - }, (error: CometChat.CometChatException) => { - console.log("Online group member count fetching failed with error:", error); +## Pagination + +Use `fetchNext()` repeatedly to paginate through results: + +```javascript +class GroupListManager { + constructor() { + this.groupsRequest = new CometChat.GroupsRequestBuilder() + .setLimit(30) + .build(); + this.groups = []; } -); + + async loadMore() { + try { + const groupList = await this.groupsRequest.fetchNext(); + this.groups = [...this.groups, ...groupList]; + return groupList; + } catch (error) { + console.log("Failed to load groups:", error); + return []; + } + } +} + +// Usage +const manager = new GroupListManager(); +const firstPage = await manager.loadMore(); +const secondPage = await manager.loadMore(); ``` - +--- - +## Group Properties + +| Property | Type | Description | +|----------|------|-------------| +| `guid` | String | Unique identifier | +| `name` | String | Display name | +| `type` | String | PUBLIC, PASSWORD, or PRIVATE | +| `icon` | String | URL to group icon | +| `description` | String | Group description | +| `owner` | String | UID of group owner | +| `membersCount` | Number | Number of members | +| `hasJoined` | Boolean | If logged-in user is a member | +| `joinedAt` | Number | When user joined (timestamp) | +| `scope` | String | User's scope (ADMIN, MODERATOR, PARTICIPANT) | +| `createdAt` | Number | Creation timestamp | +| `tags` | Array | Group tags | +| `metadata` | Object | Custom data | + +--- -This method returns a JSON Object with the GUID as the key and the online member count for that group as the value. +## Next Steps + + + + Create new groups + + + Join existing groups + + + Fetch group members + + + Modify group settings + + diff --git a/sdk/javascript/retrieve-users.mdx b/sdk/javascript/retrieve-users.mdx index 943df640..27db9e97 100644 --- a/sdk/javascript/retrieve-users.mdx +++ b/sdk/javascript/retrieve-users.mdx @@ -1,537 +1,589 @@ --- title: "Retrieve Users" +sidebarTitle: "Retrieve Users" +description: "Fetch and search users in your CometChat application" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** - -## Retrieve Logged In User Details - -You can get the details of the logged-in user using the `getLoggedInUser()` method. This method can also be used to check if the user is logged in or not. If the method returns `Promise` with reject callback, it indicates that the user is not logged in and you need to log the user into CometChat SDK. - - - ```javascript -CometChat.getLoggedinUser().then( -user => { - console.log("user details:", { user }); -}, error => { - console.log("error getting details:", { error }); -} -); -``` +// Fetch users list +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .build(); +const users = await usersRequest.fetchNext(); - +// Search users +const usersRequest = new CometChat.UsersRequestBuilder() + .setSearchKeyword("john") + .build(); - -```typescript -CometChat.getLoggedinUser().then( - (user: CometChat.User) => { - console.log("user details:", { user }); - }, (error: CometChat.CometChatException) => { - console.log("error getting details:", { error }); - } -); -``` +// Filter online users +const usersRequest = new CometChat.UsersRequestBuilder() + .setStatus(CometChat.USER_STATUS.ONLINE) + .build(); - +// Filter by role +const usersRequest = new CometChat.UsersRequestBuilder() + .setRoles(["admin", "moderator"]) + .build(); - +// Get specific user +const user = await CometChat.getUser("user_uid"); -This method will return a `User` object containing all the information related to the logged-in user. +// Get online count +const count = await CometChat.getOnlineUserCount(); -## Retrieve List of Users +// Friends only +const usersRequest = new CometChat.UsersRequestBuilder() + .friendsOnly(true) + .build(); +``` + -In order to fetch the list of users, you can use the `UsersRequest` class. To use this class i.e to create an object of the `UsersRequest` class, you need to use the `UsersRequestBuilder` class. The `UsersRequestBuilder` class allows you to set the parameters based on which the users are to be fetched. +Retrieve user information including the logged-in user, user lists, and individual user details. -The `UsersRequestBuilder` class allows you to set the below parameters: + +**Availability**: SDK, API, UI Kits + + +--- -### Set Limit +## Get Logged-In User -This method sets the limit i.e. the number of users that should be fetched in a single iteration. +Check if a user is logged in and get their details: - + ```javascript -let limit = 30; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .build(); +CometChat.getLoggedinUser().then( + (user) => { + if (user) { + console.log("Logged in as:", user.getName()); + } else { + console.log("No user logged in"); + } + }, + (error) => console.log("Error:", error) +); ``` - - ```typescript -let limit: number = 30; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .build(); +CometChat.getLoggedinUser().then( + (user: CometChat.User | null) => { + if (user) { + console.log("Logged in as:", user.getName()); + } + }, + (error: CometChat.CometChatException) => console.log("Error:", error) +); +``` + + +```javascript +async function getLoggedInUser() { + try { + const user = await CometChat.getLoggedinUser(); + if (user) { + console.log("Logged in as:", user.getName()); + } else { + console.log("No user logged in"); + } + return user; + } catch (error) { + console.log("Error:", error); + throw error; + } +} ``` - - -### Set Search Keyword +--- + +## Fetch User List -This method allows you to set the search string based on which the users are to be fetched. +Use `UsersRequestBuilder` to fetch users with various filters: - + ```javascript -let limit = 30; -let searchKeyword = "super"; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .build(); -``` +const limit = 30; - - - -```typescript -let limit: number = 30; -let searchKeyword: string = "super"; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() +const usersRequest = new CometChat.UsersRequestBuilder() .setLimit(limit) - .setSearchKeyword(searchKeyword) .build(); -``` - - - - -### Search In - -This method allows you to define in which user property should the searchKeyword be searched. This method only works in combination with `setSearchKeyword()`. By default the keyword is searched in both UID & Name. - - - -```js -let limit = 30; -let searchKeyword = "super"; -let searchIn = ["uid", "name"]; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setSearchKeyword(searchKeyword) - .searchIn(searchIn) - .build(); +usersRequest.fetchNext().then( + (userList) => console.log("Users:", userList), + (error) => console.log("Failed:", error) +); ``` - - ```typescript -let limit: number = 30; -let searchKeyword: string = "super"; -let searchIn: Array = ["uid", "name"]; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() +const limit: number = 30; + +const usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() .setLimit(limit) - .setSearchKeyword(searchKeyword) - .searchIn(searchIn) .build(); -``` +usersRequest.fetchNext().then( + (userList: CometChat.User[]) => console.log("Users:", userList), + (error: CometChat.CometChatException) => console.log("Failed:", error) +); +``` + +```javascript +async function fetchUsers(limit = 30) { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(limit) + .build(); + + try { + const userList = await usersRequest.fetchNext(); + console.log(`Fetched ${userList.length} users`); + return userList; + } catch (error) { + console.error("Failed to fetch users:", error); + throw error; + } +} +// Usage +const users = await fetchUsers(); +``` + -### Set Status -The status based on which the users are to be fetched. The status parameter can contain one of the below two values: +### Builder Options -* CometChat.USER\_STATUS.ONLINE - will return the list of only online users. -* CometChat.USER\_STATUS.OFFLINE - will return the list of only offline users. +| Method | Description | +|--------|-------------| +| `setLimit(limit)` | Number of users per request (max 100) | +| `setSearchKeyword(keyword)` | Search users by name or UID | +| `searchIn(fields)` | Fields to search in: `["uid", "name"]` | +| `setStatus(status)` | Filter by online/offline status | +| `hideBlockedUsers(true)` | Exclude blocked users | +| `setRoles(roles)` | Filter by user roles | +| `friendsOnly(true)` | Only return friends | +| `setTags(tags)` | Filter by user tags | +| `withTags(true)` | Include tags in response | +| `setUIDs(uids)` | Fetch specific users (max 25) | +| `sortBy(field)` | Sort by field (e.g., "name") | +| `sortByOrder(order)` | Sort order: "asc" or "desc" | -If this parameter is not set, will return all the available users. +--- + +## Search Users - + ```javascript -let limit = 30; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setStatus(CometChat.USER_STATUS.ONLINE) - .build() -``` +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setSearchKeyword("john") + .build(); +usersRequest.fetchNext().then( + (userList) => console.log("Search results:", userList), + (error) => console.log("Failed:", error) +); +``` - - -```typescript -let limit: number = 30; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setStatus(CometChat.USER_STATUS.ONLINE) - .build(); + +```javascript +async function searchUsers(keyword) { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setSearchKeyword(keyword) + .build(); + + try { + const userList = await usersRequest.fetchNext(); + console.log("Search results:", userList); + return userList; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} ``` - - -### Hide Blocked Users - -This method is used to determine if the blocked users should be returned as a part of the user list. If set to true, the user list will not contain the users blocked by the logged in user. +### Search in Specific Fields - - ```javascript -let limit = 30; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .hideBlockedUsers(true) - .build(); -``` - - - - -```typescript -let limit: number = 30; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .hideBlockedUsers(true) +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setSearchKeyword("john") + .searchIn(["name"]) // Only search in name, not UID .build(); ``` - - - +--- -### Set Roles +## Filter by Status -This method allows you to fetch the users based on multiple roles. +Get only online or offline users: - - ```javascript -let limit = 30; -let roles = ["default", "dev"]; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setRoles(roles) - .build(); -``` - - +// Online users only +const onlineRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setStatus(CometChat.USER_STATUS.ONLINE) + .build(); - -```typescript -let limit: number = 30; -let roles: Array = ["default", "dev"]; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setRoles(roles) +// Offline users only +const offlineRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setStatus(CometChat.USER_STATUS.OFFLINE) .build(); ``` - - - - -### Friends Only +--- -This property when set to true will return only the friends of the logged-in user. +## Filter by Role - + ```javascript -let limit = 30; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .friendsOnly(true) - .build(); -``` +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setRoles(["admin", "moderator"]) + .build(); +usersRequest.fetchNext().then( + (userList) => console.log("Admins and moderators:", userList), + (error) => console.log("Failed:", error) +); +``` - - -```typescript -let limit: number = 30; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .friendsOnly(true) - .build(); + +```javascript +async function fetchUsersByRole(roles) { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setRoles(roles) + .build(); + + try { + const userList = await usersRequest.fetchNext(); + console.log("Filtered users:", userList); + return userList; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} ``` - - -### Set Tags +--- -This method accepts a list of tags based on which the list of users is to be fetched. The list fetched will only contain the users that have been tagged with the specified tags. +## Filter by Tags - + ```javascript -let limit = 30; -let tags = ["tag1", "tag2"]; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setTags(tags) - .build(); -``` +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setTags(["premium", "verified"]) + .withTags(true) // Include tags in response + .build(); +usersRequest.fetchNext().then( + (userList) => { + userList.forEach((user) => { + console.log(user.getName(), "Tags:", user.getTags()); + }); + }, + (error) => console.log("Failed:", error) +); +``` - - -```typescript -let limit: number = 30; -let tags: Array = ["tag1", "tag2"]; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setTags(tags) - .build(); + +```javascript +async function fetchUsersByTags(tags) { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setTags(tags) + .withTags(true) + .build(); + + try { + const userList = await usersRequest.fetchNext(); + userList.forEach((user) => { + console.log(user.getName(), "Tags:", user.getTags()); + }); + return userList; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} ``` - - -### With Tags +--- -This property when set to true will fetch tags data along with the list of users. +## Get Friends Only - + ```javascript -let limit = 30; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .withTags(true) - .build(); -``` +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .friendsOnly(true) + .build(); +usersRequest.fetchNext().then( + (friends) => console.log("Friends:", friends), + (error) => console.log("Failed:", error) +); +``` - - -```typescript -let limit: number = 30; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .withTags(true) - .build(); + +```javascript +async function fetchFriends() { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .friendsOnly(true) + .build(); + + try { + const friends = await usersRequest.fetchNext(); + console.log("Friends:", friends); + return friends; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} ``` - - -### Set UIDs +--- -This method accepts a list of UIDs based on which the list of users is fetched. A maximum of `25` users can be fetched. +## Fetch Specific Users + +Get users by their UIDs (max 25): - + ```javascript -let limit = 30; -let UIDs = ["cometchat-uid-1", "cometchat-uid-2"]; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setUIDs(UIDs) - .build(); -``` +const usersRequest = new CometChat.UsersRequestBuilder() + .setUIDs(["user1", "user2", "user3"]) + .build(); +usersRequest.fetchNext().then( + (userList) => console.log("Specific users:", userList), + (error) => console.log("Failed:", error) +); +``` - - -```typescript -let limit: number = 30; -let UIDs: Array = ["cometchat-uid-1", "cometchat-uid-2"]; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .setUIDs(UIDs) - .build(); + +```javascript +async function fetchSpecificUsers(uids) { + const usersRequest = new CometChat.UsersRequestBuilder() + .setUIDs(uids) + .build(); + + try { + const userList = await usersRequest.fetchNext(); + console.log("Specific users:", userList); + return userList; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} ``` - - -### Sort By +--- -This method allows you to sort the User List by a specific property of User. By default the User List is sorted by `status => name => UID` . If `name` is pass to the `sortBy()` method the user list will be sorted by `name => UID`. +## Get Single User + +Fetch details for a specific user: -```js -let limit = 30; -let UIDs = ["cometchat-uid-1", "cometchat-uid-2"]; -let sortBy = "name"; -let usersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .sortBy(sortBy) - .build(); -``` +```javascript +const UID = "user1"; +CometChat.getUser(UID).then( + (user) => { + console.log("User:", user.getName()); + console.log("Status:", user.getStatus()); + console.log("Last Active:", user.getLastActiveAt()); + }, + (error) => console.log("Failed:", error) +); +``` - ```typescript -let limit: number = 30; -let sortBy: string = "name"; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .sortBy(sortBy) - .build(); -``` - - - - - -### Sort By Order - -This method allows you to sort the User List in a specific order. By default the user list is sorted in ascending order. +const UID: string = "user1"; - - -```js -let limit = 30; -let sortByOrder = "desc"; -let usersReques = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .sortByOrder(sortOrder) - .build(); +CometChat.getUser(UID).then( + (user: CometChat.User) => { + console.log("User:", user.getName()); + console.log("Status:", user.getStatus()); + }, + (error: CometChat.CometChatException) => console.log("Failed:", error) +); ``` - - - -```typescript -let limit: number = 30; -let sortOrder: string = "desc"; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() - .setLimit(limit) - .sortOrder(sortOrder) - .build(); + +```javascript +async function getUser(uid) { + try { + const user = await CometChat.getUser(uid); + console.log("User:", user.getName()); + console.log("Status:", user.getStatus()); + console.log("Last Active:", user.getLastActiveAt()); + return user; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} ``` - - -Finally, once all the parameters are set to the builder class, you need to call the build() method to get the object of the UsersRequest class. +--- + +## Get Online User Count -Once you have the object of the UsersRequest class, you need to call the fetchNext() method. Calling this method will return a list of User objects containing n number of users where n is the limit set in the builder class. +Get the total number of online users in your app: - + ```javascript -var limit = 30; -var usersRequest = new CometChat.UsersRequestBuilder() -.setLimit(limit) -.build(); - -usersRequest.fetchNext().then( -userList => { - console.log("User list received:", userList); -}, error => { - console.log("User list fetching failed with error:", error); -} +CometChat.getOnlineUserCount().then( + (count) => console.log("Online users:", count), + (error) => console.log("Failed:", error) ); ``` - - - -```typescript -let limit: number = 30; -let usersRequest: CometChat.UsersRequest = new CometChat.UsersRequestBuilder() -.setLimit(limit) -.build(); - -usersRequest.fetchNext().then( - (userList: CometChat.User[]) => { - console.log("User list received:", userList); - }, (error: CometChat.CometChatException) => { - console.log("User list fetching failed with error:", error); + +```javascript +async function getOnlineCount() { + try { + const count = await CometChat.getOnlineUserCount(); + console.log("Online users:", count); + return count; + } catch (error) { + console.log("Failed:", error); + throw error; } -); +} ``` - - -## Retrieve Particular User Details +--- -To get the information of a user, you can use the `getUser()` method. +## Pagination + +Use `fetchNext()` repeatedly to paginate through results: - - ```javascript -let UID = "UID"; -CometChat.getUser(UID).then( -user => { - console.log("User details fetched for user:", user); -}, error => { - console.log("User details fetching failed with error:", error); -} -); -``` +class UserListManager { + constructor() { + this.usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .build(); + this.users = []; + } - + async loadMore() { + try { + const userList = await this.usersRequest.fetchNext(); + this.users = [...this.users, ...userList]; + return userList; + } catch (error) { + console.log("Failed to load users:", error); + return []; + } + } - -```typescript -let UID: string = "UID"; -CometChat.getUser(UID).then( - (user: CometChat.User) => { - console.log("User details fetched for user:", user); - }, (error: CometChat.CometChatException) => { - console.log("User details fetching failed with error:", error); + hasMore() { + // If last fetch returned less than limit, no more users + return this.users.length > 0; } -); -``` +} - +// Usage +const manager = new UserListManager(); +const firstPage = await manager.loadMore(); +const secondPage = await manager.loadMore(); +``` - +--- -The `getUser()` method takes the following parameters: +## Hide Blocked Users -| Parameter | Description | -| --------- | ---------------------------------------------------------- | -| UID | The UID of the user for whom the details are to be fetched | +Exclude users you've blocked from the list: -It returns the `User` object containing the details of the user. +```javascript +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .hideBlockedUsers(true) + .build(); +``` -## Get online user count +--- -To get the total count of online users for your app, you can use the `getOnlineUserCount()` method. +## Sorting - - ```javascript -CometChat.getOnlineUserCount().then( -userCount => { - console.log("Total online user count:", userCount); -}, error => { - console.log("Online user count fetching failed with error:", error); -} -); -``` - - +// Sort by name ascending +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .sortBy("name") + .sortByOrder("asc") + .build(); - -```typescript -CometChat.getOnlineUserCount().then( - (userCount: number) => { - console.log("Total online user count:", userCount); - }, (error: CometChat.CometChatException) => { - console.log("Online user count fetching failed with error:", error); - } -); +// Sort by name descending +const usersRequestDesc = new CometChat.UsersRequestBuilder() + .setLimit(30) + .sortBy("name") + .sortByOrder("desc") + .build(); ``` - + +Default sort order: `status → name → UID` + - +--- -This method returns the total online user count for your app. +## Next Steps + + + + Create and update users + + + Track online/offline status + + + Block and unblock users + + + Work with group conversations + + diff --git a/sdk/javascript/send-message.mdx b/sdk/javascript/send-message.mdx index ae9f8e12..f4182bd6 100644 --- a/sdk/javascript/send-message.mdx +++ b/sdk/javascript/send-message.mdx @@ -1,1727 +1,504 @@ --- -title: "Send A Message" +title: "Send a Message" +description: "Send text, media, and custom messages to users and groups" --- +{/* Agent-Friendly Quick Reference */} + +**Quick Reference** - -Using CometChat, you can send three types of messages: - -1. [Text Message](/sdk/javascript/send-message#text-message) is the most common and standard message type. -2. [Media Message](/sdk/javascript/send-message#media-message) for sending photos, videos and files. -3. [Custom Message](/sdk/javascript/send-message#custom-message), for sending completely custom data using JSON structures. -4. [Interactive Messages](/sdk/javascript/interactive-messages), for sending end-user interactive messages of type form, card and custom Interactive - -You can also send metadata along with a text, media or custom message. Think, for example, if you'd want to share the user's location with every message, you can use the metadata field - -## Text Message - -*In other words, as a sender, how do I send a text message?* - -To send a text message to a single user or group, you need to use the `sendMessage()` method and pass a `TextMessage` object to it. - -### Add Metadata - -To send custom data along with a text message, you can use the `setMetadata` method and pass a `JSON Object` to it. - - - ```javascript -let metadata = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; - -textMessage.setMetadata(metadata); -``` +// Text message to user +const msg = new CometChat.TextMessage("USER_UID", "Hello!", CometChat.RECEIVER_TYPE.USER); +await CometChat.sendMessage(msg); - +// Text message to group +const msg = new CometChat.TextMessage("GROUP_GUID", "Hello!", CometChat.RECEIVER_TYPE.GROUP); +await CometChat.sendMessage(msg); - -```typescript -let metadata: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; +// Media message +const msg = new CometChat.MediaMessage("UID", file, CometChat.MESSAGE_TYPE.IMAGE, CometChat.RECEIVER_TYPE.USER); +await CometChat.sendMediaMessage(msg); -textMessage.setMetadata(metadata); +// Custom message (e.g., location) +const msg = new CometChat.CustomMessage("UID", CometChat.RECEIVER_TYPE.USER, "location", {lat: 0, lng: 0}); +await CometChat.sendCustomMessage(msg); ``` + - - - +CometChat supports multiple message types to cover all your chat needs. For a deeper understanding of how messages are structured, see [Message Structure & Hierarchy](/sdk/javascript/message-structure-and-hierarchy). -### Add Tags + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + -To add a tag to a message you can use the `setTags()` method of the TextMessage Class. The `setTags()` method accepts a list of tags. +| Type | Method | Use Case | +|------|--------|----------| +| [Text](#text-message) | `sendMessage()` | Standard chat messages | +| [Media](#media-message) | `sendMediaMessage()` | Images, videos, audio, files | +| [Custom](#custom-message) | `sendCustomMessage()` | Location, polls, custom data | +| [Interactive](/sdk/javascript/interactive-messages) | `sendInteractiveMessage()` | Forms, cards, buttons | - - -```javascript -let tags = ["starredMessage"]; +--- -textMessage.setTags(tags); -``` +## Text Message - +Send plain text messages to users or groups. - -```typescript -let tags: Array = ["starredMessage"]; + + + ```javascript + const receiverID = "UID"; + const messageText = "Hello!"; + const receiverType = CometChat.RECEIVER_TYPE.USER; + + const textMessage = new CometChat.TextMessage( + receiverID, + messageText, + receiverType + ); + + CometChat.sendMessage(textMessage).then( + (message) => console.log("Message sent:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```javascript + const receiverID = "GUID"; + const messageText = "Hello everyone!"; + const receiverType = CometChat.RECEIVER_TYPE.GROUP; + + const textMessage = new CometChat.TextMessage( + receiverID, + messageText, + receiverType + ); + + CometChat.sendMessage(textMessage).then( + (message) => console.log("Message sent:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```typescript + const receiverID: string = "UID"; + const messageText: string = "Hello!"; + const receiverType: string = CometChat.RECEIVER_TYPE.USER; + + const textMessage: CometChat.TextMessage = new CometChat.TextMessage( + receiverID, + messageText, + receiverType + ); + + CometChat.sendMessage(textMessage).then( + (message: CometChat.TextMessage) => console.log("Message sent:", message), + (error: CometChat.CometChatException) => console.log("Error:", error) + ); + ``` + + + ```javascript + async function sendTextMessage(receiverID, text, isGroup = false) { + const receiverType = isGroup + ? CometChat.RECEIVER_TYPE.GROUP + : CometChat.RECEIVER_TYPE.USER; + + const textMessage = new CometChat.TextMessage( + receiverID, + text, + receiverType + ); + + try { + const message = await CometChat.sendMessage(textMessage); + console.log("Message sent:", message.getId()); + return message; + } catch (error) { + console.error("Send failed:", error); + throw error; + } + } + + // Usage + await sendTextMessage("user123", "Hello!"); + await sendTextMessage("group456", "Hello everyone!", true); + ``` + + -textMessage.setTags(tags); -``` +### TextMessage Parameters - +| Parameter | Type | Description | +|-----------|------|-------------| +| `receiverID` | string | UID of user or GUID of group | +| `messageText` | string | The text content | +| `receiverType` | string | `CometChat.RECEIVER_TYPE.USER` or `GROUP` | - +### Optional: Add Metadata -Once the text message object is ready, you need to use the `sendMessage()` method to send the text message to the recipient. +Attach custom data (like location) to any message: - - ```javascript -let receiverID = "UID"; -let messageText = "Hello world!"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let textMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType -); +const textMessage = new CometChat.TextMessage(receiverID, "Check this out!", receiverType); -CometChat.sendMessage(textMessage).then( - (message) => { - console.log("Message sent successfully:", message); - }, - (error) => { - console.log("Message sending failed with error:", error); - } -); +textMessage.setMetadata({ + latitude: "50.6192171633316", + longitude: "-72.68182268750002" +}); + +CometChat.sendMessage(textMessage); ``` - +### Optional: Add Tags - -```javascript -let receiverID = "GUID"; -let messageText = "Hello world!"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let textMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType -); +Tag messages for filtering or categorization: -CometChat.sendMessage(textMessage).then( - (message) => { - console.log("Message sent successfully:", message); - }, - (error) => { - console.log("Message sending failed with error:", error); - } -); +```javascript +textMessage.setTags(["important", "starred"]); ``` - - - -```typescript -let receiverID: string = "UID", - messageText: string = "Hello world!", - receiverType: string = CometChat.RECEIVER_TYPE.USER, - textMessage: CometChat.TextMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType - ); - -CometChat.sendMessage(textMessage).then( - (message: CometChat.TextMessage) => { - console.log("Message sent successfully:", message); - }, - (error: CometChat.CometChatException) => { - console.log("Message sending failed with error:", error); - } -); -``` +### Optional: Quote a Message - +Reply to a specific message: - -```typescript -let receiverID: string = "GUID", - messageText: string = "Hello world!", - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - textMessage: CometChat.TextMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType - ); - -CometChat.sendMessage(textMessage).then( - (message: CometChat.TextMessage) => { - console.log("Message sent successfully:", message); - }, - (error: CometChat.CometChatException) => { - console.log("Message sending failed with error:", error); - } -); +```javascript +textMessage.setQuotedMessageId(previousMessageId); ``` - - - +--- -### Set Quoted Message Id +## Media Message -To set a quoted message ID for a message, use the `setQuotedMessageId()` method of the TextMessage class. This method accepts the ID of the message to be quoted. +Send images, videos, audio files, and documents. - - -```javascript -textMessage.setQuotedMessageId(10); -``` +### Send File from Input - +Upload files directly from a file input: - -```typescript -textMessage.setQuotedMessageId(10); +```html + ``` - - + + + ```javascript + const file = document.getElementById("fileInput").files[0]; + const receiverID = "UID"; + const messageType = CometChat.MESSAGE_TYPE.IMAGE; // or VIDEO, AUDIO, FILE + const receiverType = CometChat.RECEIVER_TYPE.USER; + + const mediaMessage = new CometChat.MediaMessage( + receiverID, + file, + messageType, + receiverType + ); + + CometChat.sendMediaMessage(mediaMessage).then( + (message) => console.log("Media sent:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```javascript + const file = document.getElementById("fileInput").files[0]; + const receiverID = "GUID"; + const messageType = CometChat.MESSAGE_TYPE.IMAGE; + const receiverType = CometChat.RECEIVER_TYPE.GROUP; + + const mediaMessage = new CometChat.MediaMessage( + receiverID, + file, + messageType, + receiverType + ); + + CometChat.sendMediaMessage(mediaMessage).then( + (message) => console.log("Media sent:", message), + (error) => console.log("Error:", error) + ); + ``` + -Once the text message object is ready, you need to use the `sendMessage()` method to send the text message to the recipient. +### Message Types - - -```javascript -let receiverID = "UID"; -let messageText = "Hello world!"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let textMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType -); +| Type | Constant | File Types | +|------|----------|------------| +| Image | `CometChat.MESSAGE_TYPE.IMAGE` | jpg, png, gif, etc. | +| Video | `CometChat.MESSAGE_TYPE.VIDEO` | mp4, mov, etc. | +| Audio | `CometChat.MESSAGE_TYPE.AUDIO` | mp3, wav, etc. | +| File | `CometChat.MESSAGE_TYPE.FILE` | pdf, doc, etc. | -CometChat.sendMessage(textMessage).then( - (message) => { - console.log("Message sent successfully:", message); - }, - (error) => { - console.log("Message sending failed with error:", error); - } -); -``` +### Send File from URL - +Send media hosted on your server or cloud storage: - ```javascript -let receiverID = "GUID"; -let messageText = "Hello world!"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let textMessage = new CometChat.TextMessage( +const receiverID = "UID"; +const messageType = CometChat.MESSAGE_TYPE.IMAGE; +const receiverType = CometChat.RECEIVER_TYPE.USER; + +const mediaMessage = new CometChat.MediaMessage( receiverID, - messageText, + "", + messageType, receiverType ); -CometChat.sendMessage(textMessage).then( - (message) => { - console.log("Message sent successfully:", message); - }, - (error) => { - console.log("Message sending failed with error:", error); - } -); -``` - - - - -```typescript -let receiverID: string = "UID", - messageText: string = "Hello world!", - receiverType: string = CometChat.RECEIVER_TYPE.USER, - textMessage: CometChat.TextMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType - ); - -CometChat.sendMessage(textMessage).then( - (message: CometChat.TextMessage) => { - console.log("Message sent successfully:", message); - }, - (error: CometChat.CometChatException) => { - console.log("Message sending failed with error:", error); - } -); -``` +const attachment = new CometChat.Attachment({ + name: "photo", + extension: "png", + mimeType: "image/png", + url: "https://example.com/image.png" +}); - +mediaMessage.setAttachment(attachment); - -```typescript -let receiverID: string = "GUID", - messageText: string = "Hello world!", - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - textMessage: CometChat.TextMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType - ); - -CometChat.sendMessage(textMessage).then( - (message: CometChat.TextMessage) => { - console.log("Message sent successfully:", message); - }, - (error: CometChat.CometChatException) => { - console.log("Message sending failed with error:", error); - } +CometChat.sendMediaMessage(mediaMessage).then( + (message) => console.log("Media sent:", message), + (error) => console.log("Error:", error) ); ``` - - - - -The `TextMessage` class constructor takes the following parameters: - -| Parameter | Description | | -| ---------------- | -------------------------------------------------------------------------------------------- | -------- | -| **receiverID** | `UID` of the user or `GUID` of the group receiving the message | Required | -| **messageText** | The text message | Required | -| **receiverType** | The type of the receiver - `CometChat.RECEIVER_TYPE.USER` or `CometChat.RECEIVER_TYPE.GROUP` | Required | +### Send Multiple Attachments -When a text message is sent successfully, the response will include a `TextMessage` object which includes all information related to the sent message. - -## Media Message - -*In other words, as a sender, how do I send a media message like photos, videos & files?* - -To send a media message to any user or group, you need to use the `sendMediaMessage()` method and pass a `MediaMessage` object to it. - -### Add Metadata - -To send custom data along with a media message, you can use the `setMetadata` method and pass a `JSON Object` to it. +Send multiple files in a single message: - -```javascript -let metadata = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; - -mediaMessage.setMetadata(metadata); -``` - - - - -```typescript -let metadata: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; - -mediaMessage.setMetadata(metadata); -``` - - - + + ```javascript + // HTML: + const files = document.getElementById("fileInput").files; + + const mediaMessage = new CometChat.MediaMessage( + receiverID, + files, // Pass FileList directly + CometChat.MESSAGE_TYPE.FILE, + CometChat.RECEIVER_TYPE.USER + ); + + CometChat.sendMediaMessage(mediaMessage); + ``` + + + ```javascript + const mediaMessage = new CometChat.MediaMessage( + receiverID, + "", + CometChat.MESSAGE_TYPE.IMAGE, + CometChat.RECEIVER_TYPE.USER + ); + + const attachments = [ + new CometChat.Attachment({ + name: "photo1", + extension: "png", + mimeType: "image/png", + url: "https://example.com/image1.png" + }), + new CometChat.Attachment({ + name: "photo2", + extension: "jpg", + mimeType: "image/jpeg", + url: "https://example.com/image2.jpg" + }) + ]; + + mediaMessage.setAttachments(attachments); + + CometChat.sendMediaMessage(mediaMessage); + ``` + -### Add Caption(Text along with Media Message) +### Optional: Add Caption -To send a caption with a media message, you can use the `setCaption` method and pass text to it. +Add text description to media: - - ```javascript -let caption = "Random Caption"; - -mediaMessage.setCaption(caption); -``` - - - - -```typescript -let caption: string = "Random Caption"; - -mediaMessage.setCaption(caption); +mediaMessage.setCaption("Check out this photo!"); ``` - - - - -### Add Tags - -To add a tag to a message you can use the `setTags()` method of the MediaMessage Class. The `setTags()` method accepts a list of tags. +### Optional: Add Metadata & Tags - - ```javascript -let tags = ["starredMessage"]; - -mediaMessage.setTags(tags); +mediaMessage.setMetadata({ location: "Paris" }); +mediaMessage.setTags(["vacation", "photos"]); ``` - - - -```typescript -let tags: Array = ["starredMessage"]; +--- -mediaMessage.setTags(tags); -``` +## Custom Message - +Send structured data like location coordinates, polls, or any custom payload. + + + ```javascript + const receiverID = "UID"; + const receiverType = CometChat.RECEIVER_TYPE.USER; + const customType = "location"; + const customData = { + latitude: "50.6192171633316", + longitude: "-72.68182268750002", + address: "123 Main St" + }; + + const customMessage = new CometChat.CustomMessage( + receiverID, + receiverType, + customType, + customData + ); + + CometChat.sendCustomMessage(customMessage).then( + (message) => console.log("Custom message sent:", message), + (error) => console.log("Error:", error) + ); + ``` + + + ```javascript + const receiverID = "GUID"; + const receiverType = CometChat.RECEIVER_TYPE.GROUP; + const customType = "poll"; + const customData = { + question: "Where should we meet?", + options: ["Coffee Shop", "Restaurant", "Park"] + }; + + const customMessage = new CometChat.CustomMessage( + receiverID, + receiverType, + customType, + customData + ); + + CometChat.sendCustomMessage(customMessage).then( + (message) => console.log("Poll sent:", message), + (error) => console.log("Error:", error) + ); + ``` + -There are 2 ways you can send Media Messages using the CometChat SDK: - -1. **By providing the File:** You can directly share the file object while creating an object of the MediaMessage class. When the media message is sent using the `sendMediaMessage()` method, this file is then uploaded to CometChat servers and the URL of the file is sent in the success response of the `sendMediaMessage()` function. - -Getting file Object: +### CustomMessage Parameters - - -```html - - - - - - -``` +| Parameter | Type | Description | +|-----------|------|-------------| +| `receiverID` | string | UID of user or GUID of group | +| `receiverType` | string | `USER` or `GROUP` | +| `customType` | string | Your custom type (e.g., "location", "poll") | +| `customData` | object | JSON payload with your data | - +### Control Conversation Update - +By default, custom messages update the conversation's last message. To prevent this: - - ```javascript -let receiverID = "UID"; -let messageType = CometChat.MESSAGE_TYPE.FILE; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - "INPUT FILE OBJECT", - messageType, - receiverType -); - -CometChat.sendMediaMessage(mediaMessage).then( - (message) => { - console.log("Media message sent successfully", message); - }, - (error) => { - console.log("Media message sending failed with error", error); - } -); +customMessage.shouldUpdateConversation(false); ``` - +### Custom Notification Text - -```javascript -let receiverID = "GUID"; -let messageType = CometChat.MESSAGE_TYPE.FILE; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - `INPUT FILE OBJECT`, - messageType, - receiverType -); +Set custom text for push/email/SMS notifications: -CometChat.sendMediaMessage(mediaMessage).then( - (message) => { - console.log("Media message sent successfully", message); - }, - (error) => { - console.log("Media message sending failed with error", error); - } -); +```javascript +customMessage.setConversationText("📍 Shared a location"); ``` - - - -```typescript -let receiverID: string = "UID", - messageType: string = CometChat.MESSAGE_TYPE.FILE, - receiverType: string = CometChat.RECEIVER_TYPE.USER, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - "INPUT FILE OBJECT", - messageType, - receiverType - ); +--- -CometChat.sendMediaMessage(mediaMessage).then( - (message: CometChat.MediaMessage) => { - console.log("Media message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("Media message sending failed with error", error); - } -); -``` +## Common Options - +These options work with all message types: - -```typescript -let receiverID: string = "GUID", - messageType: string = CometChat.MESSAGE_TYPE.FILE, - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - "INPUT FILE OBJECT", - messageType, - receiverType - ); +### Quote a Message (Reply) -CometChat.sendMediaMessage(mediaMessage).then( - (message: CometChat.MediaMessage) => { - console.log("Media message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("Media message sending failed with error", error); - } -); +```javascript +message.setQuotedMessageId(originalMessageId); ``` - - - - -### Set Quoted Message Id - -To set a quoted message ID for a message, use the `setQuotedMessageId()` method of the MediaMessage class. This method accepts the ID of the message to be quoted. +### Add Metadata - - ```javascript -mediaMessage.setQuotedMessageId(10); +message.setMetadata({ + customKey: "customValue", + priority: "high" +}); ``` - +### Add Tags - -```typescript -mediaMessage.setQuotedMessageId(10); +```javascript +message.setTags(["important", "follow-up"]); ``` - - - - -There are 2 ways you can send Media Messages using the CometChat SDK: - -1. **By providing the File:** You can directly share the file object while creating an object of the MediaMessage class. When the media message is sent using the `sendMediaMessage()` method, this file is then uploaded to CometChat servers and the URL of the file is sent in the success response of the `sendMediaMessage()` function. - -Getting file Object: +--- - - -```html - - - - - - -``` +## Message Response - +On success, you receive a message object with: - +| Property | Description | +|----------|-------------| +| `id` | Unique message ID | +| `sender` | User object of sender | +| `receiver` | User/Group object of receiver | +| `sentAt` | Timestamp when sent | +| `type` | Message type (text, image, etc.) | +| `category` | Message category | +| `data` | Message content/payload | - + ```javascript -let receiverID = "UID"; -let messageType = CometChat.MESSAGE_TYPE.FILE; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - "INPUT FILE OBJECT", - messageType, - receiverType -); - -CometChat.sendMediaMessage(mediaMessage).then( - (message) => { - console.log("Media message sent successfully", message); - }, - (error) => { - console.log("Media message sending failed with error", error); - } -); +CometChat.sendMessage(textMessage).then((message) => { + console.log("Message ID:", message.getId()); + console.log("Sent at:", message.getSentAt()); + console.log("Sender:", message.getSender().getName()); +}); ``` - - - + ```javascript -let receiverID = "GUID"; -let messageType = CometChat.MESSAGE_TYPE.FILE; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - `INPUT FILE OBJECT`, - messageType, - receiverType -); - -CometChat.sendMediaMessage(mediaMessage).then( - (message) => { - console.log("Media message sent successfully", message); - }, - (error) => { - console.log("Media message sending failed with error", error); +async function sendAndLogMessage(textMessage) { + try { + const message = await CometChat.sendMessage(textMessage); + console.log("Message ID:", message.getId()); + console.log("Sent at:", message.getSentAt()); + console.log("Sender:", message.getSender().getName()); + return message; + } catch (error) { + console.log("Error:", error); + throw error; } -); -``` - - - - -```typescript -let receiverID: string = "UID", - messageType: string = CometChat.MESSAGE_TYPE.FILE, - receiverType: string = CometChat.RECEIVER_TYPE.USER, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - "INPUT FILE OBJECT", - messageType, - receiverType - ); - -CometChat.sendMediaMessage(mediaMessage).then( - (message: CometChat.MediaMessage) => { - console.log("Media message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("Media message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "GUID", - messageType: string = CometChat.MESSAGE_TYPE.FILE, - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - "INPUT FILE OBJECT", - messageType, - receiverType - ); - -CometChat.sendMediaMessage(mediaMessage).then( - (message: CometChat.MediaMessage) => { - console.log("Media message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("Media message sending failed with error", error); - } -); +} ``` - - -The `MediaMessage` class constructor takes the following parameters: - -| Parameter | Description | | -| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -| **receiverId** | The `UID` or `GUID` of the recipient. | Required | -| **file** | The file object to be sent | Required | -| **messageType** | The type of the message that needs to be sent which in this case can be:
1.`CometChat.MESSAGE_TYPE.IMAGE`
2.`CometChat.MESSAGE_TYPE.VIDEO`
3.`CometChat.MESSAGE_TYPE.AUDIO`
4.`CometChat.MESSAGE_TYPE.FILE` | Required | -| **receiverType** | The type of the receiver to whom the message is to be sent.
`1. CometChat.RECEIVER_TYPE.USER`
`2. CometChat.RECEIVER_TYPE.GROUP` | Required | - -2. **By providing the URL of the File:** The second way to send media messages using the CometChat SDK is to provide the SDK with the URL of any file that is hosted on your servers or any cloud storage. To achieve this you will have to make use of the Attachment class. For more information, you can refer to the below code snippet: - - - -```javascript -let receiverID = "cometchat-uid-2"; -let messageType = CometChat.MESSAGE_TYPE.IMAGE; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - "", - messageType, - receiverType -); +--- -let file = { - name: "mario", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/mario/mario_PNG125.png", -}; - -let attachment = new CometChat.Attachment(file); - -mediaMessage.setAttachment(attachment); - -CometChat.sendMediaMessage(mediaMessage).then( - (mediaMessage) => { - console.log("message", mediaMessage); - }, - (error) => { - console.log("error in sending message", error); - } -); -``` - - - - -```javascript -let receiverID = "cometchat-guid-1"; -let messageType = CometChat.MESSAGE_TYPE.IMAGE; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - "", - messageType, - receiverType -); - -let file = { - name: "mario", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/mario/mario_PNG125.png", -}; - -let attachment = new CometChat.Attachment(file); - -mediaMessage.setAttachment(attachment); - -CometChat.sendMediaMessage(mediaMessage).then( - (mediaMessage) => { - console.log("message", mediaMessage); - }, - (error) => { - console.log("error in sending message", error); - } -); -``` - - - - -```typescript -let receiverID: string = "cometchat-uid-2", - messageType: string = CometChat.MESSAGE_TYPE.IMAGE, - receiverType: string = CometChat.RECEIVER_TYPE.USER, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - "", - messageType, - receiverType - ); - -let file: Object = { - name: "mario", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/mario/mario_PNG125.png", -}; - -let attachment: CometChat.Attachment = new CometChat.Attachment(file); - -mediaMessage.setAttachment(attachment); - -CometChat.sendMediaMessage(mediaMessage).then( - (mediaMessage: CometChat.MediaMessage) => { - console.log("message", mediaMessage); - }, - (error: CometChat.CometChatException) => { - console.log("error in sending message", error); - } -); -``` - - - - -```typescript -let receiverID: string = "cometchat-guid-1", - messageType: string = CometChat.MESSAGE_TYPE.IMAGE, - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - "", - messageType, - receiverType - ); - -let file: Object = { - name: "mario", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/mario/mario_PNG125.png", -}; - -let attachment: CometChat.Attachment = new CometChat.Attachment(file); - -mediaMessage.setAttachment(attachment); - -CometChat.sendMediaMessage(mediaMessage).then( - (mediaMessage: CometChat.MediaMessage) => { - console.log("message", mediaMessage); - }, - (error: CometChat.CometChatException) => { - console.log("error in sending message", error); - } -); -``` - - - - - -When a media message is sent successfully, the response will include a `MediaMessage` object which includes all information related to the sent message. - -## Multiple Attachments in a Media Message - -Starting version 3.0.9 & above the SDK supports sending multiple attachments in a single media message. As in the case of a single attachment in a media message, there are two ways you can send Media Messages using the CometChat SDK: - -1. **By providing an array of files:** You can now share an array of files while creating an object of the MediaMessage class. When the media message is sent using the `sendMediaMessage()` method, the files are uploaded to the CometChat servers & the URL of the files is sent in the success response of the `sendMediaMessage()` method. - -Getting files: - - - -```html - - - - - - -``` - - - - - - - -```javascript -let receiverID = "UID"; -let messageType = CometChat.MESSAGE_TYPE.FILE; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - files, - messageType, - receiverType -); - -CometChat.sendMediaMessage(mediaMessage).then( - (message) => { - console.log("Media message sent successfully", message); - }, - (error) => { - console.log("Media message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "UID", - messageType: string = CometChat.MESSAGE_TYPE.FILE, - receiverType: string = CometChat.RECEIVER_TYPE.USER, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - files, - messageType, - receiverType - ); - -CometChat.sendMediaMessage(mediaMessage).then( - (message: CometChat.MediaMessage) => { - console.log("Media message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("Media message sending failed with error", error); - } -); -``` - - - - -```javascript -let receiverID = "GUID"; -let messageType = CometChat.MESSAGE_TYPE.FILE; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - files, - messageType, - receiverType -); - -CometChat.sendMediaMessage(mediaMessage).then( - (message) => { - console.log("Media message sent successfully", message); - }, - (error) => { - console.log("Media message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "GUID", - messageType: string = CometChat.MESSAGE_TYPE.FILE, - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - files, - messageType, - receiverType - ); - -CometChat.sendMediaMessage(mediaMessage).then( - (message: CometChat.MediaMessage) => { - console.log("Media message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("Media message sending failed with error", error); - } -); -``` - - - - - -The `MediaMessage` class constructor takes the following parameters: - -| Parameter | Description | -| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **receiverId** | The `UID` or `GUID` of the recipient. | -| **files** | An array of files. | -| **messageType** | The type of the message that needs to be sent which in this case can be:
1. `CometChat.MESSAGE_TYPE.IMAGE`
2. `CometChat.MESSAGE_TYPE.VIDEO`
3. `CometChat.MESSAGE_TYPE.AUDIO`
4. `CometChat.MESSAGE_TYPE.FILE` | -| **receiverType** | The type of the receiver to whom the message is to be sent.
`1. CometChat.RECEIVER_TYPE.USER`
`2. CometChat.RECEIVER_TYPE.GROUP` | - -2. **By providing the URL of the multiple files:** The second way to send multiple attachments in a single media message using the CometChat SDK is to provide the SDK with the URL of multiple files that are hosted on your servers or any cloud storage. To achieve this you will have to make use of the Attachment class. For more information, you can refer to the below code snippet: - - - -```javascript -let receiverID = "cometchat-uid-2"; -let messageType = CometChat.MESSAGE_TYPE.IMAGE; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - "", - messageType, - receiverType -); - -let attachment1 = { - name: "mario", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/mario/mario_PNG125.png", -}; - -let attachment2 = { - name: "jaguar", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/jaguar/jaguar_PNG20759.png", -}; - -let attachments = []; -attachments.push(new CometChat.Attachment(attachment1)); -attachments.push(new CometChat.Attachment(attachment2)); - -mediaMessage.setAttachments(attachments); - -CometChat.sendMediaMessage(mediaMessage).then( - (mediaMessage) => { - console.log("message", mediaMessage); - }, - (error) => { - console.log("error in sending message", error); - } -); -``` - - - - -```typescript -let receiverID: string = "cometchat-uid-2", - messageType: string = CometChat.MESSAGE_TYPE.IMAGE, - receiverType: string = CometChat.RECEIVER_TYPE.USER, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - "", - messageType, - receiverType - ); - -let attachment1: Object = { - name: "mario", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/mario/mario_PNG125.png", -}; - -let attachment2: Object = { - name: "jaguar", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/jaguar/jaguar_PNG20759.png", -}; - -let attachments: Array = []; -attachments.push(new CometChat.Attachment(attachment1)); -attachments.push(new CometChat.Attachment(attachment2)); - -mediaMessage.setAttachments(attachments); - -CometChat.sendMediaMessage(mediaMessage).then( - (mediaMessage: CometChat.MediaMessage) => { - console.log("message", mediaMessage); - }, - (error: CometChat.CometChatException) => { - console.log("error in sending message", error); - } -); -``` - - - - -```javascript -let receiverID = "cometchat-guid-1"; -let messageType = CometChat.MESSAGE_TYPE.IMAGE; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let mediaMessage = new CometChat.MediaMessage( - receiverID, - "", - messageType, - receiverType -); - -let attachment1 = { - name: "mario", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/mario/mario_PNG125.png", -}; - -let attachment2 = { - name: "jaguar", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/jaguar/jaguar_PNG20759.png", -}; - -let attachments = []; -attachments.push(new CometChat.Attachment(attachment1)); -attachments.push(new CometChat.Attachment(attachment2)); - -mediaMessage.setAttachments(attachments); - -CometChat.sendMediaMessage(mediaMessage).then( - (mediaMessage) => { - console.log("message", mediaMessage); - }, - (error) => { - console.log("error in sending message", error); - } -); -``` - - - - -```typescript -let receiverID: string = "cometchat-guid-1", - messageType: string = CometChat.MESSAGE_TYPE.IMAGE, - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - mediaMessage: CometChat.MediaMessage = new CometChat.MediaMessage( - receiverID, - "", - messageType, - receiverType - ); - -let attachment1: Object = { - name: "mario", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/mario/mario_PNG125.png", -}; - -let attachment1: Object = { - name: "jaguar", - extension: "png", - mimeType: "image/png", - url: "https://pngimg.com/uploads/jaguar/jaguar_PNG20759.png", -}; - -let attachments: Array = []; -attachments.push(new CometChat.Attachment(attachment1)); -attachments.push(new CometChat.Attachment(attachment2)); - -mediaMessage.setAttachments(attachments); - -CometChat.sendMediaMessage(mediaMessage).then( - (mediaMessage: CometChat.MediaMessage) => { - console.log("message", mediaMessage); - }, - (error: CometChat.CometChatException) => { - console.log("error in sending message", error); - } -); -``` - - - - - -When a media message is sent successfully, the response will include a `MediaMessage` object which includes all information related to the sent message. - -You can use the `setMetadata()`, `setCaption()` & `setTags()` methods to add metadata, caption and tags respectively in exactly the same way as it is done while sending a single file or attachment in a Media Message. - -## Custom Message - -*In other words, as a sender, how do I send a custom message like location coordinates?* - -CometChat allows you to send custom messages which are neither text nor media messages. - -In order to send a custom message, you need to use the `sendCustomMessage()` method. - -The `sendCustomMessage()` method takes an object of the `CustomMessage` which can be obtained using the below constructor. - - - -```js -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); -``` - - - - -```typescript -let customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); -``` - - - - - -The above constructor, helps you create a custom message with the message type set to whatever is passed to the constructor and the category set to `custom`. - -The parameters involved are: - -1. `receiverId` - The unique ID of the user or group to which the message is to be sent. -2. `receiverType` - Type of the receiver i.e user or group -3. `customType` - custom message type that you need to set -4. `customData` - The data to be passed as the message in the form of a JSON Object. - -You can also use the subType field of the `CustomMessage` class to set a specific type for the custom message. This can be achieved using the `setSubtype()` method. - -### Add Tags - -To add a tag to a message you can use the `setTags()` method of the CustomMessage Class. The `setTags()` method accepts a list of tags. - - - -```javascript -let tags = ["starredMessage"]; - -customMessage.setTags(tags); -``` - - - - -```typescript -let tags: Array = ["starredMessage"]; - -customMessage.setTags(tags); -``` - - - - - -Once the object of `CustomMessage` class is ready you can send the custom message using the `sendCustomMessage()` method. - - - -```javascript -let receiverID = "UID"; -let customData = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; -let customType = "location"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); - -CometChat.sendCustomMessage(customMessage).then( - (message) => { - console.log("custom message sent successfully", message); - }, - (error) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```javascript -let receiverID = "GUID"; -let customData = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; -let customType = "location"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); - -CometChat.sendCustomMessage(customMessage).then( - (message) => { - console.log("custom message sent successfully", message); - }, - (error) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "UID", - customData: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", - }, - customType: string = "location", - receiverType: string = CometChat.RECEIVER_TYPE.USER, - customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData - ); - -CometChat.sendCustomMessage(customMessage).then( - (message: CometChat.CustomMessage) => { - console.log("custom message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "GUID", - customData: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", - }, - customType: string = "location", - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData - ); - -CometChat.sendCustomMessage(customMessage).then( - (message: CometChat.CustomMessage) => { - console.log("custom message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - - -### Set Quoted Message Id - -To set a quoted message ID for a message, use the `setQuotedMessageId()` method of the CustomMessage class. This method accepts the ID of the message to be quoted. - - - -```javascript -customMessage.setQuotedMessageId(10); -``` - - - - -```typescript -customMessage.setQuotedMessageId(10); -``` - - - - - -Once the object of `CustomMessage` class is ready you can send the custom message using the `sendCustomMessage()` method. - - - -```javascript -let receiverID = "UID"; -let customData = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; -let customType = "location"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); - -CometChat.sendCustomMessage(customMessage).then( - (message) => { - console.log("custom message sent successfully", message); - }, - (error) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```javascript -let receiverID = "GUID"; -let customData = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; -let customType = "location"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); - -CometChat.sendCustomMessage(customMessage).then( - (message) => { - console.log("custom message sent successfully", message); - }, - (error) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "UID", - customData: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", - }, - customType: string = "location", - receiverType: string = CometChat.RECEIVER_TYPE.USER, - customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData - ); - -CometChat.sendCustomMessage(customMessage).then( - (message: CometChat.CustomMessage) => { - console.log("custom message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "GUID", - customData: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", - }, - customType: string = "location", - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData - ); - -CometChat.sendCustomMessage(customMessage).then( - (message: CometChat.CustomMessage) => { - console.log("custom message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - - -The above sample explains how custom messages can be used to share the location with a user. The same can be achieved for groups. - -On success, you will receive an object of the `CustomMessage` class. - -### Update Conversation - -*How can I decide whether the custom message should update the last message of a conversation?* - -By default, a custom message will update the last message of a conversation. If you wish to not update the last message of the conversation when a custom message is sent, please use shouldUpdateConversation(value: boolean) method of the Custom Message. - - - -```javascript -let receiverID = "UID"; -let customData = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; -let customType = "location"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); - -customMessage.shouldUpdateConversation(false); -CometChat.sendCustomMessage(customMessage).then( - (message) => { - console.log("custom message sent successfully", message); - }, - (error) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```javascript -let receiverID = "GUID"; -let customData = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; -let customType = "location"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); - -customMessage.shouldUpdateConversation(false); -CometChat.sendCustomMessage(customMessage).then( - (message) => { - console.log("custom message sent successfully", message); - }, - (error) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "UID", - customData: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", - }, - customType: string = "location", - receiverType: string = CometChat.RECEIVER_TYPE.USER, - customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData - ); - -customMessage.shouldUpdateConversation(false); -CometChat.sendCustomMessage(customMessage).then( - (message: CometChat.CustomMessage) => { - console.log("custom message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "GUID", - customData: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", - }, - customType: string = "location", - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData - ); - -customMessage.shouldUpdateConversation(false); -CometChat.sendCustomMessage(customMessage).then( - (message: CometChat.CustomMessage) => { - console.log("custom message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - - -### Custom Notification Body - -*How can i customise the notification body of custom message?* - -To add a custom notification body for `Push, Email & SMS` notification of a custom message you can use the `setConversationText(text: string)` method of Custom Message class. - - - -```javascript -let receiverID = "UID"; -let customData = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; -let customType = "location"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); - -customMessage.setConversationText("Custom notification body"); -CometChat.sendCustomMessage(customMessage).then( - (message) => { - console.log("custom message sent successfully", message); - }, - (error) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```javascript -let receiverID = "GUID"; -let customData = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", -}; -let customType = "location"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let customMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData -); - -customMessage.setConversationText("Custom notificatoin body"); -CometChat.sendCustomMessage(customMessage).then( - (message) => { - console.log("custom message sent successfully", message); - }, - (error) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "UID", - customData: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", - }, - customType: string = "location", - receiverType: string = CometChat.RECEIVER_TYPE.USER, - customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData - ); - -customMessage.setConversationText("Custom notification body"); -CometChat.sendCustomMessage(customMessage).then( - (message: CometChat.CustomMessage) => { - console.log("custom message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - -```typescript -let receiverID: string = "GUID", - customData: Object = { - latitude: "50.6192171633316", - longitude: "-72.68182268750002", - }, - customType: string = "location", - receiverType: string = CometChat.RECEIVER_TYPE.GROUP, - customMessage: CometChat.CustomMessage = new CometChat.CustomMessage( - receiverID, - receiverType, - customType, - customData - ); - -customMessage.setConversationText("Custom notification body"); -CometChat.sendCustomMessage(customMessage).then( - (message: CometChat.CustomMessage) => { - console.log("custom message sent successfully", message); - }, - (error: CometChat.CometChatException) => { - console.log("custom message sending failed with error", error); - } -); -``` - - - - - - - -It is also possible to send interactive messages from CometChat, to know more [click here](/sdk/javascript/interactive-messages) - - +## Next Steps + + + + Handle incoming messages in real-time + + + Send forms, cards, and actionable content + + + Allow users to edit sent messages + + + Show when users are typing + + diff --git a/sdk/javascript/session-timeout.mdx b/sdk/javascript/session-timeout.mdx index 23470881..e7728a7c 100644 --- a/sdk/javascript/session-timeout.mdx +++ b/sdk/javascript/session-timeout.mdx @@ -1,34 +1,260 @@ --- -title: "Session Timeout Flow" +title: "Session Timeout" +description: "Configure automatic call termination for idle participants" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Configure idle timeout (in seconds) +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIdleTimeoutPeriod(180) // 3 minutes (warning at 120s, auto-end at 180s) + .setCallListener({ + onSessionTimeout: () => { + console.log("Call auto-terminated due to inactivity"); + CometChatCalls.endSession(); + } + }) + .build(); +``` + -Available since v4.1.0 +Automatically terminate call sessions when participants are idle to prevent abandoned calls and optimize resource usage. + + +Available since Calls SDK v4.1.0 + ## Overview -CometChat Calls SDK provides a mechanism to handle session timeouts for idle participants. By default, if a participant is alone in a call session for 180 seconds (3 minutes), the following sequence is triggered: +When a participant is alone in a call session, the SDK monitors for inactivity and can automatically terminate the call: -1. After 120 seconds of being alone in the session, the participant will see a dialog box +1. After **120 seconds** alone, a warning dialog appears +2. User can choose to **stay** or **leave immediately** +3. If no action within **60 seconds**, the call auto-terminates +4. `onSessionTimeout` callback fires when auto-terminated -2. This dialog provides options to either: +## Timeout Flow - * Stay in the call - * Leave immediately + + + -3. If no action is taken within the next 60 seconds, the call will automatically end +## Configuration -This feature helps manage inactive call sessions and prevents unnecessary resource usage. The idle timeout period ensures that participants don't accidentally remain in abandoned call sessions. +Set the idle timeout period using `setIdleTimeoutPeriod()`: -### Session Timeout Flow + + +```javascript +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIdleTimeoutPeriod(300) // 5 minutes (in seconds) + .setCallListener({ + onSessionTimeout: () => { + console.log("Call auto-terminated due to inactivity"); + // Clean up and close call UI + }, + // ... other listeners + }) + .build(); +``` + + +```typescript +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIdleTimeoutPeriod(300) + .setCallListener({ + onSessionTimeout: (): void => { + console.log("Call auto-terminated due to inactivity"); + }, + // ... other listeners + }) + .build(); +``` + + - - - +## Settings + +| Method | Description | Default | +|--------|-------------|---------| +| `setIdleTimeoutPeriod(seconds)` | Time in seconds before warning appears (warning shows 60s before termination) | `180` (3 minutes) | + + +The warning dialog appears 60 seconds before the timeout. So if you set `setIdleTimeoutPeriod(180)`, the warning appears at 120 seconds and auto-terminates at 180 seconds. + + +## Handling Timeout + +Listen for the `onSessionTimeout` event to handle automatic termination: + + + +```javascript +const callListener = new CometChatCalls.OngoingCallListener({ + onSessionTimeout: () => { + console.log("Session timed out"); + + // Clean up resources + CometChatCalls.endSession(); + + // Update UI + hideCallScreen(); + showTimeoutMessage(); + }, + onCallEnded: () => { + // Normal call end (user action) + CometChatCalls.endSession(); + hideCallScreen(); + }, + // ... other listeners +}); +``` + + +```typescript +const callListener = new CometChatCalls.OngoingCallListener({ + onSessionTimeout: (): void => { + console.log("Session timed out"); + CometChatCalls.endSession(); + hideCallScreen(); + showTimeoutMessage(); + }, + onCallEnded: (): void => { + CometChatCalls.endSession(); + hideCallScreen(); + }, + // ... other listeners +}); +``` + + + +## Use Cases + +| Scenario | Recommended Timeout | +|----------|---------------------| +| Quick calls | 120 seconds (2 min) | +| Standard calls | 180 seconds (3 min, default) | +| Meetings/webinars | 300-600 seconds (5-10 min) | +| Always-on rooms | Disable or very long timeout | + +## Complete Example + + + +```javascript +const callListener = new CometChatCalls.OngoingCallListener({ + onUserJoined: (user) => { + console.log("User joined:", user.getName()); + }, + onUserLeft: (user) => { + console.log("User left:", user.getName()); + }, + onCallEnded: () => { + console.log("Call ended normally"); + cleanup(); + }, + onCallEndButtonPressed: () => { + CometChat.endCall(sessionId).then(() => { + CometChat.clearActiveCall(); + CometChatCalls.endSession(); + cleanup(); + }); + }, + onSessionTimeout: () => { + console.log("Call auto-terminated due to inactivity"); + CometChat.clearActiveCall(); + CometChatCalls.endSession(); + cleanup(); + showNotification("Call ended due to inactivity"); + }, + onError: (error) => { + console.error("Call error:", error); + } +}); + +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIsAudioOnlyCall(false) + .setIdleTimeoutPeriod(180) // 3 minutes + .setCallListener(callListener) + .build(); + +function cleanup() { + // Hide call UI + document.getElementById("call-container").style.display = "none"; +} + +function showNotification(message) { + // Show user-friendly notification + alert(message); +} +``` + + +```typescript +const callListener = new CometChatCalls.OngoingCallListener({ + onUserJoined: (user: any): void => { + console.log("User joined:", user.getName()); + }, + onUserLeft: (user: any): void => { + console.log("User left:", user.getName()); + }, + onCallEnded: (): void => { + console.log("Call ended normally"); + cleanup(); + }, + onCallEndButtonPressed: (): void => { + CometChat.endCall(sessionId).then(() => { + CometChat.clearActiveCall(); + CometChatCalls.endSession(); + cleanup(); + }); + }, + onSessionTimeout: (): void => { + console.log("Call auto-terminated due to inactivity"); + CometChat.clearActiveCall(); + CometChatCalls.endSession(); + cleanup(); + showNotification("Call ended due to inactivity"); + }, + onError: (error: any): void => { + console.error("Call error:", error); + } +}); + +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIsAudioOnlyCall(false) + .setIdleTimeoutPeriod(180) + .setCallListener(callListener) + .build(); + +function cleanup(): void { + const container = document.getElementById("call-container"); + if (container) container.style.display = "none"; +} - +function showNotification(message: string): void { + alert(message); +} +``` + + -The `onSessionTimeout` event is triggered when the call automatically terminates due to session timeout, as illustrated in the diagram above. +## Next Steps - + + + Learn about call session management + + + Handle connection state changes + + diff --git a/sdk/javascript/setup-sdk.mdx b/sdk/javascript/setup-sdk.mdx index e9bdce87..2c57d333 100644 --- a/sdk/javascript/setup-sdk.mdx +++ b/sdk/javascript/setup-sdk.mdx @@ -1,134 +1,1575 @@ --- title: "Setup" -sidebarTitle: "Overview" +sidebarTitle: "Setup" +description: "Install and configure the CometChat JavaScript SDK" --- +{/* Agent-Friendly Quick Reference */} + +**Quick Setup Reference** +```bash +# Install +npm install @cometchat/chat-sdk-javascript - -Migrating app version from v3 to v4 ? +# Initialize (run once at app start) +CometChat.init(APP_ID, appSettings) -Skip the create new app step. Your existing v3 app can be migrated to v4. +# Login (after init) +CometChat.login(UID, AUTH_KEY) # Dev only +CometChat.login(AUTH_TOKEN) # Production +``` -Follow steps mentioned in **Add the CometChat dependency** section below to upgrade to latest version of v4 +**Required Credentials:** App ID, Region, Auth Key (dev) or Auth Token (prod) +**Get from:** [CometChat Dashboard](https://app.cometchat.com) → Your App → API & Auth Keys + - +This guide walks you through the complete setup process for the CometChat JavaScript SDK, from getting your credentials to sending your first message. -## Get your Application Keys +--- -[Signup for CometChat](https://app.cometchat.com) and then: +## Prerequisites -1. Create a new app -2. Head over to the **API & Auth Keys** section and note the **Auth Key**, **App ID** & **Region** + + + [Sign up for free](https://app.cometchat.com/signup) or [log in](https://app.cometchat.com) to your existing account. + + + From the dashboard, click **Add New App**. Choose a name and select your preferred region. + + + **Region Selection:** Choose the region closest to your users for best performance: + - `us` - United States + - `eu` - Europe + - `in` - India + + + + Navigate to your app's **API & Auth Keys** section and note: + + | Credential | Where to Find | Purpose | + |------------|---------------|---------| + | **App ID** | API & Auth Keys → App ID | Identifies your app | + | **Region** | API & Auth Keys → Region | Server location | + | **Auth Key** | API & Auth Keys → Auth Key | Development login | + | **REST API Key** | API & Auth Keys → REST API Key | Server-side operations | + + -## Add the CometChat Dependency + +**Security:** Never expose your REST API Key in client-side code. Use Auth Key only for development. In production, use [Auth Tokens](/sdk/javascript/authentication-overview#login-with-auth-token). + -### NPM +--- - - -```js -npm install @cometchat/chat-sdk-javascript -``` +## Installation - +Choose your preferred package manager or CDN: + + + ```bash + npm install @cometchat/chat-sdk-javascript + ``` + + + ```bash + yarn add @cometchat/chat-sdk-javascript + ``` + + + ```bash + pnpm add @cometchat/chat-sdk-javascript + ``` + + + ```html + + ``` + -Then, import the `CometChat` object wherever you want to use CometChat. +### Import the SDK - -```js -import { CometChat } from "@cometchat/chat-sdk-javascript"; -``` + + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; + ``` + + + ```javascript + const { CometChat } = require("@cometchat/chat-sdk-javascript"); + ``` + + + ```javascript + // CometChat is available globally after script loads + window.CometChat + ``` + + - +--- - +## Initialize CometChat -### HTML (via CDN) +Initialize the SDK once when your application starts. This must be called before any other CometChat methods. -Include the CometChat JavaScript library in your HTML code. + +`CometChat.init()` must be called before `login()`, `sendMessage()`, listener registration, or any other SDK method. Calling SDK methods before initialization will fail. + - -``` - -``` + + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; + + const appID = "YOUR_APP_ID"; + const region = "YOUR_REGION"; // "us", "eu", or "in" + + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + + CometChat.init(appID, appSettings).then( + () => { + console.log("CometChat initialized successfully"); + // Now you can login and use other CometChat methods + }, + (error) => { + console.log("Initialization failed:", error); + // Handle initialization error + } + ); + ``` + + + ```typescript + import { CometChat } from "@cometchat/chat-sdk-javascript"; + + const appID: string = "YOUR_APP_ID"; + const region: string = "YOUR_REGION"; + + const appSettings: CometChat.AppSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + + CometChat.init(appID, appSettings).then( + (success: boolean): void => { + console.log("CometChat initialized successfully", success); + }, + (error: CometChat.CometChatException): void => { + console.log("Initialization failed:", error); + } + ); + ``` + + + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; + + async function initializeCometChat() { + const appID = "YOUR_APP_ID"; + const region = "YOUR_REGION"; + + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); - + try { + await CometChat.init(appID, appSettings); + console.log("CometChat initialized successfully"); + return true; + } catch (error) { + console.log("Initialization failed:", error); + return false; + } + } + // Call on app startup + initializeCometChat(); + ``` + -## Initialize CometChat + +Replace `YOUR_APP_ID` and `YOUR_REGION` with your actual credentials from the [CometChat Dashboard](https://app.cometchat.com). + -The `init()` method initialises the settings required for CometChat. The `init()` method takes the below parameters: +--- -1. appID - You CometChat App ID -2. appSettings - An object of the AppSettings class can be created using the AppSettingsBuilder class. The region field is mandatory and can be set using the `setRegion()` method. +## Complete Quick Start -The `AppSettings` class allows you to configure two settings: +Here's a complete example that initializes CometChat, logs in a test user, and sends a message: -* **Region**: The region where you app was created. -* [Presence Subscription](/sdk/javascript/user-presence)**:** Represents the subscription type for user presence (real-time online/offline status) -* **autoEstablishSocketConnection(boolean value)**: This property takes a boolean value which when set to `true` informs the SDK to manage the web-socket connection internally. If set to `false` , it informs the SDK that the web-socket connection will be managed manually. The default value for this parameter is true. For more information on this, please check the [Managing Web-Socket connections manually](/sdk/javascript/managing-web-sockets-connections-manually) section. The default value for this property is **true.** -* **overrideAdminHost(adminHost: string)**: This method takes the admin URL as input and uses this admin URL instead of the default admin URL. This can be used in case of dedicated deployment of CometChat. -* **overrideClientHost(clientHost: string)**: This method takes the client URL as input and uses this client URL instead of the default client URL. This can be used in case of dedicated deployment of CometChat. +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; -You need to call `init()` before calling any other method from CometChat. We suggest you call the `init()` method on app startup, preferably in the `index.js` file. +// Step 1: Configuration +const appID = "YOUR_APP_ID"; +const region = "YOUR_REGION"; +const authKey = "YOUR_AUTH_KEY"; - - -```js -let appID = "APP_ID"; -let region = "APP_REGION"; -let appSetting = new CometChat.AppSettingsBuilder() +// Step 2: Initialize +const appSettings = new CometChat.AppSettingsBuilder() .subscribePresenceForAllUsers() .setRegion(region) .autoEstablishSocketConnection(true) .build(); -CometChat.init(appID, appSetting).then( + +CometChat.init(appID, appSettings).then( () => { - console.log("Initialization completed successfully"); - }, + console.log("✓ CometChat initialized"); + + // Step 3: Check if already logged in + return CometChat.getLoggedinUser(); + } +).then( + (user) => { + if (user) { + console.log("✓ Already logged in as:", user.getName()); + return user; + } + + // Step 4: Login with test user + console.log("Logging in..."); + return CometChat.login("cometchat-uid-1", authKey); + } +).then( + (user) => { + console.log("✓ Logged in as:", user.getName()); + + // Step 5: Send a test message + const message = new CometChat.TextMessage( + "cometchat-uid-2", + "Hello from CometChat!", + CometChat.RECEIVER_TYPE.USER + ); + + return CometChat.sendMessage(message); + } +).then( + (message) => { + console.log("✓ Message sent:", message.getText()); + console.log("Setup complete! CometChat is ready to use."); + } +).catch( (error) => { - console.log("Initialization failed with error:", error); + console.error("Error:", error); } ); ``` - - - -```typescript -let appID: string = "APP_ID", - region: string = "APP_REGION", - appSetting: CometChat.AppSettings = new CometChat.AppSettingsBuilder() - .subscribePresenceForAllUsers() - .setRegion(region) - .autoEstablishSocketConnection(true) - .build(); -CometChat.init(appID, appSetting).then( - (initialized: boolean) => { - console.log("Initialization completed successfully", initialized); - }, - (error: CometChat.CometChatException) => { - console.log("Initialization failed with error:", error); - } -); + +**Test Users:** CometChat provides 5 pre-created test users: `cometchat-uid-1` through `cometchat-uid-5`. Use these for development and testing. + + +--- + +## Configuration Options + +### AppSettingsBuilder Reference + +| Method | Description | Default | +|--------|-------------|---------| +| `setRegion(region)` | **Required.** Server region (`us`, `eu`, `in`) | - | +| `subscribePresenceForAllUsers()` | Receive online/offline status for all users | Disabled | +| `subscribePresenceForRoles(roles)` | Receive presence for specific roles only | - | +| `subscribePresenceForFriends()` | Receive presence for friends only | - | +| `autoEstablishSocketConnection(bool)` | Auto-manage WebSocket connection | `true` | +| `setStorageMode(mode)` | Data persistence mode | `LOCAL` | +| `overrideAdminHost(url)` | Custom admin URL (dedicated deployment) | - | +| `overrideClientHost(url)` | Custom client URL (dedicated deployment) | - | + +### Presence Subscription Options + +Choose how to receive user online/offline status updates: + + + + ```javascript + // Best for small apps (< 1000 users) + const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(region) + .subscribePresenceForAllUsers() + .build(); + ``` + + + Can be resource-intensive with many users. Consider role-based or friends-only for larger apps. + + + + ```javascript + // Best for apps with user tiers + const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(region) + .subscribePresenceForRoles(["premium", "moderator", "admin"]) + .build(); + ``` + + + ```javascript + // Best for social apps + const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(region) + .subscribePresenceForFriends() + .build(); + ``` + + + ```javascript + // Minimal setup - no presence tracking + const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(region) + .build(); + ``` + + + +### Storage Modes + +Control how CometChat persists data in the browser: + +```javascript +// Session storage - cleared when browser closes +const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(region) + .setStorageMode(CometChat.StorageMode.SESSION) + .build(); + +// Local storage (default) - persists across sessions +const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(region) + .setStorageMode(CometChat.StorageMode.LOCAL) + .build(); ``` - +| Mode | Persistence | Use Case | +|------|-------------|----------| +| `LOCAL` | Survives browser restart | Default, most apps | +| `SESSION` | Cleared on tab close | Shared computers, kiosks | + +### WebSocket Connection + +By default, the SDK automatically manages WebSocket connections. For advanced control: + +```javascript +// Automatic (default) - SDK manages connection +const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + +// Manual - you control when to connect/disconnect +const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(region) + .autoEstablishSocketConnection(false) + .build(); + +// Later, manually connect +CometChat.connect(); + +// And disconnect when needed +CometChat.disconnect(); +``` + +Learn more about [Manual WebSocket Management](/sdk/javascript/managing-web-sockets-connections-manually). + +--- + +## Framework Integration + +Choose your framework below. Each guide follows the same pattern: +1. Install the SDK +2. Set up environment variables +3. Create a CometChat service/provider +4. Initialize on app load +5. Use in your components + + + + ### React Setup + + + + ```bash + npm install @cometchat/chat-sdk-javascript + ``` + + + + Create `.env` in your project root: + ```bash + REACT_APP_COMETCHAT_APP_ID=your_app_id + REACT_APP_COMETCHAT_REGION=us + REACT_APP_COMETCHAT_AUTH_KEY=your_auth_key + ``` + + + + Create `src/hooks/useCometChat.js`: + ```javascript + import { useEffect, useState } from "react"; + import { CometChat } from "@cometchat/chat-sdk-javascript"; + + const APP_ID = process.env.REACT_APP_COMETCHAT_APP_ID; + const REGION = process.env.REACT_APP_COMETCHAT_REGION; + const AUTH_KEY = process.env.REACT_APP_COMETCHAT_AUTH_KEY; + + export function useCometChat() { + const [isInitialized, setIsInitialized] = useState(false); + const [user, setUser] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + const init = async () => { + try { + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(REGION) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init(APP_ID, appSettings); + setIsInitialized(true); + + const loggedInUser = await CometChat.getLoggedinUser(); + if (loggedInUser) { + setUser(loggedInUser); + } + } catch (err) { + setError(err.message); + } + }; + + init(); + }, []); + + const login = async (uid) => { + try { + const loggedInUser = await CometChat.login(uid, AUTH_KEY); + setUser(loggedInUser); + return loggedInUser; + } catch (err) { + setError(err.message); + throw err; + } + }; + + const logout = async () => { + await CometChat.logout(); + setUser(null); + }; + + return { isInitialized, user, error, login, logout, CometChat }; + } + ``` + + + + Update `src/App.jsx`: + ```jsx + import { useCometChat } from "./hooks/useCometChat"; + + function App() { + const { isInitialized, user, error, login, logout } = useCometChat(); + + if (error) return
Error: {error}
; + if (!isInitialized) return
Initializing CometChat...
; + + if (!user) { + return ( + + ); + } + + return ( +
+

Welcome, {user.getName()}!

+ + {/* Add your chat components here */} +
+ ); + } + + export default App; + ``` +
+ + + ```bash + npm start + ``` + Open http://localhost:3000 and click "Login to Chat". + +
+
+ + + ### Next.js 13+ App Router Setup + + + CometChat requires browser APIs. Use dynamic imports and `"use client"` directive to avoid SSR issues. + + + + + ```bash + npm install @cometchat/chat-sdk-javascript + ``` + + + + Create `.env.local` in your project root: + ```bash + NEXT_PUBLIC_COMETCHAT_APP_ID=your_app_id + NEXT_PUBLIC_COMETCHAT_REGION=us + NEXT_PUBLIC_COMETCHAT_AUTH_KEY=your_auth_key + ``` + + + + Create `app/providers/CometChatProvider.jsx`: + ```jsx + "use client"; + + import { createContext, useContext, useEffect, useState } from "react"; + + const CometChatContext = createContext(null); + + export function CometChatProvider({ children }) { + const [cometChat, setCometChat] = useState(null); + const [isReady, setIsReady] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + const initCometChat = async () => { + try { + // Dynamic import to avoid SSR issues + const { CometChat } = await import("@cometchat/chat-sdk-javascript"); + + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(process.env.NEXT_PUBLIC_COMETCHAT_REGION) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init( + process.env.NEXT_PUBLIC_COMETCHAT_APP_ID, + appSettings + ); + + setCometChat(CometChat); + setIsReady(true); + } catch (err) { + setError(err.message); + } + }; + + initCometChat(); + }, []); + + if (error) return
CometChat Error: {error}
; + if (!isReady) return
Loading CometChat...
; + + return ( + + {children} + + ); + } + + export const useCometChat = () => useContext(CometChatContext); + ``` +
+ + + Update `app/layout.jsx`: + ```jsx + import { CometChatProvider } from "./providers/CometChatProvider"; + export default function RootLayout({ children }) { + return ( + + + + {children} + + + + ); + } + ``` + + + + Create `app/chat/page.jsx`: + ```jsx + "use client"; + + import { useCometChat } from "../providers/CometChatProvider"; + import { useState } from "react"; + + export default function ChatPage() { + const CometChat = useCometChat(); + const [user, setUser] = useState(null); + + const handleLogin = async () => { + try { + const loggedInUser = await CometChat.login( + "cometchat-uid-1", + process.env.NEXT_PUBLIC_COMETCHAT_AUTH_KEY + ); + setUser(loggedInUser); + } catch (error) { + console.error("Login failed:", error); + } + }; + + if (!user) { + return ; + } + + return
Welcome, {user.getName()}!
; + } + ``` +
+ + + ```bash + npm run dev + ``` + Open http://localhost:3000/chat and click "Login to Chat". + +
+
+ + + ### Next.js Pages Router Setup + + + + ```bash + npm install @cometchat/chat-sdk-javascript + ``` + + + + Create `.env.local`: + ```bash + NEXT_PUBLIC_COMETCHAT_APP_ID=your_app_id + NEXT_PUBLIC_COMETCHAT_REGION=us + NEXT_PUBLIC_COMETCHAT_AUTH_KEY=your_auth_key + ``` + + + + Create `lib/cometchat.js`: + ```javascript + import { createContext, useContext } from "react"; + + export const CometChatContext = createContext(null); + export const useCometChat = () => useContext(CometChatContext); + ``` + + + + Update `pages/_app.js`: + ```jsx + import { useEffect, useState } from "react"; + import { CometChatContext } from "../lib/cometchat"; + + export default function App({ Component, pageProps }) { + const [cometChat, setCometChat] = useState(null); + + useEffect(() => { + const init = async () => { + const { CometChat } = await import("@cometchat/chat-sdk-javascript"); + + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(process.env.NEXT_PUBLIC_COMETCHAT_REGION) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init( + process.env.NEXT_PUBLIC_COMETCHAT_APP_ID, + appSettings + ); + + setCometChat(CometChat); + }; + + init(); + }, []); + + if (!cometChat) return
Loading CometChat...
; + + return ( + + + + ); + } + ``` +
+ + + Create `pages/chat.js`: + ```jsx + import { useState } from "react"; + import { useCometChat } from "../lib/cometchat"; + + export default function ChatPage() { + const CometChat = useCometChat(); + const [user, setUser] = useState(null); + + const handleLogin = async () => { + const loggedInUser = await CometChat.login( + "cometchat-uid-1", + process.env.NEXT_PUBLIC_COMETCHAT_AUTH_KEY + ); + setUser(loggedInUser); + }; + + if (!user) { + return ; + } + + return
Welcome, {user.getName()}!
; + } + ``` +
+ + + ```bash + npm run dev + ``` + Open http://localhost:3000/chat. + +
+
+ + + ### Vue.js Setup + + + + ```bash + npm install @cometchat/chat-sdk-javascript + ``` + + + + Create `.env` in your project root: + ```bash + VITE_COMETCHAT_APP_ID=your_app_id + VITE_COMETCHAT_REGION=us + VITE_COMETCHAT_AUTH_KEY=your_auth_key + ``` + + + + Create `src/plugins/cometchat.js`: + ```javascript + import { CometChat } from "@cometchat/chat-sdk-javascript"; + + export default { + install: async (app) => { + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(import.meta.env.VITE_COMETCHAT_REGION) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init( + import.meta.env.VITE_COMETCHAT_APP_ID, + appSettings + ); + + // Make CometChat available globally + app.config.globalProperties.$CometChat = CometChat; + app.provide("CometChat", CometChat); + }, + }; + ``` + + + + Update `src/main.js`: + ```javascript + import { createApp } from "vue"; + import App from "./App.vue"; + import CometChatPlugin from "./plugins/cometchat"; + + const app = createApp(App); + + // Initialize CometChat before mounting + CometChatPlugin.install(app).then(() => { + app.mount("#app"); + }); + ``` + + + + Update `src/App.vue`: + ```vue + + + + ``` + + + + ```bash + npm run dev + ``` + Open http://localhost:5173 and click "Login to Chat". + + + + + + ### Nuxt 3 Setup + + + Use the `.client.js` suffix for plugins to ensure they only run on the client side. + + + + + ```bash + npm install @cometchat/chat-sdk-javascript + ``` + + + + Update `nuxt.config.ts`: + ```typescript + export default defineNuxtConfig({ + runtimeConfig: { + public: { + cometchatAppId: process.env.COMETCHAT_APP_ID, + cometchatRegion: process.env.COMETCHAT_REGION, + cometchatAuthKey: process.env.COMETCHAT_AUTH_KEY, + }, + }, + }); + ``` + + Create `.env`: + ```bash + COMETCHAT_APP_ID=your_app_id + COMETCHAT_REGION=us + COMETCHAT_AUTH_KEY=your_auth_key + ``` + + + + Create `plugins/cometchat.client.js`: + ```javascript + export default defineNuxtPlugin(async () => { + const { CometChat } = await import("@cometchat/chat-sdk-javascript"); + const config = useRuntimeConfig(); + + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(config.public.cometchatRegion) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init(config.public.cometchatAppId, appSettings); + + return { + provide: { + CometChat, + }, + }; + }); + ``` + + + + Create `composables/useCometChat.js`: + ```javascript + export const useCometChatAuth = () => { + const { $CometChat } = useNuxtApp(); + const config = useRuntimeConfig(); + const user = useState("cometchat-user", () => null); + + const login = async (uid) => { + user.value = await $CometChat.login(uid, config.public.cometchatAuthKey); + return user.value; + }; + + const logout = async () => { + await $CometChat.logout(); + user.value = null; + }; + + const checkSession = async () => { + user.value = await $CometChat.getLoggedinUser(); + return user.value; + }; + + return { user, login, logout, checkSession }; + }; + ``` + + + + Create `pages/chat.vue`: + ```vue + + + + ``` + + + + ```bash + npm run dev + ``` + Open http://localhost:3000/chat. + + + + + + ### Angular Setup + + + + ```bash + npm install @cometchat/chat-sdk-javascript + ``` + + + + Update `src/environments/environment.ts`: + ```typescript + export const environment = { + production: false, + cometchatAppId: "your_app_id", + cometchatRegion: "us", + cometchatAuthKey: "your_auth_key", + }; + ``` + + + + Generate and update `src/app/services/cometchat.service.ts`: + ```bash + ng generate service services/cometchat + ``` + + ```typescript + import { Injectable } from "@angular/core"; + import { CometChat } from "@cometchat/chat-sdk-javascript"; + import { environment } from "../../environments/environment"; + + @Injectable({ + providedIn: "root", + }) + export class CometChatService { + private initialized = false; + + async init(): Promise { + if (this.initialized) return true; + + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(environment.cometchatRegion) + .autoEstablishSocketConnection(true) + .build(); + + try { + await CometChat.init(environment.cometchatAppId, appSettings); + this.initialized = true; + return true; + } catch (error) { + console.error("CometChat init failed:", error); + return false; + } + } + + async login(uid: string): Promise { + return CometChat.login(uid, environment.cometchatAuthKey); + } + + async getLoggedInUser(): Promise { + return CometChat.getLoggedinUser(); + } + + async logout(): Promise { + return CometChat.logout(); + } + + getCometChat() { + return CometChat; + } + } + ``` + + + + Update `src/app/app.component.ts`: + ```typescript + import { Component, OnInit } from "@angular/core"; + import { CometChatService } from "./services/cometchat.service"; + + @Component({ + selector: "app-root", + template: ` +
Initializing CometChat...
+
+ +
+
+

Welcome, {{ user.getName() }}!

+ + +
+ `, + }) + export class AppComponent implements OnInit { + isReady = false; + user: any = null; + + constructor(private cometChatService: CometChatService) {} + + async ngOnInit() { + this.isReady = await this.cometChatService.init(); + if (this.isReady) { + this.user = await this.cometChatService.getLoggedInUser(); + } + } + + async login() { + try { + this.user = await this.cometChatService.login("cometchat-uid-1"); + } catch (error) { + console.error("Login failed:", error); + } + } + + async logout() { + await this.cometChatService.logout(); + this.user = null; + } + } + ``` +
+ + + ```bash + ng serve + ``` + Open http://localhost:4200 and click "Login to Chat". + +
+
+ + + ### Vanilla JavaScript Setup + + + + Create `index.html`: + ```html + + + + + + CometChat Demo + + + + +
+
Initializing CometChat...
+ + + + +
+ + + + + ``` +
+ + + Create `app.js`: + ```javascript + // Configuration - Replace with your credentials + const APP_ID = "YOUR_APP_ID"; + const REGION = "YOUR_REGION"; + const AUTH_KEY = "YOUR_AUTH_KEY"; + + // Initialize CometChat + async function init() { + const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(REGION) + .autoEstablishSocketConnection(true) + .build(); + + try { + await CometChat.init(APP_ID, appSettings); + console.log("CometChat initialized"); + + // Check for existing session + const user = await CometChat.getLoggedinUser(); + if (user) { + showChat(user); + } else { + showLogin(); + } + } catch (error) { + console.error("Init failed:", error); + document.getElementById("loading").textContent = "Failed to initialize: " + error.message; + } + } + + async function login() { + try { + const user = await CometChat.login("cometchat-uid-1", AUTH_KEY); + showChat(user); + setupMessageListener(); + } catch (error) { + console.error("Login failed:", error); + alert("Login failed: " + error.message); + } + } + + async function logout() { + await CometChat.logout(); + CometChat.removeMessageListener("MESSAGE_LISTENER"); + showLogin(); + } + + async function sendMessage() { + const text = document.getElementById("messageInput").value.trim(); + if (!text) return; + + const message = new CometChat.TextMessage( + "cometchat-uid-2", + text, + CometChat.RECEIVER_TYPE.USER + ); + + try { + const sent = await CometChat.sendMessage(message); + appendMessage(sent, true); + document.getElementById("messageInput").value = ""; + } catch (error) { + console.error("Send failed:", error); + } + } + + function setupMessageListener() { + CometChat.addMessageListener( + "MESSAGE_LISTENER", + new CometChat.MessageListener({ + onTextMessageReceived: (message) => { + appendMessage(message, false); + }, + }) + ); + } + + function appendMessage(message, isSent) { + const messagesDiv = document.getElementById("messages"); + const messageEl = document.createElement("div"); + messageEl.className = "message"; + messageEl.style.textAlign = isSent ? "right" : "left"; + messageEl.style.background = isSent ? "#007bff" : "#f0f0f0"; + messageEl.style.color = isSent ? "white" : "black"; + messageEl.textContent = message.getText(); + messagesDiv.appendChild(messageEl); + messagesDiv.scrollTop = messagesDiv.scrollHeight; + } + + function showLogin() { + document.getElementById("loading").style.display = "none"; + document.getElementById("login").style.display = "block"; + document.getElementById("chat").style.display = "none"; + } + + function showChat(user) { + document.getElementById("loading").style.display = "none"; + document.getElementById("login").style.display = "none"; + document.getElementById("chat").style.display = "block"; + document.getElementById("username").textContent = user.getName(); + } + + // Handle Enter key in message input + document.addEventListener("DOMContentLoaded", () => { + document.getElementById("messageInput")?.addEventListener("keypress", (e) => { + if (e.key === "Enter") sendMessage(); + }); + }); + + // Start initialization + init(); + ``` + + + + Open `index.html` in a browser, or use a local server: + ```bash + npx serve . + ``` + Open http://localhost:3000 and click "Login as Test User". + +
+
-Make sure you replace the `APP_ID` with your CometChat **App ID** and `APP_REGION` with your **App Region** in the above code. +--- + +## Verify Your Setup + +Run this verification script to ensure everything is configured correctly: + +```javascript +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +async function verifySetup() { + const APP_ID = "YOUR_APP_ID"; + const REGION = "YOUR_REGION"; + const AUTH_KEY = "YOUR_AUTH_KEY"; + + console.log("🔍 Verifying CometChat setup...\n"); + + // Step 1: Initialize + try { + const appSettings = new CometChat.AppSettingsBuilder() + .setRegion(REGION) + .build(); + + await CometChat.init(APP_ID, appSettings); + console.log("✅ Step 1: Initialization successful"); + } catch (error) { + console.log("❌ Step 1: Initialization failed"); + console.log(" Error:", error.message); + console.log(" → Check your APP_ID and REGION"); + return; + } + + // Step 2: Login + try { + const user = await CometChat.login("cometchat-uid-1", AUTH_KEY); + console.log("✅ Step 2: Login successful as", user.getName()); + } catch (error) { + console.log("❌ Step 2: Login failed"); + console.log(" Error:", error.message); + console.log(" → Check your AUTH_KEY"); + return; + } + + // Step 3: Send test message + try { + const message = new CometChat.TextMessage( + "cometchat-uid-2", + "Test message from setup verification", + CometChat.RECEIVER_TYPE.USER + ); + const sent = await CometChat.sendMessage(message); + console.log("✅ Step 3: Message sent successfully (ID:", sent.getId() + ")"); + } catch (error) { + console.log("❌ Step 3: Message send failed"); + console.log(" Error:", error.message); + return; + } + + // Step 4: Fetch messages + try { + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setUID("cometchat-uid-2") + .setLimit(5) + .build(); + const messages = await messagesRequest.fetchPrevious(); + console.log("✅ Step 4: Fetched", messages.length, "messages"); + } catch (error) { + console.log("❌ Step 4: Fetch messages failed"); + console.log(" Error:", error.message); + return; + } + + console.log("\n🎉 All checks passed! CometChat is ready to use."); +} + +verifySetup(); +``` + +--- + +## Troubleshooting + + + + **Cause:** App ID or Region doesn't match your dashboard settings. + + **Solution:** + 1. Go to [CometChat Dashboard](https://app.cometchat.com) + 2. Select your app + 3. Navigate to **API & Auth Keys** + 4. Copy the exact App ID and Region + 5. Region must be lowercase: `us`, `eu`, or `in` + + ```javascript + // ❌ Wrong + const region = "US"; + const region = "United States"; + + // ✅ Correct + const region = "us"; + ``` + + + + **Cause:** SDK not imported or loaded before use. + + **Solution for ES Modules:** + ```javascript + // Make sure import is at the top of your file + import { CometChat } from "@cometchat/chat-sdk-javascript"; + ``` + + **Solution for CDN:** + ```html + + + + ``` + + + + **Cause:** CometChat requires browser APIs (window, localStorage) not available during server-side rendering. + + **Solution:** Use dynamic imports and ensure code runs only on client: + + ```javascript + // Next.js App Router + "use client"; + + useEffect(() => { + const init = async () => { + const { CometChat } = await import("@cometchat/chat-sdk-javascript"); + // Initialize here + }; + init(); + }, []); + ``` + + ```javascript + // Nuxt - use .client.js suffix + // plugins/cometchat.client.js + ``` + + + + **Cause:** Using wrong Auth Key or REST API Key instead of Auth Key. + + **Solution:** + 1. Go to Dashboard → API & Auth Keys + 2. Use the **Auth Key** (not REST API Key) + 3. Ensure no extra spaces when copying + + + Auth Key is for development only. Use [Auth Tokens](/sdk/javascript/authentication-overview#login-with-auth-token) in production. + + + + + **Cause:** Trying to login with a UID that hasn't been created. + + **Solution:** Use test users or create the user first: + + ```javascript + // Option 1: Use pre-created test users + CometChat.login("cometchat-uid-1", authKey); + + // Option 2: Create user first (development only) + const user = new CometChat.User("new-user-id"); + user.setName("New User"); + await CometChat.createUser(user, authKey); + await CometChat.login("new-user-id", authKey); + ``` + + + + **Cause:** Network restrictions, firewall, or VPN blocking WebSocket connections. + + **Solution:** + 1. Check if WebSockets are blocked by your network + 2. Try disabling VPN temporarily + 3. Check browser console for connection errors + 4. Verify `autoEstablishSocketConnection(true)` is set + + ```javascript + // Monitor connection status + CometChat.addConnectionListener( + "CONNECTION_LISTENER", + new CometChat.ConnectionListener({ + onConnected: () => console.log("Connected"), + onDisconnected: () => console.log("Disconnected"), + inConnecting: () => console.log("Connecting...") + }) + ); + ``` + + + + **Cause:** Message listener not registered or using wrong listener ID. + + **Solution:** + ```javascript + // Register listener AFTER login + CometChat.addMessageListener( + "UNIQUE_LISTENER_ID", // Must be unique + new CometChat.MessageListener({ + onTextMessageReceived: (message) => { + console.log("Message received:", message); + } + }) + ); + ``` + + + Listeners must be registered after successful login and use unique IDs. + + + + +--- + +## Migration from v3 + + +**Upgrading from v3?** See the complete [Migration Guide](/sdk/javascript/upgrading-from-v3) for step-by-step instructions. + + +Key changes in v4: +- New package name: `@cometchat/chat-sdk-javascript` +- Updated initialization with `AppSettingsBuilder` +- Improved TypeScript support +- New features: reactions, interactive messages, enhanced presence + +--- + +## Next Steps -| Parameter | Description | -| ---------- | ----------------------------------- | -| appID | CometChat App ID | -| appSetting | An object of the AppSettings class. | + + + Learn about Auth Keys vs Auth Tokens and secure login flows + + + Send text, media, and custom messages + + + Handle real-time messages and fetch history + + + Understand users, groups, and message types + + diff --git a/sdk/javascript/standalone-calling.mdx b/sdk/javascript/standalone-calling.mdx index 09df82d0..419a63ec 100644 --- a/sdk/javascript/standalone-calling.mdx +++ b/sdk/javascript/standalone-calling.mdx @@ -2,6 +2,32 @@ title: "Standalone Calling" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// 1. Generate call token (requires user auth token from REST API) +const callToken = await CometChatCalls.generateToken(sessionId, userAuthToken); + +// 2. Configure call settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setIsAudioOnlyCall(false) + .setCallListener({ + onCallEnded: () => CometChatCalls.endSession(), + onCallEndButtonPressed: () => CometChatCalls.endSession() + }) + .build(); + +// 3. Start call session +CometChatCalls.startSession(callToken.token, callSettings, document.getElementById("call-container")); + +// 4. End session +CometChatCalls.endSession(); +``` + + ## Overview This section demonstrates how to implement calling functionality using only the CometChat Calls SDK, without requiring the Chat SDK. This is ideal for applications that need video/audio calling capabilities without the full chat infrastructure. @@ -70,6 +96,22 @@ CometChatCalls.generateToken(sessionId, userAuthToken).then( ); ``` + +```javascript +const generateCallToken = async () => { + try { + const sessionId = "UNIQUE_SESSION_ID"; // Generate a unique session ID + const userAuthToken = "USER_AUTH_TOKEN"; // Obtained from REST API + + const callToken = await CometChatCalls.generateToken(sessionId, userAuthToken); + console.log("Call token generated:", callToken.token); + // Use callToken to start the session + } catch (error) { + console.log("Token generation failed:", error); + } +}; +``` +
| Parameter | Description | diff --git a/sdk/javascript/threaded-messages.mdx b/sdk/javascript/threaded-messages.mdx index e2d29a55..f5bff4b4 100644 --- a/sdk/javascript/threaded-messages.mdx +++ b/sdk/javascript/threaded-messages.mdx @@ -1,273 +1,450 @@ --- title: "Threaded Messages" +sidebarTitle: "Threaded Messages" +description: "Create organized conversation threads attached to parent messages" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Send a thread reply +const textMessage = new CometChat.TextMessage(receiverID, "Reply text", receiverType); +textMessage.setParentMessageId(parentMessageId); // Required for thread +await CometChat.sendMessage(textMessage); + +// Fetch thread messages +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setParentMessageId(parentMessageId) + .setLimit(30) + .build(); +const threadMessages = await messagesRequest.fetchPrevious(); + +// Hide thread replies in main chat +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(guid) + .hideReplies(true) + .build(); + +// Get reply count +const replyCount = message.getReplyCount(); + +// Listen for thread messages +if (message.getParentMessageId() === activeThreadId) { + // This is a thread reply +} +``` + -Messages that are started from a particular message are called Threaded messages or simply threads. Each Thread is attached to a message which is the Parent message for that thread. +Threaded messages are replies attached to a specific parent message. They help organize discussions by keeping related messages grouped together, especially useful in busy group conversations. -## Send Message in a Thread + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + -As mentioned in the [Send a Message](/sdk/javascript/send-message) section. You can either send a message to a User or a Group based on the `receiverType` and the UID/GUID specified for the message. A message can belong to either of the below types: +--- + +--- -1. Text Message -2. Media Message -3. Custom Message. +## How Threads Work -Any of the above messages can be sent in a thread. As mentioned, a thread is identified based on the Parent message. So while sending a message the `parentMessageId` must be set for the message to indicate that the message to be sent needs to be a part of the thread with the specified `parentMessageId`. +``` +┌─────────────────────────────────────┐ +│ Parent Message (ID: 100) │ +│ "What should we do for the launch?" │ +└─────────────────────────────────────┘ + │ + ├── Reply 1 (parentMessageId: 100) + │ "I think we should focus on social media" + │ + ├── Reply 2 (parentMessageId: 100) + │ "Agreed, let's create a content calendar" + │ + └── Reply 3 (parentMessageId: 100) + "I'll draft some posts by Friday" +``` + +--- -This can be achieved using the `setParentMessageId()` method provided by the object of the `TextMessage`, `MediaMessage` and `CustomMessage` class. The id specified in the `setParentMessageId()` method maps the message sent to the particular thread. +## Send a Thread Reply -**Example to Send a Text Message in a thread in a user conversation.** +Set the `parentMessageId` to send a message as part of a thread: - + ```javascript -let textMessage = new CometChat.TextMessage(UID, "Hello", CometChat.RECEIVER_TYPE.USER); -textMessage.setParentMessageId(100); +const receiverID = "UID"; +const parentMessageId = 100; + +const textMessage = new CometChat.TextMessage( + receiverID, + "This is a reply in the thread", + CometChat.RECEIVER_TYPE.USER +); + +textMessage.setParentMessageId(parentMessageId); CometChat.sendMessage(textMessage).then( - message => { - console.log('Message sent successfully', message); - }, err => { - console.log('err', err); - } -) + (message) => console.log("Thread reply sent:", message), + (error) => console.log("Failed to send:", error) +); ``` - + +```javascript +const receiverID = "GUID"; +const parentMessageId = 100; + +const mediaMessage = new CometChat.MediaMessage( + receiverID, + file, + CometChat.MESSAGE_TYPE.IMAGE, + CometChat.RECEIVER_TYPE.GROUP +); +mediaMessage.setParentMessageId(parentMessageId); + +CometChat.sendMediaMessage(mediaMessage).then( + (message) => console.log("Media sent in thread:", message), + (error) => console.log("Failed to send:", error) +); +``` + ```typescript -let receiverId = "UID", - receiverType: string = CometChat.RECEIVER_TYPE.USER, - textMessage: CometChat.TextMessage = new CometChat.TextMessage(receiverId, "Hello", receiverType), - messageId: number = 100; +const receiverID: string = "UID"; +const parentMessageId: number = 100; -textMessage.setParentMessageId(messageId); +const textMessage: CometChat.TextMessage = new CometChat.TextMessage( + receiverID, + "This is a reply in the thread", + CometChat.RECEIVER_TYPE.USER +); + +textMessage.setParentMessageId(parentMessageId); CometChat.sendMessage(textMessage).then( - (message: CometChat.TextMessage) => { - console.log('Message sent successfully', message); - }, (error: CometChat.CometChatException) => { - console.log('Message sending failed', error); - } + (message: CometChat.TextMessage) => console.log("Thread reply sent:", message), + (error: CometChat.CometChatException) => console.log("Failed to send:", error) ); ``` - - + +```javascript +const sendThreadReply = async () => { + try { + const receiverID = "UID"; + const parentMessageId = 100; + + const textMessage = new CometChat.TextMessage( + receiverID, + "This is a reply in the thread", + CometChat.RECEIVER_TYPE.USER + ); + + textMessage.setParentMessageId(parentMessageId); + + const message = await CometChat.sendMessage(textMessage); + console.log("Thread reply sent:", message); + } catch (error) { + console.log("Failed to send:", error); + } +}; +``` + -The above snippet shows how a message with the text "Hello" can be sent in the thread with `parentMessageId` 100. - -Similarly, using the `setParentMessageId()` method, Media and Custom Messages can be sent in threads too. - -### Receiving Real-Time Messages +--- -The procedure to receive real-time messages is exactly the same as mentioned in the [Receive Messages](/sdk/javascript/receive-message). This can be achieved using the `MessageListener` class provided by the SDK. +## Fetch Thread Messages -To add a MessageListener, you can use the `addMessageListener()` method of the SDK. The only thing that needs to be checked is if the received message belongs to the active thread. This can be done using the `parentMessageId` field of the message object. +Retrieve all messages in a specific thread: - + ```javascript -var listenerID = "UNIQUE_LISTENER_ID"; -var activeThreadId = 100; +const parentMessageId = 100; +const limit = 30; -CometChat.addMessageListener( -listenerID, -new CometChat.MessageListener({ - onTextMessageReceived: textMessage => { - if(textMessage.getParentMessageId() == activeThreadId) { - console.log("Text message received for active thread.", textMessage); - } - }, - onMediaMessageReceived: mediaMessage => { - if(mediaMessage.getParentMessageId() == activeThreadId) { - console.log("Media message received for active thread.", mediaMessage); - } - }, - onCustomMessageReceived: customMessage => { - if(customMessage.getParentMessageId() == activeThreadId) { - console.log("Custom message received for active thread.", customMessage); - } - } -}) +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setParentMessageId(parentMessageId) + .setLimit(limit) + .build(); + +messagesRequest.fetchPrevious().then( + (messages) => console.log("Thread messages:", messages), + (error) => console.log("Failed to fetch:", error) ); ``` - - ```typescript -var listenerID: string = "UNIQUE_LISTENER_ID", - activeThreadId: number = 100; +const parentMessageId: number = 100; +const limit: number = 30; + +const messagesRequest: CometChat.MessagesRequest = new CometChat.MessagesRequestBuilder() + .setParentMessageId(parentMessageId) + .setLimit(limit) + .build(); + +messagesRequest.fetchPrevious().then( + (messages: CometChat.BaseMessage[]) => console.log("Thread messages:", messages), + (error: CometChat.CometChatException) => console.log("Failed to fetch:", error) +); +``` + + +```javascript +const fetchThreadMessages = async () => { + try { + const parentMessageId = 100; + const limit = 30; + + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setParentMessageId(parentMessageId) + .setLimit(limit) + .build(); + + const messages = await messagesRequest.fetchPrevious(); + console.log("Thread messages:", messages); + } catch (error) { + console.log("Failed to fetch:", error); + } +}; +``` + + + + +Use `fetchPrevious()` to load older messages and `fetchNext()` to load newer ones. Maximum 100 messages per request. + + +--- + +## Real-Time Thread Messages + +Listen for new messages in a thread: + +```javascript +const listenerID = "THREAD_LISTENER"; +const activeThreadId = 100; CometChat.addMessageListener( listenerID, new CometChat.MessageListener({ - onTextMessageReceived: (textMessage: CometChat.TextMessage) => { - if (textMessage.getParentMessageId() == activeThreadId) { - console.log("Text message received for active thread.", textMessage); - } - }, - onMediaMessageReceived: (mediaMessage: CometChat.MediaMessage) => { - if (mediaMessage.getParentMessageId() == activeThreadId) { - console.log("Media message received for active thread.", mediaMessage); - } - }, - onCustomMessageReceived: (customMessage: CometChat.CustomMessage) => { - if (customMessage.getParentMessageId() == activeThreadId) { - console.log("Custom message received for active thread.", customMessage); - } + onTextMessageReceived: (message) => { + if (message.getParentMessageId() === activeThreadId) { + console.log("New thread message:", message); + } + }, + onMediaMessageReceived: (message) => { + if (message.getParentMessageId() === activeThreadId) { + console.log("New media in thread:", message); + } + }, + onCustomMessageReceived: (message) => { + if (message.getParentMessageId() === activeThreadId) { + console.log("New custom message in thread:", message); } + } }) ); -``` - - -
+// Remove listener when done +CometChat.removeMessageListener(listenerID); +``` -### Fetch all the messages for any particular thread. +--- -You can fetch all the messages belonging to a particular thread by using the `MessagesRequest` class. In order to get an object of the `MessagesRequest` class, you need to use the `MessagesRequestBuilder` class. and use the `setParentMessageId()` method of the `MessagesRequestBuilder` to inform the SDK that you only need the messages belonging to the thread with the specified parentMessageId. +## Hide Thread Replies in Main Chat -Once you have the object of the `MessagesRequest` class, you need to call the `fetchPrevious()` method to get the latest messages in the thread. In one integration, a maximum of 100 messages can be fetched. If you wish to fetch the next set of messages, you need to call the `fetchPrevious()` method again on the same object. +By default, thread replies appear in the main message list. To show only parent messages: - + ```javascript -let limit = 30; -let parentMessageId = 1; -let messagesRequest = new CometChat.MessagesRequestBuilder() - .setLimit(limit) - .setParentMessageId(parentMessageId) - .build(); - +const GUID = "GUID"; +const limit = 30; + +const messagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(GUID) + .setLimit(limit) + .hideReplies(true) // Exclude thread replies + .build(); + messagesRequest.fetchPrevious().then( - messages => { - console.log("Messages for thread fetched successfully", messages); - }, error => { - console.log("Message fetching failed with error:", error); - } -); + (messages) => console.log("Messages (without thread replies):", messages), + (error) => console.log("Failed to fetch:", error) +); ``` - - ```typescript -let limit: number = 30, - parentMessageId: number = 1, - messagesRequest: CometChat.MessagesRequest = new CometChat.MessagesRequestBuilder() - .setLimit(limit) - .setParentMessageId(parentMessageId) - .build(); +const GUID: string = "GUID"; +const limit: number = 30; + +const messagesRequest: CometChat.MessagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(GUID) + .setLimit(limit) + .hideReplies(true) + .build(); messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Messages for thread fetched successfully", messages); - }, (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); - } + (messages: CometChat.BaseMessage[]) => console.log("Messages:", messages), + (error: CometChat.CometChatException) => console.log("Failed to fetch:", error) ); ``` - + +```javascript +const fetchMessagesWithoutReplies = async () => { + try { + const GUID = "GUID"; + const limit = 30; + + const messagesRequest = new CometChat.MessagesRequestBuilder() + .setGUID(GUID) + .setLimit(limit) + .hideReplies(true) // Exclude thread replies + .build(); + const messages = await messagesRequest.fetchPrevious(); + console.log("Messages (without thread replies):", messages); + } catch (error) { + console.log("Failed to fetch:", error); + } +}; +``` + -## Avoid Threaded Messages in User/Group Conversations +--- + +## Get Thread Reply Count -While fetching messages for normal user/group conversations using the `MessagesRequest`, the threaded messages by default will be a part of the list of messages received. In order to exclude the threaded messages from the list of user/group messages, you need to use the `hideReplies()` method of the `MessagesRequestBuilder` class. This method takes a boolean argument which when set to true excludes the messages belonging to threads from the list of messages. +Check how many replies a message has: - - ```javascript -let UID = "UID"; -let limit = 30; -let messagesRequest = new CometChat.MessagesRequestBuilder() - .setUID(UID) - .setLimit(limit) - .hideReplies(true) - .build(); - -messagesRequest.fetchPrevious().then( - messages => { - console.log("Messages fetched successfully", messages); - }, error => { - console.log("Message fetching failed with error:", error); - } -); +const replyCount = message.getReplyCount(); +console.log(`This message has ${replyCount} replies`); ``` - +--- + +## Complete Implementation - ```javascript -let GUID = "GUID"; -let limit = 30; -let messagesRequest = new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setLimit(limit) - .hideReplies(true) - .build(); - -messagesRequest.fetchPrevious().then( - messages => { - console.log("Messages fetched successfully", messages); - }, error => { - console.log("Message fetching failed with error:", error); +class ThreadManager { + constructor() { + this.activeThreadId = null; + this.threadMessages = []; + this.listenerID = "thread-manager"; } -); -``` - + async openThread(parentMessageId) { + this.activeThreadId = parentMessageId; + this.threadMessages = []; + + this.setupListener(); + await this.fetchThreadMessages(); + } - -```typescript -let UID: string = "UID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = new CometChat.MessagesRequestBuilder() - .setUID(UID) - .setLimit(limit) - .hideReplies(true) + setupListener() { + CometChat.addMessageListener( + this.listenerID, + new CometChat.MessageListener({ + onTextMessageReceived: (msg) => this.handleNewMessage(msg), + onMediaMessageReceived: (msg) => this.handleNewMessage(msg), + onCustomMessageReceived: (msg) => this.handleNewMessage(msg) + }) + ); + } + + handleNewMessage(message) { + if (message.getParentMessageId() === this.activeThreadId) { + this.threadMessages.push(message); + this.renderThread(); + } + } + + async fetchThreadMessages() { + const request = new CometChat.MessagesRequestBuilder() + .setParentMessageId(this.activeThreadId) + .setLimit(50) .build(); -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Messages fetched successfully", messages); - }, (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); + try { + this.threadMessages = await request.fetchPrevious(); + this.renderThread(); + } catch (error) { + console.log("Failed to fetch thread:", error); + } } -); -``` - + async sendReply(text, receiverID, receiverType) { + const message = new CometChat.TextMessage(receiverID, text, receiverType); + message.setParentMessageId(this.activeThreadId); - -```typescript -let GUID: string = "GUID", - limit: number = 30, - messagesRequest: CometChat.MessagesRequest = new CometChat.MessagesRequestBuilder() - .setGUID(GUID) - .setLimit(limit) - .hideReplies(true) - .build(); + try { + const sent = await CometChat.sendMessage(message); + console.log("Reply sent:", sent); + } catch (error) { + console.log("Failed to send reply:", error); + } + } -messagesRequest.fetchPrevious().then( - (messages: CometChat.BaseMessage[]) => { - console.log("Messages fetched successfully", messages); - }, (error: CometChat.CometChatException) => { - console.log("Message fetching failed with error:", error); + renderThread() { + console.log(`Thread has ${this.threadMessages.length} messages`); + // Update your UI here } -); + + closeThread() { + CometChat.removeMessageListener(this.listenerID); + this.activeThreadId = null; + this.threadMessages = []; + } +} + +// Usage +const threadManager = new ThreadManager(); +await threadManager.openThread(100); +await threadManager.sendReply("Great idea!", "group-123", CometChat.RECEIVER_TYPE.GROUP); +threadManager.closeThread(); ``` - +--- - +## Best Practices + + + + - Show reply count on parent messages to indicate threads exist + - Use a slide-out panel or modal for thread views + - Keep the parent message visible at the top of the thread + - Show "View in thread" link when displaying thread replies in main chat + + + - Use `hideReplies(true)` in main chat to reduce message count + - Paginate thread messages for long threads + - Cache thread messages when switching between threads + + + - Update reply count on parent message when new replies arrive + - Show typing indicators within thread context + - Handle message edits and deletes in threads + + + +--- + +## Next Steps -The above snippet will return messages between the logged in user and `cometchat-uid-1` excluding all the threaded messages belonging to the same conversation. + + + Add emoji reactions to messages + + + @mention users in messages + + diff --git a/sdk/javascript/transfer-group-ownership.mdx b/sdk/javascript/transfer-group-ownership.mdx index 1de52a89..e85d84cd 100644 --- a/sdk/javascript/transfer-group-ownership.mdx +++ b/sdk/javascript/transfer-group-ownership.mdx @@ -1,44 +1,127 @@ --- title: "Transfer Group Ownership" +sidebarTitle: "Transfer Ownership" +description: "Transfer ownership of a group to another member" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Transfer ownership (owner only) +await CometChat.transferGroupOwnership("group_guid", "new_owner_uid"); + +// Common pattern: Transfer then leave +await CometChat.transferGroupOwnership("group_guid", "new_owner_uid"); +await CometChat.leaveGroup("group_guid"); -*In other words, as a logged-in user, how do I transfer the ownership of any group if I am the owner of the group?* +// Note: Owner must transfer ownership before leaving the group +``` + -In order to transfer the ownership of any group, the first condition is that you must be the owner of the group. In case you are the owner of the group, you can use the `transferGroupOwnership()` method provided by the `CometChat` class. +Transfer group ownership to another member when you need to step down as owner. -This will be helpful as the owner is not allowed to leave the group. In case, you as the owner would like to leave the group, you will have to use this method and transfer your ownership first to any other member of the group and only then you will be allowed to leave the group. + +**Availability**: SDK, API, UI Kits + +Only the current owner can transfer ownership. The owner must transfer ownership before leaving the group. + + +--- + +## Transfer Ownership - + ```javascript -let GUID = "GUID"; -let UID = "UID"; +const GUID = "group-123"; +const UID = "new-owner-uid"; + CometChat.transferGroupOwnership(GUID, UID).then( - () => { - console.log("Successfully transferred ownership of the group."); - }, error => { - console.log("Could not transfer ownership of the group: ", error); - } -) + () => console.log("Ownership transferred successfully"), + (error) => console.log("Failed to transfer:", error) +); ``` - - ```typescript -let GUID: string = "GUID"; -let UID: string = "UID"; +const GUID: string = "group-123"; +const UID: string = "new-owner-uid"; + CometChat.transferGroupOwnership(GUID, UID).then( - (ownershipTransferred: string) => { - console.log("Successfully transferred ownership of the group."); - }, error => { - console.log("Could not transfer ownership of the group: ", error); - } + (response: string) => console.log("Ownership transferred successfully"), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - + +```javascript +const transferOwnership = async () => { + try { + const GUID = "group-123"; + const UID = "new-owner-uid"; + await CometChat.transferGroupOwnership(GUID, UID); + console.log("Ownership transferred successfully"); + } catch (error) { + console.log("Failed to transfer:", error); + } +}; +``` + + +| Parameter | Description | +|-----------|-------------| +| `GUID` | Group identifier | +| `UID` | UID of the new owner (must be a group member) | + +--- + +## When to Transfer Ownership + + + + The owner cannot leave a group without first transferring ownership. Transfer to another admin or trusted member before leaving. + + + When the current owner is no longer the appropriate person to manage the group (e.g., leaving the company, changing teams). + + + +--- + +## Implementation Example + +```javascript +async function transferAndLeave(groupId, newOwnerId) { + try { + // First transfer ownership + await CometChat.transferGroupOwnership(groupId, newOwnerId); + console.log("Ownership transferred"); + + // Now you can leave the group + await CometChat.leaveGroup(groupId); + console.log("Left group successfully"); + } catch (error) { + console.log("Failed:", error); + } +} + +// Usage +await transferAndLeave("group-123", "user456"); +``` + +--- + +## Next Steps + + + + Leave a group + + + Update member permissions + + diff --git a/sdk/javascript/transient-messages.mdx b/sdk/javascript/transient-messages.mdx index 9f44b226..12434bb3 100644 --- a/sdk/javascript/transient-messages.mdx +++ b/sdk/javascript/transient-messages.mdx @@ -1,112 +1,201 @@ --- title: "Transient Messages" +sidebarTitle: "Transient Messages" +description: "Send real-time messages that are not stored or persisted" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Send transient message (not persisted) +const transientMessage = new CometChat.TransientMessage( + "receiverId", + CometChat.RECEIVER_TYPE.USER, // or GROUP + { LIVE_REACTION: "❤️" } +); +CometChat.sendTransientMessage(transientMessage); -Transient messages are messages that are sent in real-time only and are not saved or tracked anywhere. The receiver of the message will only receive the message if he is online and these messages cannot be retrieved later. +// Receive transient messages +CometChat.addMessageListener("TRANSIENT_LISTENER", new CometChat.MessageListener({ + onTransientMessageReceived: (msg) => console.log(msg.getData()) +})); +``` + -## Send a Transient Message +Transient messages are ephemeral messages sent in real-time that are not saved anywhere. They're perfect for live reactions, typing indicators, or any temporary data that doesn't need to be stored. + + +**Availability**: SDK + +Transient messages are only received if the recipient is online. They cannot be retrieved later. + -You can use the `sendTransientMessage()` method to send a transient message to a user or in a group. The receiver will receive this information in the `onTransientMessageReceived()` method of the `MessageListener` class. In order to send the transient message, you need to use the `TransientMessage` class. +--- + +## Use Cases + +| Use Case | Description | +|----------|-------------| +| Live Reactions | Floating hearts, thumbs up during live streams | +| Custom Typing | Advanced typing indicators with custom data | +| Presence Updates | Custom presence states beyond online/offline | +| Ephemeral Data | Any data that shouldn't be stored | + +--- + +## Send a Transient Message ```javascript -let receiverId = "UID"; -let receiverType = CometChat.RECEIVER_TYPE.USER; -let data = { "LIVE_REACTION": "heart" }; +const receiverId = "user1"; +const receiverType = CometChat.RECEIVER_TYPE.USER; +const data = { LIVE_REACTION: "heart" }; + +const transientMessage = new CometChat.TransientMessage( + receiverId, + receiverType, + data +); -let transientMessage = new CometChat.TransientMessage(receiverId, receiverType, data); CometChat.sendTransientMessage(transientMessage); ``` - - ```javascript -let receiverId = "GUID"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; -let data = { "LIVE_REACTION": "heart" }; - -let transientMessage = new CometChat.TransientMessage(receiverId, receiverType, data); -CometChat.sendTransientMessage(transientMessage); -``` - - - - -```typescript -let receiverId: string = "UID"; -let receiverType: string = CometChat.RECEIVER_TYPE.USER; -let data: Object = { "LIVE_REACTION": "heart" }; +const receiverId = "group-123"; +const receiverType = CometChat.RECEIVER_TYPE.GROUP; +const data = { LIVE_REACTION: "heart" }; + +const transientMessage = new CometChat.TransientMessage( + receiverId, + receiverType, + data +); -let transientMessage: CometChat.TransientMessage = new CometChat.TransientMessage(receiverId, receiverType, data); CometChat.sendTransientMessage(transientMessage); ``` - - - + ```typescript -let receiverId: string = "GUID"; -let receiverType: string = CometChat.RECEIVER_TYPE.GROUP; -let data: Object = { "LIVE_REACTION": "heart" }; +const receiverId: string = "user1"; +const receiverType: string = CometChat.RECEIVER_TYPE.USER; +const data: Object = { LIVE_REACTION: "heart" }; + +const transientMessage: CometChat.TransientMessage = new CometChat.TransientMessage( + receiverId, + receiverType, + data +); -let transientMessage: CometChat.TransientMessage = new CometChat.TransientMessage(receiverId, receiverType, data); CometChat.sendTransientMessage(transientMessage); ``` - - -## Real-time Transient Messages +--- -*In other words, as a recipient, how do I know when someone sends a transient message?* +## Receive Transient Messages -You will receive the transient message in the `onTransientMessageReceived()` method of the registered `MessageListener` class. +Listen for transient messages in real-time: - - ```javascript -let listenerId = "UNIQUE_LITENER_ID"; - -CometChat.addMessageListener( -listenerId, -new CometChat.MessageListener({ - onTransientMessageReceived: transientMessage => { - console.log('transient message received', transientMessage); - }, -}) -); -``` - - - - -```typescript -let listenerId: string = "UNIQUE_LITENER_ID"; +const listenerID = "TRANSIENT_LISTENER"; CometChat.addMessageListener( - listenerId, + listenerID, new CometChat.MessageListener({ - onTransientMessageReceived: (transientMessage: CometChat.TransientMessage) => { - console.log('transient message received', transientMessage); - }, + onTransientMessageReceived: (transientMessage) => { + const data = transientMessage.getData(); + const sender = transientMessage.getSender(); + + console.log(`${sender.getName()} sent:`, data); + + // Handle based on data type + if (data.LIVE_REACTION) { + showFloatingReaction(data.LIVE_REACTION); + } + } }) ); + +// Remove listener when done +CometChat.removeMessageListener(listenerID); ``` - +--- - +## TransientMessage Properties + +| Property | Description | +|----------|-------------| +| `sender` | User object of the sender | +| `receiverId` | UID or GUID of the recipient | +| `receiverType` | USER or GROUP | +| `data` | Custom JSON data | + +--- + +## Implementation Example + +```javascript +class LiveReactionManager { + constructor() { + this.listenerID = "live-reactions"; + } + + initialize() { + CometChat.addMessageListener( + this.listenerID, + new CometChat.MessageListener({ + onTransientMessageReceived: (msg) => this.handleTransient(msg) + }) + ); + } + + handleTransient(transientMessage) { + const data = transientMessage.getData(); + + if (data.LIVE_REACTION) { + this.showReaction(data.LIVE_REACTION, transientMessage.getSender()); + } + } + + sendReaction(receiverId, receiverType, reaction) { + const data = { LIVE_REACTION: reaction }; + const message = new CometChat.TransientMessage(receiverId, receiverType, data); + CometChat.sendTransientMessage(message); + } + + showReaction(reaction, sender) { + // Display floating reaction animation + console.log(`${sender.getName()} sent ${reaction}`); + } + + cleanup() { + CometChat.removeMessageListener(this.listenerID); + } +} + +// Usage +const reactionManager = new LiveReactionManager(); +reactionManager.initialize(); + +// Send a live reaction +reactionManager.sendReaction("group-123", CometChat.RECEIVER_TYPE.GROUP, "❤️"); +``` + +--- -The `TransientMessage` class consists of the below parameters: +## Next Steps -| Parameter | Information | -| ---------------- | -------------------------------------------------------------------------------------------------------- | -| **sender** | An object of the User class holding all the information. related to the sender of the transient message. | -| **receiverId** | Unique Id of the receiver. This can be the Id of the group or the user the transient message is sent to. | -| **receiverType** | The type of the receiver - `CometChat.RECEIVER_TYPE.USER` or `CometChat.RECEIVER_TYPE.GROUP` | -| **data** | A JSONObject to provide data. | + + + Send interactive forms and buttons + + + Send custom message types + + diff --git a/sdk/javascript/typing-indicators.mdx b/sdk/javascript/typing-indicators.mdx index 0174f572..0629b6cc 100644 --- a/sdk/javascript/typing-indicators.mdx +++ b/sdk/javascript/typing-indicators.mdx @@ -1,174 +1,453 @@ --- title: "Typing Indicators" +description: "Show when users are typing in real-time" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Start typing +const typingIndicator = new CometChat.TypingIndicator( + "receiver_uid", // or group_guid + CometChat.RECEIVER_TYPE.USER // or GROUP +); +CometChat.startTyping(typingIndicator); + +// Stop typing +CometChat.endTyping(typingIndicator); + +// Listen for typing events +CometChat.addMessageListener("TYPING_LISTENER", new CometChat.MessageListener({ + onTypingStarted: (indicator) => { + console.log(indicator.getSender().getName(), "is typing..."); + }, + onTypingEnded: (indicator) => { + console.log(indicator.getSender().getName(), "stopped typing"); + } +})); + +// Best practice: Debounce and auto-stop after 2s of inactivity +``` + -## Send a Typing Indicator +Typing indicators let users know when someone is composing a message, creating a more engaging chat experience. -*In other words, as a sender, how do I let the recipient(s) know that I'm typing?* + +**Available via:** SDK | [UI Kits](/ui-kit/react/overview) + + +--- + +## Send Typing Indicator ### Start Typing -You can use the `startTyping()` method to inform the receiver that the logged in user has started typing. The receiver will receive this information in the `onTypingStarted()` method of the `MessageListener` class. In order to send the typing indicator, you need to use the `TypingIndicator` class. +Notify the recipient that you've started typing: - -```javascript -let receiverId = "UID"; -let receiverType = CometChat.RECEIVER_TYPE.USER; + + ```javascript + const receiverID = "user_uid"; + const receiverType = CometChat.RECEIVER_TYPE.USER; + + const typingNotification = new CometChat.TypingIndicator( + receiverID, + receiverType + ); + + CometChat.startTyping(typingNotification); + ``` + + + ```javascript + const receiverID = "group_guid"; + const receiverType = CometChat.RECEIVER_TYPE.GROUP; + + const typingNotification = new CometChat.TypingIndicator( + receiverID, + receiverType + ); + + CometChat.startTyping(typingNotification); + ``` + + -let typingNotification = new CometChat.TypingIndicator(receiverId, receiverType); -CometChat.startTyping(typingNotification); -``` +### Stop Typing - +Notify when you've stopped typing: - -```javascript -let receiverId = "GUID"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; + + + ```javascript + const receiverID = "user_uid"; + const receiverType = CometChat.RECEIVER_TYPE.USER; + + const typingNotification = new CometChat.TypingIndicator( + receiverID, + receiverType + ); + + CometChat.endTyping(typingNotification); + ``` + + + ```javascript + const receiverID = "group_guid"; + const receiverType = CometChat.RECEIVER_TYPE.GROUP; + + const typingNotification = new CometChat.TypingIndicator( + receiverID, + receiverType + ); + + CometChat.endTyping(typingNotification); + ``` + + -let typingNotification = new CometChat.TypingIndicator(receiverId,receiverType); -CometChat.startTyping(typingNotification); -``` +--- - +## Receive Typing Indicators - -```typescript -let receiverId: string = "UID"; -let receiverType: string = CometChat.RECEIVER_TYPE.USER; +Listen for typing events from other users: -let typingNotification: CometChat.TypingIndicator = new CometChat.TypingIndicator(receiverId, receiverType); -CometChat.startTyping(typingNotification); -``` +```javascript +const listenerID = "TYPING_LISTENER"; - +CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onTypingStarted: (typingIndicator) => { + console.log("Typing started:", typingIndicator); + + const sender = typingIndicator.getSender(); + console.log(sender.getName(), "is typing..."); + }, + onTypingEnded: (typingIndicator) => { + console.log("Typing ended:", typingIndicator); + + const sender = typingIndicator.getSender(); + console.log(sender.getName(), "stopped typing"); + } + }) +); +``` - -```typescript -let receiverId: string = "GUID"; -let receiverType: string = CometChat.RECEIVER_TYPE.GROUP; +--- -let typingNotification: CometChat.TypingIndicator = new CometChat.TypingIndicator(receiverId, receiverType); -CometChat.startTyping(typingNotification); -``` +## TypingIndicator Properties - +| Property | Method | Description | +|----------|--------|-------------| +| Sender | `getSender()` | User object of who is typing | +| Receiver ID | `getReceiverId()` | UID or GUID of recipient | +| Receiver Type | `getReceiverType()` | `user` or `group` | +| Metadata | `getMetadata()` | Custom data (optional) | -
+--- -### Stop Typing +## Add Custom Metadata -You can use the `endTyping()` method to inform the receiver that the logged in user has stopped typing. The receiver will receive this information in the `onTypingEnded()` method of the `MessageListener` class. In order to send the typing indicator, you need to use the `TypingIndicator` class. +Send additional data with typing indicators: - - ```javascript -let receiverId = "UID"; -let receiverType = CometChat.RECEIVER_TYPE.USER; +const typingNotification = new CometChat.TypingIndicator( + receiverID, + receiverType +); + +typingNotification.setMetadata({ + isVoiceMessage: true, + customField: "value" +}); -let typingNotification = new CometChat.TypingIndicator(receiverId, receiverType); -CometChat.endTyping(typingNotification); +CometChat.startTyping(typingNotification); ``` - +Access metadata when receiving: - ```javascript -let receiverId = "GUID"; -let receiverType = CometChat.RECEIVER_TYPE.GROUP; - -let typingNotification = new CometChat.TypingIndicator(receiverId, receiverType); -CometChat.endTyping(typingNotification); +onTypingStarted: (typingIndicator) => { + const metadata = typingIndicator.getMetadata(); + if (metadata?.isVoiceMessage) { + console.log("Recording voice message..."); + } +} ``` - - - -```typescript -let receiverId: string = "UID"; -let receiverType: string = CometChat.RECEIVER_TYPE.USER; +--- -let typingNotification: CometChat.TypingIndicator = new CometChat.TypingIndicator(receiverId, receiverType); -CometChat.endTyping(typingNotification); -``` +## Implementation Example - +Here's a complete implementation with debouncing: - -```typescript -let receiverId: string = "GUID"; -let receiverType: string = CometChat.RECEIVER_TYPE.GROUP; +```javascript +class TypingHandler { + constructor(receiverID, receiverType) { + this.receiverID = receiverID; + this.receiverType = receiverType; + this.typingTimeout = null; + this.isTyping = false; + } -let typingNotification: CometChat.TypingIndicator = new CometChat.TypingIndicator(receiverId, receiverType); -CometChat.endTyping(typingNotification); -``` + // Call this on every keystroke in the input field + onInputChange() { + // Start typing if not already + if (!this.isTyping) { + this.startTyping(); + } + + // Reset the timeout + clearTimeout(this.typingTimeout); + + // Stop typing after 2 seconds of inactivity + this.typingTimeout = setTimeout(() => { + this.stopTyping(); + }, 2000); + } - + startTyping() { + this.isTyping = true; + const typingNotification = new CometChat.TypingIndicator( + this.receiverID, + this.receiverType + ); + CometChat.startTyping(typingNotification); + } - + stopTyping() { + this.isTyping = false; + const typingNotification = new CometChat.TypingIndicator( + this.receiverID, + this.receiverType + ); + CometChat.endTyping(typingNotification); + } - -Custom Data + // Call this when message is sent + onMessageSent() { + clearTimeout(this.typingTimeout); + if (this.isTyping) { + this.stopTyping(); + } + } +} -You can use the `metadata` field of the `TypingIndicator` class to pass additional data along with the typing indicators. The metadata field is a JSONObject and can be set using the `setMetadata()` method of the `TypingIndicator` class. This data will be received at the receiver end and can be obtained using the `getMetadata()` method. +// Usage +const typingHandler = new TypingHandler("user_uid", CometChat.RECEIVER_TYPE.USER); - +// In your input field +inputField.addEventListener("input", () => { + typingHandler.onInputChange(); +}); -## Real-time Typing Indicators +// When sending message +sendButton.addEventListener("click", () => { + sendMessage(); + typingHandler.onMessageSent(); +}); +``` -*In other words, as a recipient, how do I know when someone is typing?* +--- -You will receive the typing indicators in the `onTypingStarted()` and the `onTypingEnded()` method of the registered `MessageListener` class. +## UI Display Example - - ```javascript -let listenerId = "UNIQUE_LITENER_ID"; +// Track who is typing +const typingUsers = new Map(); CometChat.addMessageListener( -listenerId, -new CometChat.MessageListener({ - onTypingStarted: typingIndicator => { - console.log("Typing started :", typingIndicator); - }, - onTypingEnded: typingIndicator => { - console.log("Typing ended :", typingIndicator); - } -}) + "TYPING_LISTENER", + new CometChat.MessageListener({ + onTypingStarted: (typingIndicator) => { + const sender = typingIndicator.getSender(); + typingUsers.set(sender.getUid(), sender.getName()); + updateTypingUI(); + }, + onTypingEnded: (typingIndicator) => { + const sender = typingIndicator.getSender(); + typingUsers.delete(sender.getUid()); + updateTypingUI(); + } + }) ); -``` - +function updateTypingUI() { + const names = Array.from(typingUsers.values()); + + if (names.length === 0) { + typingLabel.textContent = ""; + } else if (names.length === 1) { + typingLabel.textContent = `${names[0]} is typing...`; + } else if (names.length === 2) { + typingLabel.textContent = `${names[0]} and ${names[1]} are typing...`; + } else { + typingLabel.textContent = "Several people are typing..."; + } +} +``` - -```typescript -let listenerId: string = "UNIQUE_LITENER_ID"; +--- -CometChat.addMessageListener( - listenerId, - new CometChat.MessageListener({ - onTypingStarted: (typingIndicator: CometChat.TypingIndicator) => { - console.log("Typing started :", typingIndicator); - }, - onTypingEnded: (typingIndicator: CometChat.TypingIndicator) => { - console.log("Typing ended :", typingIndicator); +## React Hook Example + +```jsx +import { useEffect, useState, useCallback, useRef } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; + +export function useTypingIndicator(receiverID, receiverType) { + const [typingUsers, setTypingUsers] = useState(new Map()); + const isTypingRef = useRef(false); + const timeoutRef = useRef(null); + + // Listen for typing events + useEffect(() => { + const listenerID = `typing_${receiverID}`; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onTypingStarted: (indicator) => { + const sender = indicator.getSender(); + setTypingUsers((prev) => { + const next = new Map(prev); + next.set(sender.getUid(), sender.getName()); + return next; + }); + }, + onTypingEnded: (indicator) => { + const sender = indicator.getSender(); + setTypingUsers((prev) => { + const next = new Map(prev); + next.delete(sender.getUid()); + return next; + }); + } + }) + ); + + return () => { + CometChat.removeMessageListener(listenerID); + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); } - }) -); + // Stop typing on unmount + if (isTypingRef.current) { + stopTyping(); + } + }; + }, [receiverID]); + + const startTyping = useCallback(() => { + if (!isTypingRef.current) { + isTypingRef.current = true; + const indicator = new CometChat.TypingIndicator(receiverID, receiverType); + CometChat.startTyping(indicator); + } + + // Reset timeout + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + // Auto-stop after 2 seconds of inactivity + timeoutRef.current = setTimeout(() => { + stopTyping(); + }, 2000); + }, [receiverID, receiverType]); + + const stopTyping = useCallback(() => { + if (isTypingRef.current) { + isTypingRef.current = false; + const indicator = new CometChat.TypingIndicator(receiverID, receiverType); + CometChat.endTyping(indicator); + } + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + }, [receiverID, receiverType]); + + // Format typing text + const typingText = useCallback(() => { + const names = Array.from(typingUsers.values()); + if (names.length === 0) return ""; + if (names.length === 1) return `${names[0]} is typing...`; + if (names.length === 2) return `${names[0]} and ${names[1]} are typing...`; + return "Several people are typing..."; + }, [typingUsers]); + + return { + typingUsers, + typingText: typingText(), + isAnyoneTyping: typingUsers.size > 0, + onInputChange: startTyping, + onMessageSent: stopTyping + }; +} + +// Usage in component +function ChatInput({ receiverID }) { + const [message, setMessage] = useState(""); + const { typingText, isAnyoneTyping, onInputChange, onMessageSent } = + useTypingIndicator(receiverID, CometChat.RECEIVER_TYPE.USER); + + const handleChange = (e) => { + setMessage(e.target.value); + onInputChange(); + }; + + const handleSend = async () => { + if (!message.trim()) return; + // Send message... + onMessageSent(); + setMessage(""); + }; + + return ( +
+ {isAnyoneTyping &&
{typingText}
} + + +
+ ); +} ``` -
+--- -
+## Best Practices + + + + Don't send `startTyping` on every keystroke. Use a debounce to avoid flooding the server. + + + Automatically call `endTyping` after 2-3 seconds of no input to handle cases where users abandon typing. + + + Always call `endTyping` when a message is sent to immediately clear the typing indicator. + + + Call `endTyping` when the chat component unmounts to clean up any active typing state. + + + +--- -The `TypingIndicator` class consists of the below parameters: +## Next Steps -| Parameter | Information | -| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **sender** | An object of the `User` class holding all the information. related to the sender of the typing indicator. | -| **receiverId** | Unique Id of the receiver. This can be the Id of the group or the user the typing indicator is sent to. | -| **receiverType** | This parameter indicates if the typing indicator is to be sent to a user or a group. The possible values are: 1. `CometChat.RECEIVER_TYPE.USER` 2. `CometChat.RECEIVER_TYPE.GROUP` | -| **metadata** | A JSONObject to provider additional data. | + + + Track message delivery and read status + + + Send text, media, and custom messages + + diff --git a/sdk/javascript/update-group.mdx b/sdk/javascript/update-group.mdx index c8717d61..e5333fe7 100644 --- a/sdk/javascript/update-group.mdx +++ b/sdk/javascript/update-group.mdx @@ -1,61 +1,252 @@ --- -title: "Update A Group" +title: "Update a Group" +sidebarTitle: "Update Group" +description: "Modify group name, icon, description, and other settings" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Update group details +const group = new CometChat.Group("group_guid", "New Name", CometChat.GROUP_TYPE.PUBLIC); +group.setDescription("New description"); +group.setIcon("https://example.com/icon.png"); +group.setMetadata({ department: "Engineering" }); +group.setTags(["active", "priority"]); +const updated = await CometChat.updateGroup(group); + +// Editable: name, icon, description, metadata, tags, owner +// Not editable: guid, type +``` + + +Update group details like name, icon, description, and metadata. -## Update Group + +**Availability**: SDK, API, UI Kits -*In other words, as a group owner, how can I update the group details?* +Only admins and moderators can update group settings (depending on your configuration). + + +--- -You can update the existing details of the group using the `updateGroup()` method. +## Update Group Details - + ```javascript -var GUID = "GUID"; -var groupName = "Hello Group"; -var groupType = CometChat.GROUP_TYPE.PUBLIC; -var group = new CometChat.Group(GUID, groupName, groupType); +const GUID = "group-123"; +const groupName = "Updated Team Name"; +const groupType = CometChat.GROUP_TYPE.PUBLIC; + +const group = new CometChat.Group(GUID, groupName, groupType); +group.setDescription("New description for the team"); +group.setIcon("https://example.com/new-icon.png"); CometChat.updateGroup(group).then( -group => { - console.log("Groups details updated successfully:", group); -}, error => { - console.log("Group details update failed with exception:", error); -} + (updatedGroup) => console.log("Group updated:", updatedGroup), + (error) => console.log("Failed to update:", error) ); ``` - - ```typescript -var GUID: string = "GUID"; -var groupName: string = "Hello Group!"; -var groupType: string = CometChat.GROUP_TYPE.PUBLIC; +const GUID: string = "group-123"; +const groupName: string = "Updated Team Name"; +const groupType: string = CometChat.GROUP_TYPE.PUBLIC; -var group: CometChat.Group = new CometChat.Group(GUID, groupName, groupType); +const group: CometChat.Group = new CometChat.Group(GUID, groupName, groupType); +group.setDescription("New description for the team"); +group.setIcon("https://example.com/new-icon.png"); CometChat.updateGroup(group).then( - (group: CometChat.Group) => { - console.log("Group details updated successfully:", group); - }, (error: CometChat.CometChatException) => { - console.log("Group details update failed with exception:", error); + (updatedGroup: CometChat.Group) => console.log("Group updated:", updatedGroup), + (error: CometChat.CometChatException) => console.log("Failed:", error) +); +``` + + +```javascript +const updateGroup = async () => { + try { + const GUID = "group-123"; + const groupName = "Updated Team Name"; + const groupType = CometChat.GROUP_TYPE.PUBLIC; + + const group = new CometChat.Group(GUID, groupName, groupType); + group.setDescription("New description for the team"); + group.setIcon("https://example.com/new-icon.png"); + + const updatedGroup = await CometChat.updateGroup(group); + console.log("Group updated:", updatedGroup); + } catch (error) { + console.log("Failed to update:", error); } +}; +``` + + + +--- + +## Update Specific Properties + +### Update Name Only + + + +```javascript +const group = new CometChat.Group("group-123", "New Name", CometChat.GROUP_TYPE.PUBLIC); + +CometChat.updateGroup(group).then( + (updated) => console.log("Name updated:", updated.getName()), + (error) => console.log("Failed:", error) ); ``` + + +```javascript +async function updateGroupName(guid, newName) { + try { + const group = new CometChat.Group(guid, newName, CometChat.GROUP_TYPE.PUBLIC); + const updated = await CometChat.updateGroup(group); + console.log("Name updated:", updated.getName()); + return updated; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} +``` + + + +### Update Icon + + +```javascript +const group = new CometChat.Group("group-123", "Team", CometChat.GROUP_TYPE.PUBLIC); +group.setIcon("https://example.com/new-icon.png"); + +CometChat.updateGroup(group).then( + (updated) => console.log("Icon updated:", updated.getIcon()), + (error) => console.log("Failed:", error) +); +``` + +```javascript +async function updateGroupIcon(guid, iconUrl) { + try { + const group = new CometChat.Group(guid, "Team", CometChat.GROUP_TYPE.PUBLIC); + group.setIcon(iconUrl); + const updated = await CometChat.updateGroup(group); + console.log("Icon updated:", updated.getIcon()); + return updated; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} +``` + + + +### Update Metadata + + + +```javascript +const group = new CometChat.Group("group-123", "Team", CometChat.GROUP_TYPE.PUBLIC); +group.setMetadata({ + department: "Engineering", + project: "Alpha", + priority: "high" +}); + +CometChat.updateGroup(group).then( + (updated) => console.log("Metadata updated:", updated.getMetadata()), + (error) => console.log("Failed:", error) +); +``` + + +```javascript +async function updateGroupMetadata(guid, metadata) { + try { + const group = new CometChat.Group(guid, "Team", CometChat.GROUP_TYPE.PUBLIC); + group.setMetadata(metadata); + const updated = await CometChat.updateGroup(group); + console.log("Metadata updated:", updated.getMetadata()); + return updated; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} +``` + + + +### Update Tags + + + +```javascript +const group = new CometChat.Group("group-123", "Team", CometChat.GROUP_TYPE.PUBLIC); +group.setTags(["engineering", "priority", "active"]); +CometChat.updateGroup(group).then( + (updated) => console.log("Tags updated:", updated.getTags()), + (error) => console.log("Failed:", error) +); +``` + + +```javascript +async function updateGroupTags(guid, tags) { + try { + const group = new CometChat.Group(guid, "Team", CometChat.GROUP_TYPE.PUBLIC); + group.setTags(tags); + const updated = await CometChat.updateGroup(group); + console.log("Tags updated:", updated.getTags()); + return updated; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} +``` + -This method takes an instance of the `Group` class as a parameter which should contain the data that you wish to update. +--- + +## Editable Properties -| Parameter | Description | -| --------- | ---------------------------- | -| `group` | an instance of class `Group` | +| Property | Editable | Notes | +|----------|----------|-------| +| `name` | Yes | Display name | +| `icon` | Yes | URL to group icon | +| `description` | Yes | Group description | +| `metadata` | Yes | Custom JSON data | +| `tags` | Yes | Array of tags | +| `owner` | Yes | Transfer ownership | +| `type` | No | Cannot change after creation | +| `guid` | No | Cannot change after creation | + +--- -After a successful update of the group, you will receive an instance of `Group` class containing update information of the group. +## Next Steps -For more information on the `Group` class, please check [here](/sdk/javascript/create-group#create-a-group). + + + Transfer group ownership + + + Manage group members + + diff --git a/sdk/javascript/upgrading-from-v3.mdx b/sdk/javascript/upgrading-from-v3.mdx index 00cf6868..cd12c97e 100644 --- a/sdk/javascript/upgrading-from-v3.mdx +++ b/sdk/javascript/upgrading-from-v3.mdx @@ -1,65 +1,193 @@ --- title: "Upgrading From V3" +description: "Step-by-step guide to migrate from CometChat SDK v3 to v4" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** - -## Upgrading From v3 - -Upgrading from v3.x to v4 is fairly simple. Below are the major changes that are released as a part of CometChat v4: - -Please follow the [setup](/sdk/javascript/setup-sdk) instructions to upgrade to latest version of V4 before proceeding further - -## Dependency Change - -## Chat SDK - - - ```bash -npm i @cometchat/chat-sdk-javascript -``` - - - - - -## Calls SDK +# 1. Remove old packages +npm uninstall @cometchat-pro/chat @cometchat-pro/calls - - -```bash -npm i @cometchat/calls-sdk-javascript +# 2. Install new packages +npm install @cometchat/chat-sdk-javascript +npm install @cometchat/calls-sdk-javascript # if using calls ``` - - - - -## Change The Import Statements - -Change the import statements all around the project. - -## Chat SDK +```javascript +// 3. Update imports +// Before: import { CometChat } from "@cometchat-pro/chat"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; - - -```js -import {CometChat} from '@cometchat/chat-sdk-javascript'; +// Before: import { CometChatCalls } from "@cometchat-pro/calls"; +import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; ``` - - - - - -## Calls SDK - - - -```js -import {CometChatCalls} from '@cometchat/calls-sdk-javascript'; + + +Upgrading from v3.x to v4 is straightforward. This guide covers all breaking changes and migration steps. + + +Complete the [SDK Setup](/sdk/javascript/setup-sdk) for v4 before proceeding with the migration steps below. + + +## What's New in V4 + +| Feature | V3 | V4 | +|---------|----|----| +| Package Name | `@cometchat-pro/chat` | `@cometchat/chat-sdk-javascript` | +| Calls SDK | `@cometchat-pro/calls` | `@cometchat/calls-sdk-javascript` | +| TypeScript Support | Partial | Full | +| Bundle Size | Larger | Optimized | +| Tree Shaking | Limited | Full support | + +## Migration Steps + + + + Remove the old packages and install the new ones: + + ```bash + # Remove old packages + npm uninstall @cometchat-pro/chat @cometchat-pro/calls + + # Install new packages + npm install @cometchat/chat-sdk-javascript + npm install @cometchat/calls-sdk-javascript # If using calls + ``` + + + + Update all import statements throughout your project: + + + + ```javascript + // Before (v3) + import { CometChat } from "@cometchat-pro/chat"; + + // After (v4) + import { CometChat } from "@cometchat/chat-sdk-javascript"; + ``` + + + ```javascript + // Before (v3) + import { CometChatCalls } from "@cometchat-pro/calls"; + + // After (v4) + import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; + ``` + + + + + + The initialization API remains the same: + + ```javascript + const appSetting = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + + await CometChat.init(appId, appSetting); + ``` + + + + Run your application and verify: + - User authentication works + - Messages send and receive correctly + - Real-time listeners fire as expected + - Calls connect properly (if using Calls SDK) + + + +## Find and Replace Guide + +Use your IDE's find and replace to quickly update imports: + +| Find | Replace With | +|------|--------------| +| `@cometchat-pro/chat` | `@cometchat/chat-sdk-javascript` | +| `@cometchat-pro/calls` | `@cometchat/calls-sdk-javascript` | + +## Breaking Changes + + +The following changes may require code updates beyond simple find-and-replace. + + +### Package Scope Change + +The package scope changed from `@cometchat-pro` to `@cometchat`: + +```javascript +// v3 +import { CometChat } from "@cometchat-pro/chat"; + +// v4 +import { CometChat } from "@cometchat/chat-sdk-javascript"; ``` - - - +### TypeScript Improvements + +V4 includes improved TypeScript definitions. If you're using TypeScript, you may see new type errors that were previously undetected. These are typically beneficial as they catch potential bugs. + +## Troubleshooting + + + + Ensure you've completely removed the old packages: + + ```bash + rm -rf node_modules + rm package-lock.json # or yarn.lock + npm install + ``` + + + + Clear your TypeScript cache and rebuild: + + ```bash + rm -rf dist .tsbuildinfo + npm run build + ``` + + + + Ensure both SDKs are updated to v4: + + ```bash + npm list @cometchat/chat-sdk-javascript @cometchat/calls-sdk-javascript + ``` + + + +## Verification Checklist + +After migration, verify these features work correctly: + +- [ ] SDK initialization succeeds +- [ ] User login/logout works +- [ ] Send and receive text messages +- [ ] Send and receive media messages +- [ ] Real-time message listeners fire +- [ ] User presence updates work +- [ ] Group operations function correctly +- [ ] Calls connect and disconnect properly (if applicable) + +## Next Steps + + + + Review the complete setup guide + + + See all v4 features and improvements + + diff --git a/sdk/javascript/user-management.mdx b/sdk/javascript/user-management.mdx index 76ac2b58..ecd1d726 100644 --- a/sdk/javascript/user-management.mdx +++ b/sdk/javascript/user-management.mdx @@ -1,197 +1,401 @@ --- title: "User Management" +sidebarTitle: "User Management" +description: "Create, update, and manage users in your CometChat application" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Create user (requires Auth Key - use on backend only) +const user = new CometChat.User("user_uid"); +user.setName("John Doe"); +user.setAvatar("https://example.com/avatar.png"); +user.setRole("premium"); +user.setMetadata({ department: "Engineering" }); +await CometChat.createUser(user, authKey); -When a user logs into your app, you need to programmatically login the user into CometChat. But before you log in the user to CometChat, you need to create the user. +// Update any user (requires Auth Key) +await CometChat.updateUser(user, authKey); -Summing up- +// Update current logged-in user (no Auth Key needed) +await CometChat.updateCurrentUserDetails(user); -**When a user registers in your app** +// Get user properties +const user = await CometChat.getUser("user_uid"); +user.getUid(), user.getName(), user.getAvatar(), user.getStatus() -1. You add the user details in your database -2. You create a user in CometChat +// Delete user: REST API only (security) +``` + + +User management is the foundation of your chat application. Before users can send messages, they need to exist in CometChat. + + +**Availability**: SDK (with Auth Key), REST API -**When a user logs into your app** +For production apps, user creation should happen on your backend using the REST API. SDK methods are useful for development and prototyping. + -1. You log in the user to your app -2. You [log in the user in CometChat](/sdk/javascript/authentication-overview) (programmatically) +--- + +## User Lifecycle + + + + Save user details to your database + + + Create a corresponding CometChat user (via API or SDK) + + + Authenticate with CometChat using [login](/sdk/javascript/authentication-overview) + + + User can now send and receive messages + + -## Creating a user +--- -Ideally, user creation should take place at your backend. You can refer our Rest API to learn more about [creating a user](https://api-explorer.cometchat.com/reference/creates-user) and use the appropriate code sample based on your backend language. +## Create a User -However, if you wish to create users on the fly, you can use the `createUser()` method. This method takes a `User` object and the `Auth Key` as input parameters and returns the created `User` object if the request is successful. + +Creating users requires the Auth Key. In production, this should only be done from your backend server. Never expose your Auth Key in client-side code. + -```js -let authKey = "AUTH_KEY"; -var uid = "user1"; -var name = "Kevin"; - -var user = new CometChat.User(uid); +```javascript +const authKey = "YOUR_AUTH_KEY"; +const uid = "user1"; +const name = "Kevin"; +const user = new CometChat.User(uid); user.setName(name); CometChat.createUser(user, authKey).then( - user => { - console.log("user created", user); - }, error => { - console.log("error", error); - } -) + (user) => console.log("User created:", user), + (error) => console.log("Failed to create user:", error) +); ``` - - ```typescript -let authKey: string = "AUTH_KEY"; -var uid: string = "user1"; -var name: string = "Kevin"; - -var user: CometChat.User = new CometChat.User(uid); +const authKey: string = "YOUR_AUTH_KEY"; +const uid: string = "user1"; +const name: string = "Kevin"; +const user: CometChat.User = new CometChat.User(uid); user.setName(name); CometChat.createUser(user, authKey).then( - (user: CometChat.User) => { - console.log("user created", user); - }, (error: CometChat.CometChatException) => { - console.log("error", error); - } + (user: CometChat.User) => console.log("User created:", user), + (error: CometChat.CometChatException) => console.log("Failed:", error) ); ``` - - + +```javascript +const createUser = async () => { + try { + const authKey = "YOUR_AUTH_KEY"; + const uid = "user1"; + const name = "Kevin"; + + const user = new CometChat.User(uid); + user.setName(name); + + const createdUser = await CometChat.createUser(user, authKey); + console.log("User created:", createdUser); + } catch (error) { + console.log("Failed to create user:", error); + } +}; +``` + - -UID can be alphanumeric with underscore and hyphen. Spaces, punctuation and other special characters are not allowed. +### With All Properties - + + +```javascript +const authKey = "YOUR_AUTH_KEY"; + +const user = new CometChat.User("user1"); +user.setName("Kevin Smith"); +user.setAvatar("https://example.com/avatar.png"); +user.setLink("https://example.com/profile/kevin"); +user.setRole("premium"); +user.setMetadata({ department: "Engineering", level: 5 }); +user.setStatusMessage("Available for chat"); +user.setTags(["developer", "team-alpha"]); + +CometChat.createUser(user, authKey).then( + (user) => console.log("User created:", user), + (error) => console.log("Failed:", error) +); +``` + + +```javascript +async function createUserWithAllProperties() { + try { + const authKey = "YOUR_AUTH_KEY"; + + const user = new CometChat.User("user1"); + user.setName("Kevin Smith"); + user.setAvatar("https://example.com/avatar.png"); + user.setLink("https://example.com/profile/kevin"); + user.setRole("premium"); + user.setMetadata({ department: "Engineering", level: 5 }); + user.setStatusMessage("Available for chat"); + user.setTags(["developer", "team-alpha"]); + + const createdUser = await CometChat.createUser(user, authKey); + console.log("User created:", createdUser); + return createdUser; + } catch (error) { + console.log("Failed:", error); + throw error; + } +} +``` + + + + +**UID Requirements**: Alphanumeric characters, underscores, and hyphens only. No spaces, punctuation, or special characters. + -## Updating a user +--- -Updating a user similar to creating a user should ideally be achieved at your backend using the Restful APIs. For more information, you can check the [update a user](https://api-explorer.cometchat.com/reference/update-user) section. However, this can be achieved on the fly as well as using the `updateUser()` method. This method takes a `User` object and the `Auth Key` as inputs and returns the updated `User` object on the successful execution of the request. +## Update a User + +Update any user's profile using the Auth Key: -```js -let authKey = "AUTH_KEY"; -let uid = "user1"; -let name = "Kevin Fernandez"; - -var user = new CometChat.User(uid); +```javascript +const authKey = "YOUR_AUTH_KEY"; +const uid = "user1"; -user.setName(name); +const user = new CometChat.User(uid); +user.setName("Kevin Fernandez"); +user.setAvatar("https://example.com/new-avatar.png"); CometChat.updateUser(user, authKey).then( - user => { - console.log("user updated", user); - }, error => { - console.log("error", error); - } -) + (user) => console.log("User updated:", user), + (error) => console.log("Failed to update:", error) +); ``` - - ```typescript -let authKey: string = "AUTH_KEY"; -var uid: string = "user1"; -var name: string = "Kevin Fernandez"; - -var user: CometChat.User = new CometChat.User(uid); +const authKey: string = "YOUR_AUTH_KEY"; +const uid: string = "user1"; -user.setName(name); +const user: CometChat.User = new CometChat.User(uid); +user.setName("Kevin Fernandez"); +user.setAvatar("https://example.com/new-avatar.png"); CometChat.updateUser(user, authKey).then( - (user: CometChat.User) => { - console.log("user updated", user); - }, (error: CometChat.CometChatException) => { - console.log("error", error); + (user: CometChat.User) => console.log("User updated:", user), + (error: CometChat.CometChatException) => console.log("Failed:", error) +); +``` + + +```javascript +const updateUser = async () => { + try { + const authKey = "YOUR_AUTH_KEY"; + const uid = "user1"; + + const user = new CometChat.User(uid); + user.setName("Kevin Fernandez"); + user.setAvatar("https://example.com/new-avatar.png"); + + const updatedUser = await CometChat.updateUser(user, authKey); + console.log("User updated:", updatedUser); + } catch (error) { + console.log("Failed to update:", error); } -) +}; ``` - - -Please make sure the `User` object provided to the `updateUser()` method has the `UID` of the user to be updated set. +--- -## Updating logged-in user +## Update Current User -Updating a logged-in user is similar to updating a user. The only difference being this method does not require an AuthKey. This method takes a `User` object as input and returns the updated `User` object on the successful execution of the request. +The logged-in user can update their own profile without the Auth Key: -```js -let uid = "user1"; -let name = "Kevin Fernandez"; - -var user = new CometChat.User(uid); +```javascript +const user = new CometChat.User("user1"); +user.setName("Kevin Fernandez"); +user.setAvatar("https://example.com/new-avatar.png"); +user.setStatusMessage("In a meeting"); -user.setName(name); +CometChat.updateCurrentUserDetails(user).then( + (user) => console.log("Profile updated:", user), + (error) => console.log("Failed to update:", error) +); +``` + + +```typescript +const user: CometChat.User = new CometChat.User("user1"); +user.setName("Kevin Fernandez"); +user.setAvatar("https://example.com/new-avatar.png"); +user.setStatusMessage("In a meeting"); CometChat.updateCurrentUserDetails(user).then( - user => { - console.log("user updated", user); - }, error => { - console.log("error", error); + (user: CometChat.User) => console.log("Profile updated:", user), + (error: CometChat.CometChatException) => console.log("Failed:", error) +); +``` + + +```javascript +const updateMyProfile = async () => { + try { + const user = new CometChat.User("user1"); + user.setName("Kevin Fernandez"); + user.setAvatar("https://example.com/new-avatar.png"); + user.setStatusMessage("In a meeting"); + + const updatedUser = await CometChat.updateCurrentUserDetails(user); + console.log("Profile updated:", updatedUser); + } catch (error) { + console.log("Failed to update:", error); } -) +}; ``` - + - -```typescript -var uid: string = "user1"; -var name: string = "Kevin Fernandez"; + +`updateCurrentUserDetails()` only updates the logged-in user regardless of the UID provided. You cannot change the user's role with this method. + -var user: CometChat.User = new CometChat.User(uid); +--- -user.setName(name); +## Delete a User -CometChat.updateCurrentUserDetails(user).then( - (user: CometChat.User) => { - console.log("user updated", user); - }, (error: CometChat.CometChatException) => { - console.log("error", error); - } -); +User deletion is only available via the REST API for security reasons. + +```bash +curl -X DELETE "https://api-{region}.cometchat.io/v3/users/{uid}" \ + -H "apiKey: YOUR_API_KEY" \ + -H "Content-Type: application/json" ``` - +[View REST API Documentation →](https://api-explorer.cometchat.com/reference/delete-user) - +--- + +## User Properties Reference + +| Property | Editable | Type | Description | +|----------|----------|------|-------------| +| `uid` | Create only | String | Unique identifier | +| `name` | Yes | String | Display name | +| `avatar` | Yes | String | URL to profile picture | +| `link` | Yes | String | URL to profile page | +| `role` | Yes* | String | Role for access control | +| `metadata` | Yes | Object | Custom JSON data | +| `status` | No | String | Online/offline (system managed) | +| `statusMessage` | Yes | String | Custom status message | +| `lastActiveAt` | No | Number | Unix timestamp of last activity | +| `hasBlockedMe` | No | Boolean | If user has blocked logged-in user | +| `blockedByMe` | No | Boolean | If logged-in user has blocked this user | +| `tags` | Yes | Array | Tags for categorization | + + +*Role can only be updated via `updateUser()` with Auth Key, not via `updateCurrentUserDetails()`. + + +--- + +## Working with User Properties -By using the `updateCurrentUserDetails()` method one can only update the logged-in user irrespective of the UID passed. Also, it is not possible to update the role of a logged-in user. +### Set Custom Metadata -## Deleting a user +```javascript +const user = new CometChat.User("user1"); +user.setMetadata({ + department: "Engineering", + skills: ["JavaScript", "React", "Node.js"], + preferences: { notifications: true, theme: "dark" } +}); +``` + +### Set User Tags + +```javascript +const user = new CometChat.User("user1"); +user.setTags(["premium", "developer", "team-alpha"]); +``` + +### Get User Properties -Deleting a user can only be achieved via the Restful APIs. For more information please check the [delete a user](https://api-explorer.cometchat.com/reference/delete-user) section. +```javascript +const user = await CometChat.getUser("user1"); -## User Class +console.log("UID:", user.getUid()); +console.log("Name:", user.getName()); +console.log("Avatar:", user.getAvatar()); +console.log("Status:", user.getStatus()); +console.log("Last Active:", user.getLastActiveAt()); +console.log("Metadata:", user.getMetadata()); +console.log("Tags:", user.getTags()); +``` + +--- + +## Best Practices + + + + - Use your existing user IDs as CometChat UIDs for easy mapping + - Keep UIDs consistent across your system + - Avoid using email addresses as UIDs (they may change) + + + - Create users from your backend, not client-side + - Use Auth Tokens instead of Auth Key for login in production + - Never expose your Auth Key in client code + + + - Keep CometChat user data in sync with your database + - Update CometChat when users change their profile in your app + - Use metadata for app-specific data that doesn't fit standard fields + + + +--- -| Field | Editable | Information | -| ------------- | --------------------------------------------------- | -------------------------------------------------------------------- | -| uid | specified on user creation. Not editable after that | Unique identifier of the user | -| name | Yes | Display name of the user | -| avatar | Yes | URL to profile picture of the user | -| link | Yes | URL to profile page | -| role | Yes | User role of the user for role based access control | -| metadata | Yes | Additional information about the user as JSON | -| status | No | Status of the user. Could be either online/offline | -| statusMessage | Yes | Any custom status message that needs to be set for a user | -| lastActiveAt | No | The unix timestamp of the time the user was last active. | -| hasBlockedMe | No | A boolean that determines if the user has blocked the logged in user | -| blockedByMe | No | A boolean that determines if the logged in user has blocked the user | -| tags | Yes | A list of tags to identify specific users | +## Next Steps + + + + Fetch and search users in your app + + + Block and unblock users + + + Track online/offline status + + + Login and logout users + + diff --git a/sdk/javascript/user-presence.mdx b/sdk/javascript/user-presence.mdx index 503bc0d6..2a9cb4b1 100644 --- a/sdk/javascript/user-presence.mdx +++ b/sdk/javascript/user-presence.mdx @@ -1,109 +1,333 @@ --- title: "User Presence" -sidebarTitle: "Overview" +sidebarTitle: "User Presence" +description: "Track when users are online or offline in real-time" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Configure presence during init +const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() // or subscribePresenceForRoles(["admin"]) + .setRegion(region) + .build(); +await CometChat.init(appID, appSettings); + +// Listen for presence changes +CometChat.addUserListener("PRESENCE_LISTENER", new CometChat.UserListener({ + onUserOnline: (user) => console.log(user.getName(), "is online"), + onUserOffline: (user) => { + console.log(user.getName(), "went offline"); + console.log("Last seen:", user.getLastActiveAt()); + } +})); +// Check user status +const user = await CometChat.getUser("user_uid"); +const status = user.getStatus(); // "online" or "offline" +const lastActive = user.getLastActiveAt(); // Unix timestamp +``` + -User Presence helps us understand if a user is available to chat or not. +User presence shows whether users are currently online and available to chat. CometChat provides real-time presence updates and last-seen timestamps. -## Real-time Presence + +**Availability**: SDK, API, UI Kits -*In other words, as a logged-in user, how do I know if a user is online or offline?* +Presence must be configured during SDK initialization. + -Based on the settings provided in the AppSettings class while initialising the SDK using the `init()` method, the logged-in user will receive the presence for the other users in the app. +--- -In the `AppSettings` class, you can set the type of Presence you wish to receive for that particular session of the app. +## Configure Presence Subscription -For presence subscription, the AppSettingsBuilder provides 3 methods : +Set up presence subscription when initializing the SDK using `AppSettingsBuilder`: -* `subscribePresenceForAllUsers()` - this will inform the logged-in user when any user in the app comes online or goes offline -* `subscribePresenceForRoles(Array roles)` - This will inform the logged-in user, only when the users with the specified roles come online or go offline. -* `subscribePresenceForFriends()` - This will inform the logged-in user, only when either of his friends come online or go offline. + + +```javascript +const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForAllUsers() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + +CometChat.init(appID, appSettings); +``` + + +```javascript +const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForRoles(["admin", "moderator"]) + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + +CometChat.init(appID, appSettings); +``` + + +```javascript +const appSettings = new CometChat.AppSettingsBuilder() + .subscribePresenceForFriends() + .setRegion(region) + .autoEstablishSocketConnection(true) + .build(); + +CometChat.init(appID, appSettings); +``` + + + +| Method | Description | +|--------|-------------| +| `subscribePresenceForAllUsers()` | Receive presence for all users | +| `subscribePresenceForRoles(roles)` | Receive presence for users with specific roles | +| `subscribePresenceForFriends()` | Receive presence for friends only | + + +If no presence method is called, no presence updates will be received. + -If none of the above methods are used, no presence will be sent to the logged-in user. +--- + +## Listen for Presence Changes -You need to register the `UserListener` using the `addUserListener()` method where ever you wish to receive these events in. +Register a listener to receive real-time presence updates: - -``` -let listenerID = "UNIQUE_LISTENER_ID"; + +```javascript +const listenerID = "PRESENCE_LISTENER"; CometChat.addUserListener( -listenerID, -new CometChat.UserListener({ - onUserOnline: onlineUser => { - console.log("On User Online:", { onlineUser }); - }, - onUserOffline: offlineUser => { - console.log("On User Offline:", { offlineUser }); - } -}) -); + listenerID, + new CometChat.UserListener({ + onUserOnline: (user) => { + console.log(`${user.getName()} is now online`); + }, + onUserOffline: (user) => { + console.log(`${user.getName()} went offline`); + console.log("Last seen:", user.getLastActiveAt()); + } + }) +); ``` - - ```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; +const listenerID: string = "PRESENCE_LISTENER"; CometChat.addUserListener( listenerID, new CometChat.UserListener({ - onUserOnline: (onlineUser: CometChat.User) => { - console.log("On User Online:", { onlineUser }); - }, - onUserOffline: (offlineUser: CometChat.User) => { - console.log("On User Offline:", { offlineUser }); - } + onUserOnline: (user: CometChat.User) => { + console.log(`${user.getName()} is now online`); + }, + onUserOffline: (user: CometChat.User) => { + console.log(`${user.getName()} went offline`); + console.log("Last seen:", user.getLastActiveAt()); + } }) ); ``` - - -| Parameter | Description | -| ------------ | --------------------------------------------- | -| `listenerID` | An ID that uniquely identifies that listener. | +### Remove Listener -You will receive an object of the `User` class in the listener methods. +```javascript +CometChat.removeUserListener("PRESENCE_LISTENER"); +``` -We recommend you remove the listener once the activity or view is not in use. -We suggest adding this method when not in use. +--- - - -``` -let listenerID = "UNIQUE_LISTENER_ID"; -CometChat.removeUserListener(listenerID); -``` +## Check User Status - +When fetching users, check their presence status: - -```typescript -let listenerID: string = "UNIQUE_LISTENER_ID"; -CometChat.removeUserListener(listenerID); +```javascript +const user = await CometChat.getUser("user1"); + +// Get current status +const status = user.getStatus(); // "online" or "offline" + +// Get last active timestamp (when offline) +const lastActive = user.getLastActiveAt(); + +if (status === "online") { + console.log("User is online"); +} else { + const lastSeen = new Date(lastActive * 1000); + console.log("Last seen:", lastSeen.toLocaleString()); +} ``` - +--- - +## User Status Properties + +| Property | Type | Description | +|----------|------|-------------| +| `status` | String | `"online"` or `"offline"` | +| `lastActiveAt` | Number | Unix timestamp of last activity | + +--- + +## Implementation Example + +```javascript +class PresenceManager { + constructor() { + this.onlineUsers = new Set(); + this.listenerID = "presence-manager"; + } + + initialize() { + CometChat.addUserListener( + this.listenerID, + new CometChat.UserListener({ + onUserOnline: (user) => this.handleOnline(user), + onUserOffline: (user) => this.handleOffline(user) + }) + ); + } + + handleOnline(user) { + this.onlineUsers.add(user.getUid()); + this.updateUI(user.getUid(), "online"); + } + + handleOffline(user) { + this.onlineUsers.delete(user.getUid()); + this.updateUI(user.getUid(), "offline", user.getLastActiveAt()); + } -## User List Presence + isOnline(uid) { + return this.onlineUsers.has(uid); + } -*In other words, as a logged-in user, when I retrieve the user list, how do I know if a user is online/offline?* + updateUI(uid, status, lastActive = null) { + // Update your UI here + console.log(`${uid} is now ${status}`); + if (lastActive) { + console.log("Last seen:", new Date(lastActive * 1000)); + } + } -When you fetch the list of users, in the [User](/sdk/javascript/user-management#user-class) object, you will receive 2 fields + formatLastSeen(timestamp) { + if (!timestamp) return "Unknown"; + + const now = Date.now(); + const diff = now - timestamp * 1000; + + const minutes = Math.floor(diff / 60000); + const hours = Math.floor(diff / 3600000); + const days = Math.floor(diff / 86400000); + + if (minutes < 1) return "Just now"; + if (minutes < 60) return `${minutes}m ago`; + if (hours < 24) return `${hours}h ago`; + return `${days}d ago`; + } + + cleanup() { + CometChat.removeUserListener(this.listenerID); + } +} -1. `status` - This will hold either of the two values : +// Usage +const presenceManager = new PresenceManager(); +presenceManager.initialize(); -* online - This indicates that the user is currently online and available to chat. -* offline - This indicates that the user is currently offline and is not available to chat. +// Check if user is online +if (presenceManager.isOnline("user123")) { + console.log("User is online"); +} + +// Cleanup when done +presenceManager.cleanup(); +``` + +--- + +## Display Presence Indicator + +```javascript +function getPresenceIndicator(user) { + const status = user.getStatus(); + + if (status === "online") { + return { + color: "green", + text: "Online" + }; + } + + const lastActive = user.getLastActiveAt(); + const lastSeen = formatLastSeen(lastActive); + + return { + color: "gray", + text: `Last seen ${lastSeen}` + }; +} + +function formatLastSeen(timestamp) { + if (!timestamp) return "Unknown"; + + const now = Date.now(); + const diff = now - timestamp * 1000; + const minutes = Math.floor(diff / 60000); + + if (minutes < 1) return "just now"; + if (minutes < 60) return `${minutes} min ago`; + if (minutes < 1440) return `${Math.floor(minutes / 60)} hours ago`; + return new Date(timestamp * 1000).toLocaleDateString(); +} +``` + +--- + +## Best Practices + + + + - Use role-based or friends-only presence for large apps + - `subscribePresenceForAllUsers()` can be resource-intensive with many users + - Remove listeners when components unmount + + + - Show green dot for online users + - Display "Last seen" for offline users + - Update presence indicators in real-time + - Consider showing "typing..." instead of "online" when user is typing + + + - Some users may prefer to hide their online status + - Consider adding presence privacy settings in your app + + + +--- -2. `lastActiveAt` - in case the user is offline, this field holds the timestamp of the time when the user was last online. This can be used to display the Last seen of the user if need be. +## Next Steps + + + + Fetch and search users + + + Show when users are typing + + + Create and update users + + + Block and unblock users + + diff --git a/sdk/javascript/users-overview.mdx b/sdk/javascript/users-overview.mdx index 2193624f..26274d03 100644 --- a/sdk/javascript/users-overview.mdx +++ b/sdk/javascript/users-overview.mdx @@ -1,10 +1,353 @@ --- title: "Users" sidebarTitle: "Overview" +description: "Manage users and build contact lists in your chat application" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Get current user +const user = await CometChat.getLoggedinUser(); -The primary aim for our Users functionality is to allow you to quickly retrieve and add users to CometChat. +// Fetch users list +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .build(); +const users = await usersRequest.fetchNext(); -You can begin with [user management](/sdk/javascript/user-management) to sync your users to CometChat. Once that is done, you can [retrieve users](/sdk/javascript/retrieve-users) and display them in your app. +// Get specific user +const user = await CometChat.getUser("user_uid"); + +// Search users +const usersRequest = new CometChat.UsersRequestBuilder() + .setSearchKeyword("john") + .build(); + +// Filter online users +const usersRequest = new CometChat.UsersRequestBuilder() + .setStatus(CometChat.USER_STATUS.ONLINE) + .build(); + +// Listen for presence changes +CometChat.addUserListener("LISTENER_ID", new CometChat.UserListener({ + onUserOnline: (user) => console.log(user.getName(), "online"), + onUserOffline: (user) => console.log(user.getName(), "offline") +})); +``` + + +Users are the foundation of your chat application. This section covers retrieving, creating, updating, and managing users. + + +**Available via:** SDK | [REST API](https://api-explorer.cometchat.com) | [UI Kits](/ui-kit/react/overview) + + +--- + +## Core Concepts + +- **UID**: Unique identifier for each user (typically matches your database user ID) +- **User Object**: Contains profile info like name, avatar, status, and metadata +- **Presence**: Real-time online/offline status + +--- + +## Quick Start + +### Get Current User + + + +```javascript +CometChat.getLoggedinUser().then( + (user) => { + if (user) { + console.log("Logged in as:", user.getName()); + } + } +); +``` + + +```javascript +async function getCurrentUser() { + try { + const user = await CometChat.getLoggedinUser(); + if (user) { + console.log("Logged in as:", user.getName()); + } + return user; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Fetch Users + + + +```javascript +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .build(); + +usersRequest.fetchNext().then( + (users) => console.log("Users:", users), + (error) => console.log("Error:", error) +); +``` + + +```javascript +async function fetchUsers() { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .build(); + + try { + const users = await usersRequest.fetchNext(); + console.log("Users:", users); + return users; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +--- + +## User Management + + + + Fetch user lists with filtering and search + + + Create, update, and manage user profiles + + + Block and unblock users + + + Track online/offline status in real-time + + + +--- + +## User Object Properties + +| Property | Method | Description | Editable | +|----------|--------|-------------|----------| +| UID | `getUid()` | Unique identifier | No (set at creation) | +| Name | `getName()` | Display name | Yes | +| Avatar | `getAvatar()` | Profile picture URL | Yes | +| Status | `getStatus()` | `online` or `offline` | No (system managed) | +| Role | `getRole()` | User role for access control | Yes | +| Metadata | `getMetadata()` | Custom JSON data | Yes | +| Status Message | `getStatusMessage()` | Custom status text | Yes | +| Last Active | `getLastActiveAt()` | Last activity timestamp | No | +| Link | `getLink()` | Profile page URL | Yes | +| Tags | `getTags()` | Array of tags | Yes | +| Blocked By Me | `getBlockedByMe()` | If logged-in user blocked them | No | +| Has Blocked Me | `getHasBlockedMe()` | If they blocked logged-in user | No | + +--- + +## Common Use Cases + +### Build a Contacts List + + + +```javascript +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .friendsOnly(true) + .build(); + +usersRequest.fetchNext().then((users) => { + users.forEach((user) => { + console.log(user.getName(), user.getStatus()); + }); +}); +``` + + +```javascript +async function fetchContacts() { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .friendsOnly(true) + .build(); + + try { + const users = await usersRequest.fetchNext(); + users.forEach((user) => { + console.log(user.getName(), user.getStatus()); + }); + return users; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Search Users + + + +```javascript +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setSearchKeyword("john") + .build(); + +usersRequest.fetchNext().then((users) => { + console.log("Search results:", users); +}); +``` + + +```javascript +async function searchUsers(keyword) { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setSearchKeyword(keyword) + .build(); + + try { + const users = await usersRequest.fetchNext(); + console.log("Search results:", users); + return users; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Filter Online Users + + + +```javascript +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setStatus(CometChat.USER_STATUS.ONLINE) + .build(); + +usersRequest.fetchNext().then((users) => { + console.log("Online users:", users); +}); +``` + + +```javascript +async function fetchOnlineUsers() { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setStatus(CometChat.USER_STATUS.ONLINE) + .build(); + + try { + const users = await usersRequest.fetchNext(); + console.log("Online users:", users); + return users; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +### Filter by Role + + + +```javascript +const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setRoles(["premium", "moderator"]) + .build(); + +usersRequest.fetchNext().then((users) => { + console.log("Premium/Moderator users:", users); +}); +``` + + +```javascript +async function fetchUsersByRole(roles) { + const usersRequest = new CometChat.UsersRequestBuilder() + .setLimit(30) + .setRoles(roles) + .build(); + + try { + const users = await usersRequest.fetchNext(); + console.log("Filtered users:", users); + return users; + } catch (error) { + console.log("Error:", error); + throw error; + } +} +``` + + + +--- + +## Real-Time User Events + +Listen for user status changes: + +```javascript +const listenerID = "USER_LISTENER"; + +CometChat.addUserListener( + listenerID, + new CometChat.UserListener({ + onUserOnline: (onlineUser) => { + console.log("User online:", onlineUser.getName()); + }, + onUserOffline: (offlineUser) => { + console.log("User offline:", offlineUser.getName()); + } + }) +); + +// Remove when done +CometChat.removeUserListener(listenerID); +``` + +--- + +## Next Steps + + + + Learn all filtering and pagination options + + + Implement real-time online/offline status + + diff --git a/sdk/javascript/video-view-customisation.mdx b/sdk/javascript/video-view-customisation.mdx index 2fd63257..d4399dab 100644 --- a/sdk/javascript/video-view-customisation.mdx +++ b/sdk/javascript/video-view-customisation.mdx @@ -1,41 +1,249 @@ --- -title: "Video View Customisation" +title: "Video View Customization" +sidebarTitle: "Video Customization" +description: "Customize the main video container appearance and controls" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** +```javascript +// Configure video container settings +const videoSettings = new CometChatCalls.MainVideoContainerSetting(); +videoSettings.setMainVideoAspectRatio(CometChatCalls.ASPECT_RATIO_CONTAIN); +videoSettings.setFullScreenButtonParams(CometChatCalls.POSITION_BOTTOM_RIGHT, true); +videoSettings.setNameLabelParams(CometChatCalls.POSITION_BOTTOM_LEFT, true, "rgba(27,27,27,0.4)"); -This section will guide you to customise the main video container. +// Apply to call settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .setMainVideoContainerSetting(videoSettings) + .build(); +``` + + +Customize the main video container's aspect ratio, button positions, and label visibility to match your application's design. + +## Prerequisites + +Before customizing video views, ensure you have implemented either: +- [Ringing](/sdk/javascript/default-call) calling flow +- [Call Session](/sdk/javascript/direct-call) calling flow + +## Main Video Container Settings + +Use the `MainVideoContainerSetting` class to customize the main video view: + + + +```javascript +const videoSettings = new CometChatCalls.MainVideoContainerSetting(); + +// Set aspect ratio +videoSettings.setMainVideoAspectRatio( + CometChatCalls.ASPECT_RATIO_CONTAIN +); + +// Configure full screen button +videoSettings.setFullScreenButtonParams( + CometChatCalls.POSITION_BOTTOM_RIGHT, + true // visible +); + +// Configure name label +videoSettings.setNameLabelParams( + CometChatCalls.POSITION_BOTTOM_LEFT, + true, // visible + "rgba(27, 27, 27, 0.4)" // background color +); + +// Configure network quality label +videoSettings.setNetworkLabelParams( + CometChatCalls.POSITION_BOTTOM_RIGHT, + true // visible +); + +// Apply to call settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setMainVideoContainerSetting(videoSettings) + .setCallListener(callListener) + .build(); +``` + + +```typescript +const videoSettings = new CometChatCalls.MainVideoContainerSetting(); + +// Set aspect ratio +videoSettings.setMainVideoAspectRatio( + CometChatCalls.ASPECT_RATIO_CONTAIN +); + +// Configure full screen button +videoSettings.setFullScreenButtonParams( + CometChatCalls.POSITION_BOTTOM_RIGHT, + true +); + +// Configure name label +videoSettings.setNameLabelParams( + CometChatCalls.POSITION_BOTTOM_LEFT, + true, + "rgba(27, 27, 27, 0.4)" +); + +// Configure network quality label +videoSettings.setNetworkLabelParams( + CometChatCalls.POSITION_BOTTOM_RIGHT, + true +); + +// Apply to call settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setMainVideoContainerSetting(videoSettings) + .setCallListener(callListener) + .build(); +``` + + -## Implementation +## Configuration Options -Once you have decided to implement [Default Calling](/sdk/javascript/default-call) or [Direct Calling](/sdk/javascript/direct-call) calling and followed the steps to implement them. Just few additional methods will help you quickly customize the main video container. +### Aspect Ratio -Please make sure your callSettings is configured accordingly for [Default Calling](/sdk/javascript/default-call) or [Direct Calling](/sdk/javascript/direct-call). +Control how the video fills the container: -## Main Video Container Setting +| Value | Description | +|-------|-------------| +| `CometChatCalls.ASPECT_RATIO_CONTAIN` | Video fits within container, may have letterboxing (default) | +| `CometChatCalls.ASPECT_RATIO_COVER` | Video fills container, may be cropped | -The `MainVideoContainerSetting` Class is the required in case you want to customise the main video view. You need to pass the Object of the `MainVideoContainerSetting` Class in the `setMainVideoContainerSetting()` method of the `CallSettingsBuilder`. +### Position Constants -| Setting | Description | -| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `setMainVideoAspectRatio(aspectRatio: string)` | This method is used to set the aspect ratio of main video. The default value is **contain.**

Possible Values:
**1. CometChat.CallSettings. ASPECT\_RATIO\_CONTAIN\*\*\*\***
**2. CometChat.CallSettings. ASPECT\_RATIO\_COVER** | -| `setFullScreenButtonParams(position: string, visibility: boolean)` | This method is used to set the position & visibility parameter of the full screen button. By default the full screen button is visible in the **bottom-right** position.

Possible Values for **POSITION:**
1. **CometChat.CallSettings. POSITION\_TOP\_LEFT**
2. **CometChat.CallSettings. POSITION\_TOP\_RIGHT**
3. **CometChat.CallSettings. POSITION\_BOTTOM\_LEFT**
4. **CometChat.CallSettings. POSITION\_BOTTOM\_RIGHT**

Possible Values for **VISIBILITY:**
1. **true**
2. **false** | -| `setNameLabelParams(position: string, visibility: boolean, backgroundColor: string)` | This method is used to set the position, visibility & background color of the name label. By default the name label is visible in the **bottom-left** position with a background-color \*\*rgba(27, 27, 27, 0.4)\*\*

Possible Values for **POSITION:**
1. **CometChat.CallSettings. POSITION\_TOP\_LEFT**
2. **CometChat.CallSettings. POSITION\_TOP\_RIGHT**
3. **CometChat.CallSettings. POSITION\_BOTTOM\_LEFT**
4. **CometChat.CallSettings. POSITION\_BOTTOM\_RIGHT**

Possible Values for **VISIBILITY:**
1. **true**
2. **false** | -| `setNetworkLabelParams(position: string, visibility: boolean)` | This method is used to set the position, visibility of the network label. By default the network label is visible in the **bottom-right** position.

Possible Values for **POSITION:**
1. **CometChat.CallSettings. POSITION\_TOP\_LEFT**
2. **CometChat.CallSettings. POSITION\_TOP\_RIGHT**
3. **CometChat.CallSettings. POSITION\_BOTTOM\_LEFT**
4. **CometChat.CallSettings. POSITION\_BOTTOM\_RIGHT**

Possible Values for **VISIBILITY:**
1. **true**
2. **false** | +Available positions for buttons and labels: -Example: +| Constant | Position | +|----------|----------| +| `CometChatCalls.POSITION_TOP_LEFT` | Top left corner | +| `CometChatCalls.POSITION_TOP_RIGHT` | Top right corner | +| `CometChatCalls.POSITION_BOTTOM_LEFT` | Bottom left corner | +| `CometChatCalls.POSITION_BOTTOM_RIGHT` | Bottom right corner | + +## Setting Methods + +| Method | Description | Default | +|--------|-------------|---------| +| `setMainVideoAspectRatio(ratio)` | Set video aspect ratio | `ASPECT_RATIO_CONTAIN` | +| `setFullScreenButtonParams(position, visible)` | Configure full screen button | Bottom right, visible | +| `setNameLabelParams(position, visible, bgColor)` | Configure participant name label | Bottom left, visible, `rgba(27, 27, 27, 0.4)` | +| `setNetworkLabelParams(position, visible)` | Configure network quality indicator | Bottom right, visible | + +## Examples + +### Minimal UI + +Hide all overlays for a clean video view: + +```javascript +const videoSettings = new CometChatCalls.MainVideoContainerSetting(); + +videoSettings.setFullScreenButtonParams( + CometChatCalls.POSITION_BOTTOM_RIGHT, + false // hidden +); +videoSettings.setNameLabelParams( + CometChatCalls.POSITION_BOTTOM_LEFT, + false, // hidden + "transparent" +); +videoSettings.setNetworkLabelParams( + CometChatCalls.POSITION_BOTTOM_RIGHT, + false // hidden +); +``` + ```typescript -let videoSettings = new CometChat.MainVideoContainerSetting(); +const videoSettings = new CometChatCalls.MainVideoContainerSetting(); -videoSettings.setMainVideoAspectRatio(CometChat.CallSettings.ASPECT_RATIO_CONTAIN); -videoSettings.setFullScreenButtonParams(CometChat.CallSettings.POSITION_BOTTOM_RIGHT, true); -videoSettings.setNameLabelParams(CometChat.CallSettings.POSITION_BOTTOM_LEFT, true, "rgba(27, 27, 27, 0.4)"); -videoSettings.setNetworkLabelParams(CometChat.CallSettings.POSITION_BOTTOM_RIGHT, true); +videoSettings.setFullScreenButtonParams( + CometChatCalls.POSITION_BOTTOM_RIGHT, + false +); +videoSettings.setNameLabelParams( + CometChatCalls.POSITION_BOTTOM_LEFT, + false, + "transparent" +); +videoSettings.setNetworkLabelParams( + CometChatCalls.POSITION_BOTTOM_RIGHT, + false +); ``` + + +### Custom Branding + +Apply custom colors to match your brand: + + + +```javascript +const videoSettings = new CometChatCalls.MainVideoContainerSetting(); + +// Cover mode for full-bleed video +videoSettings.setMainVideoAspectRatio( + CometChatCalls.ASPECT_RATIO_COVER +); + +// Name label with brand color +videoSettings.setNameLabelParams( + CometChatCalls.POSITION_TOP_LEFT, + true, + "rgba(0, 115, 255, 0.8)" // Brand blue +); + +// Move full screen to top right +videoSettings.setFullScreenButtonParams( + CometChatCalls.POSITION_TOP_RIGHT, + true +); +``` + +```typescript +const videoSettings = new CometChatCalls.MainVideoContainerSetting(); +videoSettings.setMainVideoAspectRatio( + CometChatCalls.ASPECT_RATIO_COVER +); + +videoSettings.setNameLabelParams( + CometChatCalls.POSITION_TOP_LEFT, + true, + "rgba(0, 115, 255, 0.8)" +); + +videoSettings.setFullScreenButtonParams( + CometChatCalls.POSITION_TOP_RIGHT, + true +); +``` + + +## Next Steps + + + + Style the entire call UI with CSS + + + Add blur or custom backgrounds + + diff --git a/sdk/javascript/virtual-background.mdx b/sdk/javascript/virtual-background.mdx index 63edd0a8..752e1e4c 100644 --- a/sdk/javascript/virtual-background.mdx +++ b/sdk/javascript/virtual-background.mdx @@ -1,116 +1,314 @@ --- title: "Virtual Background" +description: "Apply blur or custom image backgrounds during video calls" --- +{/* TL;DR for Agents and Quick Reference */} + +**Quick Reference for AI Agents & Developers** + +```javascript +// Configure virtual background +const virtualBackground = new CometChatCalls.VirtualBackground(); +virtualBackground.allowBackgroundBlur(true); +virtualBackground.allowUserImages(true); +virtualBackground.setImages(["https://example.com/bg1.jpg"]); +virtualBackground.enforceBackgroundBlur(50); // Start with blur (1-99) + +// Apply to call settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .showVirtualBackgroundSetting(true) + .setVirtualBackground(virtualBackground) + .build(); + +// Programmatic control during call +const controller = CometChatCalls.CallController.getInstance(); +controller.setBackgroundBlur(50); +controller.setBackgroundImage("https://example.com/bg.jpg"); +``` + + +**Available via**: SDK | UI Kits + -This section will guide you to implement virtual background feature in video calls. +Enhance video calls with virtual backgrounds, allowing users to blur their surroundings or display custom images behind them. -## Implementation +## Prerequisites -Once you have decided to implement [Default Calling](/sdk/javascript/default-call) or [Direct Calling](/sdk/javascript/direct-call) calling and followed the steps to implement them. Just few additional methods will help you quickly implement virtual background. +Before implementing virtual backgrounds, ensure you have: +1. Completed the [Calls SDK Setup](/sdk/javascript/calling-setup) +2. Implemented either [Ringing](/sdk/javascript/default-call) or [Call Session](/sdk/javascript/direct-call) calling -Please make sure your callSettings is configured accordingly for [Default Calling](/sdk/javascript/default-call) or [Direct Calling](/sdk/javascript/direct-call). +## Quick Start -## Settings +Enable virtual background settings in your call configuration: -The `CallSettings`class allows you to customise the overall calling experience. The properties for the call/conference can be set using the `CallSettingsBuilder` class. This will eventually give you and object of the `CallSettings` class which you can pass to the `startCall()` method to start the call. + + +```javascript +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .showVirtualBackgroundSetting(true) // Show VB button in UI + .setCallListener(callListener) + .build(); +``` + + +```typescript +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .showVirtualBackgroundSetting(true) + .setCallListener(callListener) + .build(); +``` + + + +## Call Settings Options + +| Method | Description | Default | +|--------|-------------|---------| +| `showVirtualBackgroundSetting(boolean)` | Show/hide virtual background button in menu | `true` | +| `setVirtualBackground(VirtualBackground)` | Configure virtual background options | - | -The **mandatory** parameters that are required to be present for any call/conference to work are: +## Virtual Background Configuration -1. sessionId - The unique session Id for the call/conference session. +Use the `VirtualBackground` class to customize available options: -The options available for virtual background are: + + +```javascript +const virtualBackground = new CometChatCalls.VirtualBackground(); + +// Allow background blur +virtualBackground.allowBackgroundBlur(true); + +// Allow users to upload custom images +virtualBackground.allowUserImages(true); + +// Show default background images +virtualBackground.showDefaultImages(true); + +// Add custom background images +virtualBackground.setImages([ + "https://example.com/bg1.jpg", + "https://example.com/bg2.jpg", + "https://example.com/bg3.jpg" +]); + +// Apply to call settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setVirtualBackground(virtualBackground) + .setCallListener(callListener) + .build(); +``` + + +```typescript +const virtualBackground = new CometChatCalls.VirtualBackground(); + +virtualBackground.allowBackgroundBlur(true); +virtualBackground.allowUserImages(true); +virtualBackground.showDefaultImages(true); +virtualBackground.setImages([ + "https://example.com/bg1.jpg", + "https://example.com/bg2.jpg", + "https://example.com/bg3.jpg" +]); + +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setVirtualBackground(virtualBackground) + .setCallListener(callListener) + .build(); +``` + + -| Setting | Description | -| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -| `showVirtualBackgroundSetting(showVBSettings: boolean)` | This method shows/hides the virtual background settings in the menu bar. **Default value = true** | -| `setVirtualBackground(virtualBackground: CometChat.VirtualBackground)` | This method will set the virtual background setting. This methods takes an Object of Virtual Background Class. | +## Configuration Options -For the use case where you wish to align your own custom buttons and not use the default layout provided by CometChat, you can embed the buttons in your layout and use the below methods to perform the corresponding operations: +| Method | Description | Default | +|--------|-------------|---------| +| `allowBackgroundBlur(boolean)` | Allow users to blur their background | `true` | +| `allowUserImages(boolean)` | Allow users to upload custom images | `true` | +| `showDefaultImages(boolean)` | Show CometChat's default background images | `true` | +| `setImages(string[])` | Add custom background images (URLs) | `[]` | +| `enforceBackgroundBlur(number)` | Start call with blur enabled (1-99 intensity) | `0` (disabled) | +| `enforceBackgroundImage(string)` | Start call with specific background image | - | -### Open Virtual Background Setting +## Enforce Settings -You can use the `openVirtualBackground()` method to open the virtual background settings pop-up. +Force specific virtual background settings when the call starts: - -```js -let callController = CometChat.CallController.getInstance(); -callController.openVirtualBackground(); + +```javascript +const virtualBackground = new CometChatCalls.VirtualBackground(); + +// Start call with medium blur (1-99) +virtualBackground.enforceBackgroundBlur(50); + +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setVirtualBackground(virtualBackground) + .build(); ``` + + +```javascript +const virtualBackground = new CometChatCalls.VirtualBackground(); + +// Start call with specific background +virtualBackground.enforceBackgroundImage("https://example.com/office-bg.jpg"); +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .setVirtualBackground(virtualBackground) + .build(); +``` + + +## Programmatic Control +For custom UI implementations, control virtual backgrounds programmatically: + +### Open Settings Dialog + + + +```javascript +const callController = CometChatCalls.CallController.getInstance(); +callController.openVirtualBackground(); +``` + ```typescript -let callController: CometChat.CallController = CometChat.CallController.getInstance(); +const callController = CometChatCalls.CallController.getInstance(); callController.openVirtualBackground(); ``` - - ### Set Background Blur -You can use the `setBackgroundBlur()` method to apply background blur on the video stream. This method accepts a number which decides the level of blur to be applied. +Apply blur with intensity from 1 (light) to 99 (heavy): -```js -let callController = CometChat.CallController.getInstance(); -let blurLevel = 1; -callController.setBackgroundBlur(blurLevel); -``` +```javascript +const callController = CometChatCalls.CallController.getInstance(); - +// Light blur +callController.setBackgroundBlur(20); + +// Medium blur +callController.setBackgroundBlur(50); +// Heavy blur +callController.setBackgroundBlur(80); +``` + ```typescript -let callController: CometChat.CallController = CometChat.CallController.getInstance(); -let blurLevel: number = 1; -callController.setBackgroundBlur(blurLevel); +const callController = CometChatCalls.CallController.getInstance(); +callController.setBackgroundBlur(50); ``` - - ### Set Background Image -You can use the `setBackgroundImage()`method to set the background image. This method takes either a URL or file Object & sets that image as the background. +Apply a custom background image: - -```js -let callController = CometChat.CallController.getInstance(); -let imageURL = "URL_OF_BACKGROUND_IMAGE"; -callController.setBackgroundImage(imageURL); + +```javascript +const callController = CometChatCalls.CallController.getInstance(); +callController.setBackgroundImage("https://example.com/background.jpg"); ``` - + +```javascript +const callController = CometChatCalls.CallController.getInstance(); + +// From file input +const fileInput = document.getElementById("bg-file-input"); +fileInput.addEventListener("change", (event) => { + const file = event.target.files[0]; + callController.setBackgroundImage(file); +}); +``` + + + +## Complete Example + + +```javascript +// Configure virtual background options +const virtualBackground = new CometChatCalls.VirtualBackground(); +virtualBackground.allowBackgroundBlur(true); +virtualBackground.allowUserImages(true); +virtualBackground.showDefaultImages(true); +virtualBackground.setImages([ + "https://example.com/office.jpg", + "https://example.com/nature.jpg", + "https://example.com/abstract.jpg" +]); + +// Optional: Start with blur enabled +virtualBackground.enforceBackgroundBlur(30); + +// Build call settings +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .showVirtualBackgroundSetting(true) + .setVirtualBackground(virtualBackground) + .setCallListener(callListener) + .build(); + +// Start the call +const htmlElement = document.getElementById("call-container"); +CometChatCalls.startSession(callToken, callSettings, htmlElement); +``` + ```typescript -let callController: CometChat.CallController = CometChat.CallController.getInstance(); -let imageURL: string = "URL_OF_BACKGROUND_IMAGE"; -callController.setBackgroundImage(imageURL); +const virtualBackground = new CometChatCalls.VirtualBackground(); +virtualBackground.allowBackgroundBlur(true); +virtualBackground.allowUserImages(true); +virtualBackground.showDefaultImages(true); +virtualBackground.setImages([ + "https://example.com/office.jpg", + "https://example.com/nature.jpg", + "https://example.com/abstract.jpg" +]); +virtualBackground.enforceBackgroundBlur(30); + +const callSettings = new CometChatCalls.CallSettingsBuilder() + .enableDefaultLayout(true) + .showVirtualBackgroundSetting(true) + .setVirtualBackground(virtualBackground) + .setCallListener(callListener) + .build(); + +const htmlElement = document.getElementById("call-container") as HTMLElement; +CometChatCalls.startSession(callToken, callSettings, htmlElement); ``` - - -## Virtual Background Settings - -The `VirtualBackground` Class is the required in case you want to change how the end user can use virtual background features in a video call. You need to pass the Object of the `VirtualBackground` Class in the `setVirtualBackground()` method of the `CallSettingsBuilder`. +## Next Steps -| Setting | Description | -| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `allowBackgroundBlur(allowBackgroundBlur: boolean)` | This method shows/hides the ability to allow end user to blur background. **Default = true** | -| `allowUserImages(allowUserImages: boolean)` | This method shows/hides the ability to allow end user to add their own custom background image. **Default = true** | -| `showDefaultImages(showDefaultImages: boolean)` | This method shows/hides the ability to allow end user to choose from default background images. **Default = true** | -| `setImages(images: Array)` | This method allows developer to add their custom background image which the end user can choose. | -| `enforceBackgroundBlur(enforceBackgroundBlur: number)` | This method starts the call with background blurred. To blur the background you need to pass an integer value between 1-99 which decides the blur level. **Default = 0** | -| `enforceBackgroundImage(enforceBackgroundImage: string)` | This methods starts the call with the provided background image. | + + + Customize video container appearance + + + Style the call UI with CSS + +