@traiyani/chatsdk-react 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,67 +16,713 @@ React SDK for ChatSDK - Real-time chat solution with product-based conversations
16
16
  - Ready-made UI components (Conversation List + Chat Window)
17
17
  - Pre-built — works with any bundler, zero config
18
18
 
19
- ## Requirements
19
+ ## Table of Contents
20
20
 
21
- - **React**: >= 16.8.0
22
- - **Node.js**: >= 16.0.0
21
+ 1. [Installation](#1-installation)
22
+ 2. [SDK Initialization](#2-sdk-initialization)
23
+ 3. [User Authentication](#3-user-authentication)
24
+ 4. [Start a New Conversation](#4-start-a-new-conversation)
25
+ 5. [Using Ready-Made UI Components](#5-using-ready-made-ui-components)
26
+ 6. [Sending Messages](#6-sending-messages)
27
+ 7. [File Uploads & Attachments](#7-file-uploads--attachments)
28
+ 8. [Unread Message Counts](#8-unread-message-counts)
29
+ 9. [Block & Unblock Users](#9-block--unblock-users)
30
+ 10. [Real-Time Events](#10-real-time-events)
31
+ 11. [Theme Support](#11-theme-support)
32
+ 12. [Internationalization (i18n)](#12-internationalization-i18n)
33
+ 13. [Logout & Cleanup](#13-logout--cleanup)
34
+ 14. [TypeScript Support](#14-typescript-support)
35
+ 15. [Troubleshooting](#15-troubleshooting)
23
36
 
24
- ## Installation
37
+ ---
38
+
39
+ ## 1. Installation
25
40
 
26
41
  ```bash
27
42
  npm install @traiyani/chatsdk-react axios socket.io-client
28
43
  ```
29
44
 
30
- Import the stylesheet in your app's entry point:
45
+ ### Requirements
46
+
47
+ | Dependency | Minimum Version |
48
+ |---|---|
49
+ | `react` | >= 16.8.0 |
50
+ | `react-dom` | >= 16.8.0 |
51
+ | `axios` | >= 0.21.0 |
52
+ | `socket.io-client` | >= 4.0.0 |
53
+
54
+ **No build configuration changes needed.** Works with Vite, webpack, Next.js, Create React App, Parcel, and any React bundler out of the box.
55
+
56
+ ### Import CSS
57
+
58
+ Import the stylesheet once in your app's entry point:
31
59
 
32
60
  ```tsx
33
61
  import '@traiyani/chatsdk-react/dist/chatsdk.css';
34
62
  ```
35
63
 
36
- ## Quick Start
64
+ ---
37
65
 
38
- See [DOCUMENTATION.md](./DOCUMENTATION.md) for the complete integration guide covering:
66
+ ## 2. SDK Initialization
39
67
 
40
- 1. SDK Initialization
41
- 2. User Authentication (login with `isLoggedinUser = true`)
42
- 3. Verify Other User (with `isLoggedinUser = false`)
43
- 4. Generate `externalGroupId` (GUID for fast room lookup)
44
- 5. Start Conversations (direct + product-based with metadata)
45
- 6. Using Ready-Made UI Components (ConversationList + ChatWindow)
46
- 7. Sending Messages
47
- 8. File Uploads
48
- 9. Unread Message Counts
49
- 10. Block & Unblock Users
50
- 11. Real-Time Events
51
- 12. Theme Support
52
- 13. Internationalization (i18n)
53
- 14. Logout & Cleanup
54
- 15. Troubleshooting
68
+ Initialize the SDK once in your app, before any authentication or chat operations.
55
69
 
56
- ## Peer Dependencies
70
+ ```tsx
71
+ import { ChatSDK } from '@traiyani/chatsdk-react';
57
72
 
58
- | Package | Version |
59
- |---------|---------|
60
- | `react` | >= 16.8.0 |
61
- | `react-dom` | >= 16.8.0 |
62
- | `axios` | >= 0.21.0 |
63
- | `socket.io-client` | >= 4.0.0 |
73
+ const sdk = ChatSDK.getInstance();
64
74
 
65
- ## What's Inside the Package
75
+ await sdk.init({
76
+ apiBaseUrl: 'https://your-chat-api.com/api', // Your Mzad Chat API URL
77
+ appId: 'your-app-id', // Your application ID
78
+ environment: 'production', // 'development' | 'staging' | 'production'
79
+ enableLogging: true, // Enable console logs (set false in production)
80
+ autoConnect: true, // Auto-connect WebSocket after auth
81
+ });
82
+ ```
66
83
 
84
+ ### Configuration Options
85
+
86
+ ```typescript
87
+ interface ChatSDKConfig {
88
+ apiBaseUrl: string; // Required - API server URL
89
+ appId: string; // Required - Your application ID
90
+ environment: 'development' | 'staging' | 'production'; // Required
91
+ wsUrl?: string; // WebSocket URL (defaults to apiBaseUrl)
92
+ apiKey?: string; // API key (if required by server)
93
+ enableLogging?: boolean; // Enable debug logging (default: false)
94
+ autoConnect?: boolean; // Auto-connect WebSocket (default: true)
95
+ timeout?: number; // HTTP request timeout in ms (default: 30000)
96
+ }
67
97
  ```
68
- dist/
69
- chatsdk-react.mjs – ES module build
70
- chatsdk-react.cjs – CommonJS build
71
- chatsdk.css – single merged stylesheet
72
- index.d.ts – TypeScript declarations
73
- *.map – source maps
98
+
99
+ ### Environment Variables
100
+
101
+ Config values can come from any source:
102
+
103
+ ```tsx
104
+ // Create React App
105
+ await sdk.init({ apiBaseUrl: process.env.REACT_APP_API_URL, appId: process.env.REACT_APP_APP_ID, ... });
106
+
107
+ // Vite
108
+ await sdk.init({ apiBaseUrl: import.meta.env.VITE_API_URL, appId: import.meta.env.VITE_APP_ID, ... });
109
+
110
+ // Next.js
111
+ await sdk.init({ apiBaseUrl: process.env.NEXT_PUBLIC_API_URL, appId: process.env.NEXT_PUBLIC_APP_ID, ... });
74
112
  ```
75
113
 
76
- ## License
114
+ ---
77
115
 
78
- MIT
116
+ ## 3. User Authentication
117
+
118
+ The SDK uses the `chatUsers.authenticate()` method which tries login first and falls back to registration automatically.
119
+
120
+ ### 3.1 Login the Current User (`isLoggedinUser = true`)
121
+
122
+ Use `isLoggedinUser = true` when the user is the **currently logged-in user** of your app. This saves the auth token so the SDK can make API calls on behalf of this user.
123
+
124
+ ```tsx
125
+ const sdk = ChatSDK.getInstance();
126
+
127
+ // Authenticate the current logged-in user
128
+ const currentUser = await sdk.chatUsers.authenticate(
129
+ 'external-user-123', // Your app's user ID
130
+ 'your-app-id', // App ID (must match sdk.init)
131
+ 'John Doe', // Display name
132
+ 'john@example.com', // Email
133
+ true // isLoggedinUser = true → saves token
134
+ );
135
+
136
+ // Connect WebSocket for real-time messaging
137
+ await sdk.connect(currentUser.id);
138
+
139
+ console.log('Logged in:', currentUser.name);
140
+ ```
141
+
142
+ **What happens under the hood:**
143
+ 1. Tries to **login** the user (if already registered in chat system)
144
+ 2. If login fails, **registers** the user automatically
145
+ 3. Saves the auth token to localStorage (because `isLoggedinUser = true`)
146
+ 4. All subsequent API calls use this token
147
+
148
+ ### 3.2 Verify Another User's Existence (`isLoggedinUser = false`)
149
+
150
+ Use `isLoggedinUser = false` when you need to verify or register **another user** (e.g., a seller, the other participant) without switching the current session. This does NOT save the token.
151
+
152
+ ```tsx
153
+ // Verify/register the other user (seller) without switching sessions
154
+ const otherUser = await sdk.chatUsers.authenticate(
155
+ 'seller-456', // The other user's external ID
156
+ 'your-app-id', // App ID
157
+ 'Jane Smith', // Their display name
158
+ 'jane@example.com', // Their email
159
+ false // isLoggedinUser = false → does NOT save token
160
+ );
161
+
162
+ console.log('Other user verified:', otherUser.name, otherUser.id);
163
+ // Now you can use otherUser.id to start a chat
164
+ ```
165
+
166
+ **Why this matters:** Before starting a chat with another user, you must ensure they exist in the chat system. Calling `authenticate` with `isLoggedinUser = false` creates or verifies the user without disrupting your current session.
167
+
168
+ ### 3.3 Check Login Status
169
+
170
+ ```tsx
171
+ const isLoggedIn = sdk.chatUsers.isAuthenticated();
172
+ const currentUser = sdk.getCurrentUser();
173
+ ```
174
+
175
+ ---
176
+
177
+ ## 4. Start a New Conversation
178
+
179
+ ### 4.1 Understanding `externalGroupId` (Required)
180
+
181
+ All `startChat` methods require an `externalGroupId`. This is a unique identifier your app generates to enable fast room lookup (98% faster) and prevent duplicate conversations.
182
+
183
+ **How to generate it:**
184
+
185
+ ```tsx
186
+ async function generateExternalGroupId(userId1, userId2, productId) {
187
+ const sorted = [userId1, userId2].sort();
188
+ const base = productId
189
+ ? `${sorted[0]}_${sorted[1]}_product_${productId}`
190
+ : `${sorted[0]}_${sorted[1]}`;
191
+
192
+ return await hashString(base);
193
+ }
194
+
195
+ async function hashString(input) {
196
+ if (typeof crypto !== 'undefined' && crypto.subtle) {
197
+ const data = new TextEncoder().encode(input);
198
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
199
+ return Array.from(new Uint8Array(hashBuffer))
200
+ .map(b => b.toString(16).padStart(2, '0')).join('');
201
+ }
202
+ // Fallback for non-HTTPS environments (e.g. http://localhost)
203
+ let hash = 0x811c9dc5;
204
+ for (let i = 0; i < input.length; i++) {
205
+ hash ^= input.charCodeAt(i);
206
+ hash = (hash * 0x01000193) >>> 0;
207
+ }
208
+ return hash.toString(16).padStart(8, '0');
209
+ }
210
+ ```
211
+
212
+ **Usage:**
213
+
214
+ ```tsx
215
+ const currentUserId = sdk.getCurrentUser().id;
216
+ const externalGroupId = await generateExternalGroupId(currentUserId, otherUser.id, 'PRODUCT_123');
217
+ ```
218
+
219
+ ### 4.2 Simple Direct Chat
220
+
221
+ ```tsx
222
+ const conversation = await sdk.chatUsers.startChat(
223
+ externalGroupId, // Generated GUID
224
+ otherUser.id // The other participant's chat user ID
225
+ );
226
+
227
+ console.log('Chat started:', conversation.id);
228
+ ```
229
+
230
+ ### 4.3 Chat with Product Context & Metadata
231
+
232
+ ```tsx
233
+ // Create product context
234
+ const productContext = {
235
+ productId: 'CAR_456',
236
+ productName: 'Toyota Camry 2023',
237
+ productImage: 'https://example.com/car.jpg',
238
+ price: 25000,
239
+ currency: 'QAR',
240
+ category: 'Vehicles',
241
+ productMetadata: {
242
+ mileage: '50000',
243
+ transmission: 'Automatic',
244
+ year: '2023',
245
+ },
246
+ };
247
+
248
+ // Optional: custom chat metadata
249
+ const chatMetadata = {
250
+ dealType: 'sale',
251
+ negotiable: true,
252
+ priority: 'high',
253
+ source: 'featured_listing',
254
+ };
255
+
256
+ // Start product chat
257
+ const conversation = await sdk.chatUsers.startChatWithProduct(
258
+ externalGroupId, // Generated GUID (include productId in generation)
259
+ otherUser.id, // Seller's chat user ID
260
+ productContext, // Product information
261
+ chatMetadata // Optional chat metadata
262
+ );
263
+
264
+ console.log('Product chat started:', conversation.id);
265
+ ```
266
+
267
+ ### 4.4 Complete Flow: Login → Verify Seller → Start Product Chat
268
+
269
+ ```tsx
270
+ import { ChatSDK } from '@traiyani/chatsdk-react';
271
+
272
+ const sdk = ChatSDK.getInstance();
273
+
274
+ // Step 1: Initialize SDK
275
+ await sdk.init({
276
+ apiBaseUrl: 'https://your-chat-api.com/api',
277
+ appId: 'your-app-id',
278
+ environment: 'production',
279
+ });
280
+
281
+ // Step 2: Login the current user (buyer)
282
+ const currentUser = await sdk.chatUsers.authenticate(
283
+ 'buyer-external-id',
284
+ 'your-app-id',
285
+ 'Ahmed',
286
+ 'ahmed@example.com',
287
+ true // isLoggedinUser = true → this is the logged-in user
288
+ );
289
+ await sdk.connect(currentUser.id);
290
+
291
+ // Step 3: Verify/register the other user (seller) — does NOT switch session
292
+ const seller = await sdk.chatUsers.authenticate(
293
+ 'seller-external-id',
294
+ 'your-app-id',
295
+ 'Mohammed',
296
+ 'mohammed@example.com',
297
+ false // isLoggedinUser = false → just verify existence
298
+ );
299
+
300
+ // Step 4: Generate externalGroupId
301
+ const externalGroupId = await generateExternalGroupId(
302
+ currentUser.id,
303
+ seller.id,
304
+ 'PRODUCT_789'
305
+ );
306
+
307
+ // Step 5: Start chat with product
308
+ const conversation = await sdk.chatUsers.startChatWithProduct(
309
+ externalGroupId,
310
+ seller.id,
311
+ {
312
+ productId: 'PRODUCT_789',
313
+ productName: 'iPhone 15 Pro',
314
+ productImage: 'https://example.com/iphone.jpg',
315
+ price: 4999,
316
+ currency: 'QAR',
317
+ category: 'Electronics',
318
+ }
319
+ );
320
+
321
+ // Step 6: Now show ChatWindow component with this conversation
322
+ ```
323
+
324
+ ---
325
+
326
+ ## 5. Using Ready-Made UI Components
327
+
328
+ The SDK includes two ready-made React components with full functionality.
329
+
330
+ ### 5.1 Conversation List
331
+
332
+ Displays all conversations with last message preview, unread badges, product context, and real-time updates.
333
+
334
+ ```tsx
335
+ import { ConversationList } from '@traiyani/chatsdk-react';
336
+
337
+ <ConversationList
338
+ currentUser={currentUser}
339
+ onSelectConversation={(conversation) => setSelectedConversation(conversation)}
340
+ selectedConversationId={selectedConversation?.id}
341
+ />
342
+ ```
343
+
344
+ **Props:**
345
+
346
+ ```typescript
347
+ interface ConversationListProps {
348
+ currentUser: ChatSDKUser; // Required - authenticated user
349
+ onSelectConversation: (conv: Conversation) => void; // Required - selection callback
350
+ selectedConversationId?: string; // Highlights active conversation
351
+ }
352
+ ```
353
+
354
+ ### 5.2 Chat Window
355
+
356
+ Full chat interface with messaging, file uploads, typing indicators, message status, block/unblock, and product context bar.
357
+
358
+ ```tsx
359
+ import { ChatWindow } from '@traiyani/chatsdk-react';
360
+
361
+ <ChatWindow
362
+ conversation={selectedConversation}
363
+ currentUser={currentUser}
364
+ onClose={() => setSelectedConversation(null)}
365
+ onBack={() => setSelectedConversation(null)}
366
+ />
367
+ ```
368
+
369
+ **Props:**
370
+
371
+ ```typescript
372
+ interface ChatWindowProps {
373
+ conversation: Conversation | null; // Required - active conversation
374
+ currentUser: ChatSDKUser; // Required - authenticated user
375
+ onClose?: () => void; // Called when close button pressed
376
+ onBack?: () => void; // Called when back button pressed (mobile)
377
+ }
378
+ ```
379
+
380
+ ### 5.3 Complete App Example
381
+
382
+ ```tsx
383
+ import React, { useState, useEffect } from 'react';
384
+ import { ChatSDK, ConversationList, ChatWindow } from '@traiyani/chatsdk-react';
385
+ import '@traiyani/chatsdk-react/dist/chatsdk.css';
386
+
387
+ function ChatApp() {
388
+ const [currentUser, setCurrentUser] = useState(null);
389
+ const [selectedConversation, setSelectedConversation] = useState(null);
390
+
391
+ useEffect(() => {
392
+ const init = async () => {
393
+ const sdk = ChatSDK.getInstance();
394
+ await sdk.init({
395
+ apiBaseUrl: process.env.REACT_APP_API_URL,
396
+ appId: process.env.REACT_APP_APP_ID,
397
+ environment: 'production',
398
+ });
399
+
400
+ const user = await sdk.chatUsers.authenticate(
401
+ 'user-123', 'your-app-id', 'John Doe', 'john@example.com', true
402
+ );
403
+ await sdk.connect(user.id);
404
+ setCurrentUser(user);
405
+ };
406
+ init();
407
+ }, []);
408
+
409
+ if (!currentUser) return <div>Loading...</div>;
410
+
411
+ return (
412
+ <div style={{ display: 'flex', height: '100vh' }}>
413
+ <div style={{ width: '350px', borderRight: '1px solid #e0e0e0' }}>
414
+ <ConversationList
415
+ currentUser={currentUser}
416
+ onSelectConversation={setSelectedConversation}
417
+ selectedConversationId={selectedConversation?.id}
418
+ />
419
+ </div>
420
+ <div style={{ flex: 1 }}>
421
+ {selectedConversation ? (
422
+ <ChatWindow
423
+ conversation={selectedConversation}
424
+ currentUser={currentUser}
425
+ onClose={() => setSelectedConversation(null)}
426
+ onBack={() => setSelectedConversation(null)}
427
+ />
428
+ ) : (
429
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
430
+ Select a conversation
431
+ </div>
432
+ )}
433
+ </div>
434
+ </div>
435
+ );
436
+ }
437
+ ```
438
+
439
+ ---
440
+
441
+ ## 6. Sending Messages
442
+
443
+ ### Send a Text Message
79
444
 
80
- ## Support
445
+ ```tsx
446
+ const sdk = ChatSDK.getInstance();
447
+
448
+ const message = await sdk.messages.sendMessage(
449
+ conversationId,
450
+ 'Hello! Is this still available?'
451
+ );
452
+
453
+ console.log('Message sent:', message.id);
454
+ ```
455
+
456
+ ### Send with Metadata
457
+
458
+ ```tsx
459
+ const message = await sdk.messages.sendMessageWithOptions({
460
+ conversationId: conversationId,
461
+ content: 'Here is my offer',
462
+ type: 'text',
463
+ metadata: { offerAmount: 4500, currency: 'QAR' },
464
+ });
465
+ ```
466
+
467
+ ### Load Messages (with Pagination)
468
+
469
+ ```tsx
470
+ const messages = await sdk.messages.getMessages({
471
+ conversationId: conversationId,
472
+ limit: 50,
473
+ offset: 0,
474
+ });
475
+
476
+ messages.forEach(msg => {
477
+ console.log(`${msg.senderName}: ${msg.content}`);
478
+ });
479
+ ```
480
+
481
+ ### Send Typing Indicator
482
+
483
+ ```tsx
484
+ // User started typing
485
+ await sdk.messages.sendTypingIndicator(conversationId, true);
486
+
487
+ // User stopped typing
488
+ await sdk.messages.sendTypingIndicator(conversationId, false);
489
+ ```
490
+
491
+ ### Mark Messages as Read
492
+
493
+ ```tsx
494
+ // Mark all messages in a conversation as read
495
+ await sdk.chatUsers.markRoomMessagesRead(conversationId);
496
+
497
+ // Mark a specific message as read
498
+ await sdk.chatUsers.markMessageRead(messageId);
499
+ ```
500
+
501
+ ---
502
+
503
+ ## 7. File Uploads & Attachments
504
+
505
+ ### Upload and Send a File
506
+
507
+ ```tsx
508
+ const sdk = ChatSDK.getInstance();
509
+
510
+ const result = await sdk.media.uploadMedia({
511
+ file: selectedFile, // File object from input
512
+ type: 'image', // 'image' | 'video' | 'audio' | 'document'
513
+ conversationId: conversationId,
514
+ caption: 'Check this out',
515
+ onProgress: (progress) => {
516
+ console.log(`Upload: ${progress}%`);
517
+ },
518
+ });
519
+
520
+ console.log('Uploaded:', result.fileUrl);
521
+ ```
522
+
523
+ ### Convenience Methods
524
+
525
+ ```tsx
526
+ // Send image
527
+ await sdk.media.sendImage(conversationId, imageFile, 'Photo caption');
528
+
529
+ // Send video
530
+ await sdk.media.sendVideo(conversationId, videoFile);
531
+
532
+ // Send document (PDF, DOC, etc.)
533
+ await sdk.media.sendDocument(conversationId, pdfFile);
534
+
535
+ // Send audio
536
+ await sdk.media.sendAudio(conversationId, audioFile);
537
+ ```
538
+
539
+ **Supported file types:** Images (`.jpg`, `.png`, `.gif`, `.webp`), Videos (`.mp4`, `.mov`), Documents (`.pdf`, `.doc`, `.docx`), Audio (`.mp3`, `.wav`)
540
+
541
+ **Note:** The built-in `<ChatWindow />` component handles file picking, uploading, and preview automatically.
542
+
543
+ ---
544
+
545
+ ## 8. Unread Message Counts
546
+
547
+ ### Get Unread Conversations Count
548
+
549
+ ```tsx
550
+ const count = await sdk.chatUsers.getUnreadConversationsCount();
551
+ console.log(`${count} conversations with unread messages`);
552
+ ```
553
+
554
+ ### Get Total Unread Message Count
555
+
556
+ ```tsx
557
+ const total = await sdk.chatUsers.getTotalUnreadCount();
558
+ console.log(`${total} total unread messages`);
559
+ ```
560
+
561
+ ### Get Detailed Unread Summary
562
+
563
+ ```tsx
564
+ const summary = await sdk.chatUsers.getUnreadSummary();
565
+ console.log('Total unread conversations:', summary.totalConversationsWithUnread);
566
+ console.log('Total unread messages:', summary.totalUnreadMessages);
567
+
568
+ summary.unreadSummary.forEach(item => {
569
+ console.log(`${item.room_name}: ${item.unread_count} unread`);
570
+ });
571
+ ```
572
+
573
+ ### Auto-Mark as Read
574
+
575
+ ```tsx
576
+ // When user opens a conversation
577
+ sdk.chatUsers.startViewingConversation(conversationId);
81
578
 
82
- - Documentation: [DOCUMENTATION.md](./DOCUMENTATION.md)
579
+ // When user leaves the conversation
580
+ sdk.chatUsers.stopViewingConversation(conversationId);
581
+ ```
582
+
583
+ ---
584
+
585
+ ## 9. Block & Unblock Users
586
+
587
+ ```tsx
588
+ await sdk.users.blockUser(userIdToBlock);
589
+ await sdk.users.unblockUser(userIdToUnblock);
590
+ const blockedUsers = await sdk.users.getBlockedUsers();
591
+ ```
592
+
593
+ **Notes:**
594
+ - Blocking is per-conversation, not global
595
+ - Blocked users cannot send messages in that conversation
596
+ - The built-in `<ChatWindow />` has a block/unblock UI built in
597
+
598
+ ---
599
+
600
+ ## 10. Real-Time Events
601
+
602
+ ### Listen for Events
603
+
604
+ ```tsx
605
+ const sdk = ChatSDK.getInstance();
606
+
607
+ sdk.socket.on('message_received', (data) => {
608
+ console.log('New message:', data.message.content);
609
+ });
610
+
611
+ sdk.socket.on('typing_indicator', (data) => {
612
+ console.log(data.isTyping ? 'User is typing...' : 'User stopped typing');
613
+ });
614
+
615
+ sdk.socket.on('user_status_changed', (data) => {
616
+ console.log('User status:', data.status);
617
+ });
618
+
619
+ sdk.socket.on('connection_status', (status) => {
620
+ console.log('WebSocket:', status);
621
+ });
622
+ ```
623
+
624
+ ### Available Event Types
625
+
626
+ | Event | Description |
627
+ |-------|-------------|
628
+ | `message_received` | New message arrived |
629
+ | `typing_indicator` | User started/stopped typing |
630
+ | `user_status_changed` | User online/offline status changed |
631
+ | `conversation_updated` | Conversation metadata changed |
632
+ | `connection_status` | WebSocket connected/disconnected/error |
633
+
634
+ ### Socket Direct Operations
635
+
636
+ ```tsx
637
+ sdk.socket.joinConversation(conversationId);
638
+ sdk.socket.leaveConversation(conversationId);
639
+ sdk.socket.sendTypingIndicator(conversationId, true);
640
+ const isConnected = sdk.socket.isConnected();
641
+ ```
642
+
643
+ ---
644
+
645
+ ## 11. Theme Support
646
+
647
+ ```tsx
648
+ import { ThemeProvider, ThemeToggle, useTheme } from '@traiyani/chatsdk-react';
649
+
650
+ // Option 1: ThemeProvider + ThemeToggle
651
+ function App() {
652
+ return (
653
+ <ThemeProvider>
654
+ <ThemeToggle showLabel />
655
+ </ThemeProvider>
656
+ );
657
+ }
658
+
659
+ // Option 2: useTheme hook
660
+ function MyComponent() {
661
+ const { theme, actualTheme, setTheme, toggleTheme } = useTheme();
662
+ return <button onClick={toggleTheme}>Current: {actualTheme}</button>;
663
+ }
664
+
665
+ // Option 3: Imperative
666
+ import { initializeTheme } from '@traiyani/chatsdk-react';
667
+ initializeTheme();
668
+ ```
669
+
670
+ ---
671
+
672
+ ## 12. Internationalization (i18n)
673
+
674
+ Supported languages: **English** (`en`), **Arabic** (`ar` with RTL)
675
+
676
+ ```tsx
677
+ import { changeLanguage, getCurrentLanguage, isRTL, t } from '@traiyani/chatsdk-react';
678
+
679
+ const title = t('conversations_title');
680
+ changeLanguage('ar'); // Switches to Arabic + sets RTL
681
+ const lang = getCurrentLanguage(); // 'en' or 'ar'
682
+ const rtl = isRTL(); // true if Arabic
683
+ ```
684
+
685
+ ---
686
+
687
+ ## 13. Logout & Cleanup
688
+
689
+ ```tsx
690
+ const sdk = ChatSDK.getInstance();
691
+
692
+ // Disconnect WebSocket
693
+ sdk.socket.disconnect();
694
+
695
+ // Logout (clears token)
696
+ await sdk.chatUsers.logout();
697
+ ```
698
+
699
+ ---
700
+
701
+ ## 14. TypeScript Support
702
+
703
+ Full type declarations are included. No extra `@types/*` packages needed.
704
+
705
+ ```tsx
706
+ import type {
707
+ ChatSDKConfig, ChatSDKUser, ChatSDKMessage, ChatSDKConversation,
708
+ ProductContext, Product, ChatState, ChatWindowProps, ConversationListProps,
709
+ SendMessageOptions, MediaUploadOptions, MediaUploadResult,
710
+ CreateConversationOptions, EventCallback,
711
+ } from '@traiyani/chatsdk-react';
712
+ ```
713
+
714
+ ---
715
+
716
+ ## 15. Troubleshooting
717
+
718
+ | Problem | Solution |
719
+ |---------|----------|
720
+ | WebSocket not connecting | Ensure `autoConnect: true` in config, verify API URL is reachable, check CORS |
721
+ | Messages not loading | Ensure user is authenticated first, verify `conversationId` is valid |
722
+ | CSS not applying | Ensure `import '@traiyani/chatsdk-react/dist/chatsdk.css'` is in your entry file |
723
+ | Authentication fails | Verify `apiBaseUrl` and `appId`, check browser console, ensure CORS is configured |
724
+ | "SDK not initialized" | Ensure `await sdk.init()` is called before any other SDK method |
725
+
726
+ ## License
727
+
728
+ MIT