@traiyani/chatsdk-react 1.0.2 → 1.0.3

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.
Files changed (2) hide show
  1. package/README.md +674 -40
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -16,67 +16,701 @@ 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
+ const encoder = new TextEncoder();
193
+ const data = encoder.encode(base);
194
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
195
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
196
+ return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
197
+ }
198
+ ```
199
+
200
+ **Usage:**
201
+
202
+ ```tsx
203
+ const currentUserId = sdk.getCurrentUser().id;
204
+ const externalGroupId = await generateExternalGroupId(currentUserId, otherUser.id, 'PRODUCT_123');
205
+ ```
79
206
 
80
- ## Support
207
+ ### 4.2 Simple Direct Chat
208
+
209
+ ```tsx
210
+ const conversation = await sdk.chatUsers.startChat(
211
+ externalGroupId, // Generated GUID
212
+ otherUser.id // The other participant's chat user ID
213
+ );
214
+
215
+ console.log('Chat started:', conversation.id);
216
+ ```
217
+
218
+ ### 4.3 Chat with Product Context & Metadata
219
+
220
+ ```tsx
221
+ // Create product context
222
+ const productContext = {
223
+ productId: 'CAR_456',
224
+ productName: 'Toyota Camry 2023',
225
+ productImage: 'https://example.com/car.jpg',
226
+ price: 25000,
227
+ currency: 'QAR',
228
+ category: 'Vehicles',
229
+ productMetadata: {
230
+ mileage: '50000',
231
+ transmission: 'Automatic',
232
+ year: '2023',
233
+ },
234
+ };
235
+
236
+ // Optional: custom chat metadata
237
+ const chatMetadata = {
238
+ dealType: 'sale',
239
+ negotiable: true,
240
+ priority: 'high',
241
+ source: 'featured_listing',
242
+ };
243
+
244
+ // Start product chat
245
+ const conversation = await sdk.chatUsers.startChatWithProduct(
246
+ externalGroupId, // Generated GUID (include productId in generation)
247
+ otherUser.id, // Seller's chat user ID
248
+ productContext, // Product information
249
+ chatMetadata // Optional chat metadata
250
+ );
251
+
252
+ console.log('Product chat started:', conversation.id);
253
+ ```
254
+
255
+ ### 4.4 Complete Flow: Login → Verify Seller → Start Product Chat
256
+
257
+ ```tsx
258
+ import { ChatSDK } from '@traiyani/chatsdk-react';
259
+
260
+ const sdk = ChatSDK.getInstance();
261
+
262
+ // Step 1: Initialize SDK
263
+ await sdk.init({
264
+ apiBaseUrl: 'https://your-chat-api.com/api',
265
+ appId: 'your-app-id',
266
+ environment: 'production',
267
+ });
268
+
269
+ // Step 2: Login the current user (buyer)
270
+ const currentUser = await sdk.chatUsers.authenticate(
271
+ 'buyer-external-id',
272
+ 'your-app-id',
273
+ 'Ahmed',
274
+ 'ahmed@example.com',
275
+ true // isLoggedinUser = true → this is the logged-in user
276
+ );
277
+ await sdk.connect(currentUser.id);
278
+
279
+ // Step 3: Verify/register the other user (seller) — does NOT switch session
280
+ const seller = await sdk.chatUsers.authenticate(
281
+ 'seller-external-id',
282
+ 'your-app-id',
283
+ 'Mohammed',
284
+ 'mohammed@example.com',
285
+ false // isLoggedinUser = false → just verify existence
286
+ );
287
+
288
+ // Step 4: Generate externalGroupId
289
+ const externalGroupId = await generateExternalGroupId(
290
+ currentUser.id,
291
+ seller.id,
292
+ 'PRODUCT_789'
293
+ );
294
+
295
+ // Step 5: Start chat with product
296
+ const conversation = await sdk.chatUsers.startChatWithProduct(
297
+ externalGroupId,
298
+ seller.id,
299
+ {
300
+ productId: 'PRODUCT_789',
301
+ productName: 'iPhone 15 Pro',
302
+ productImage: 'https://example.com/iphone.jpg',
303
+ price: 4999,
304
+ currency: 'QAR',
305
+ category: 'Electronics',
306
+ }
307
+ );
308
+
309
+ // Step 6: Now show ChatWindow component with this conversation
310
+ ```
311
+
312
+ ---
313
+
314
+ ## 5. Using Ready-Made UI Components
315
+
316
+ The SDK includes two ready-made React components with full functionality.
317
+
318
+ ### 5.1 Conversation List
319
+
320
+ Displays all conversations with last message preview, unread badges, product context, and real-time updates.
321
+
322
+ ```tsx
323
+ import { ConversationList } from '@traiyani/chatsdk-react';
324
+
325
+ <ConversationList
326
+ currentUser={currentUser}
327
+ onSelectConversation={(conversation) => setSelectedConversation(conversation)}
328
+ selectedConversationId={selectedConversation?.id}
329
+ />
330
+ ```
331
+
332
+ **Props:**
333
+
334
+ ```typescript
335
+ interface ConversationListProps {
336
+ currentUser: ChatSDKUser; // Required - authenticated user
337
+ onSelectConversation: (conv: Conversation) => void; // Required - selection callback
338
+ selectedConversationId?: string; // Highlights active conversation
339
+ }
340
+ ```
341
+
342
+ ### 5.2 Chat Window
343
+
344
+ Full chat interface with messaging, file uploads, typing indicators, message status, block/unblock, and product context bar.
345
+
346
+ ```tsx
347
+ import { ChatWindow } from '@traiyani/chatsdk-react';
348
+
349
+ <ChatWindow
350
+ conversation={selectedConversation}
351
+ currentUser={currentUser}
352
+ onClose={() => setSelectedConversation(null)}
353
+ onBack={() => setSelectedConversation(null)}
354
+ />
355
+ ```
356
+
357
+ **Props:**
358
+
359
+ ```typescript
360
+ interface ChatWindowProps {
361
+ conversation: Conversation | null; // Required - active conversation
362
+ currentUser: ChatSDKUser; // Required - authenticated user
363
+ onClose?: () => void; // Called when close button pressed
364
+ onBack?: () => void; // Called when back button pressed (mobile)
365
+ }
366
+ ```
367
+
368
+ ### 5.3 Complete App Example
369
+
370
+ ```tsx
371
+ import React, { useState, useEffect } from 'react';
372
+ import { ChatSDK, ConversationList, ChatWindow } from '@traiyani/chatsdk-react';
373
+ import '@traiyani/chatsdk-react/dist/chatsdk.css';
374
+
375
+ function ChatApp() {
376
+ const [currentUser, setCurrentUser] = useState(null);
377
+ const [selectedConversation, setSelectedConversation] = useState(null);
378
+
379
+ useEffect(() => {
380
+ const init = async () => {
381
+ const sdk = ChatSDK.getInstance();
382
+ await sdk.init({
383
+ apiBaseUrl: process.env.REACT_APP_API_URL,
384
+ appId: process.env.REACT_APP_APP_ID,
385
+ environment: 'production',
386
+ });
387
+
388
+ const user = await sdk.chatUsers.authenticate(
389
+ 'user-123', 'your-app-id', 'John Doe', 'john@example.com', true
390
+ );
391
+ await sdk.connect(user.id);
392
+ setCurrentUser(user);
393
+ };
394
+ init();
395
+ }, []);
396
+
397
+ if (!currentUser) return <div>Loading...</div>;
398
+
399
+ return (
400
+ <div style={{ display: 'flex', height: '100vh' }}>
401
+ <div style={{ width: '350px', borderRight: '1px solid #e0e0e0' }}>
402
+ <ConversationList
403
+ currentUser={currentUser}
404
+ onSelectConversation={setSelectedConversation}
405
+ selectedConversationId={selectedConversation?.id}
406
+ />
407
+ </div>
408
+ <div style={{ flex: 1 }}>
409
+ {selectedConversation ? (
410
+ <ChatWindow
411
+ conversation={selectedConversation}
412
+ currentUser={currentUser}
413
+ onClose={() => setSelectedConversation(null)}
414
+ onBack={() => setSelectedConversation(null)}
415
+ />
416
+ ) : (
417
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
418
+ Select a conversation
419
+ </div>
420
+ )}
421
+ </div>
422
+ </div>
423
+ );
424
+ }
425
+ ```
426
+
427
+ ---
428
+
429
+ ## 6. Sending Messages
430
+
431
+ ### Send a Text Message
432
+
433
+ ```tsx
434
+ const sdk = ChatSDK.getInstance();
81
435
 
82
- - Documentation: [DOCUMENTATION.md](./DOCUMENTATION.md)
436
+ const message = await sdk.messages.sendMessage(
437
+ conversationId,
438
+ 'Hello! Is this still available?'
439
+ );
440
+
441
+ console.log('Message sent:', message.id);
442
+ ```
443
+
444
+ ### Send with Metadata
445
+
446
+ ```tsx
447
+ const message = await sdk.messages.sendMessageWithOptions({
448
+ conversationId: conversationId,
449
+ content: 'Here is my offer',
450
+ type: 'text',
451
+ metadata: { offerAmount: 4500, currency: 'QAR' },
452
+ });
453
+ ```
454
+
455
+ ### Load Messages (with Pagination)
456
+
457
+ ```tsx
458
+ const messages = await sdk.messages.getMessages({
459
+ conversationId: conversationId,
460
+ limit: 50,
461
+ offset: 0,
462
+ });
463
+
464
+ messages.forEach(msg => {
465
+ console.log(`${msg.senderName}: ${msg.content}`);
466
+ });
467
+ ```
468
+
469
+ ### Send Typing Indicator
470
+
471
+ ```tsx
472
+ // User started typing
473
+ await sdk.messages.sendTypingIndicator(conversationId, true);
474
+
475
+ // User stopped typing
476
+ await sdk.messages.sendTypingIndicator(conversationId, false);
477
+ ```
478
+
479
+ ### Mark Messages as Read
480
+
481
+ ```tsx
482
+ // Mark all messages in a conversation as read
483
+ await sdk.chatUsers.markRoomMessagesRead(conversationId);
484
+
485
+ // Mark a specific message as read
486
+ await sdk.chatUsers.markMessageRead(messageId);
487
+ ```
488
+
489
+ ---
490
+
491
+ ## 7. File Uploads & Attachments
492
+
493
+ ### Upload and Send a File
494
+
495
+ ```tsx
496
+ const sdk = ChatSDK.getInstance();
497
+
498
+ const result = await sdk.media.uploadMedia({
499
+ file: selectedFile, // File object from input
500
+ type: 'image', // 'image' | 'video' | 'audio' | 'document'
501
+ conversationId: conversationId,
502
+ caption: 'Check this out',
503
+ onProgress: (progress) => {
504
+ console.log(`Upload: ${progress}%`);
505
+ },
506
+ });
507
+
508
+ console.log('Uploaded:', result.fileUrl);
509
+ ```
510
+
511
+ ### Convenience Methods
512
+
513
+ ```tsx
514
+ // Send image
515
+ await sdk.media.sendImage(conversationId, imageFile, 'Photo caption');
516
+
517
+ // Send video
518
+ await sdk.media.sendVideo(conversationId, videoFile);
519
+
520
+ // Send document (PDF, DOC, etc.)
521
+ await sdk.media.sendDocument(conversationId, pdfFile);
522
+
523
+ // Send audio
524
+ await sdk.media.sendAudio(conversationId, audioFile);
525
+ ```
526
+
527
+ **Supported file types:** Images (`.jpg`, `.png`, `.gif`, `.webp`), Videos (`.mp4`, `.mov`), Documents (`.pdf`, `.doc`, `.docx`), Audio (`.mp3`, `.wav`)
528
+
529
+ **Note:** The built-in `<ChatWindow />` component handles file picking, uploading, and preview automatically.
530
+
531
+ ---
532
+
533
+ ## 8. Unread Message Counts
534
+
535
+ ### Get Unread Conversations Count
536
+
537
+ ```tsx
538
+ const count = await sdk.chatUsers.getUnreadConversationsCount();
539
+ console.log(`${count} conversations with unread messages`);
540
+ ```
541
+
542
+ ### Get Total Unread Message Count
543
+
544
+ ```tsx
545
+ const total = await sdk.chatUsers.getTotalUnreadCount();
546
+ console.log(`${total} total unread messages`);
547
+ ```
548
+
549
+ ### Get Detailed Unread Summary
550
+
551
+ ```tsx
552
+ const summary = await sdk.chatUsers.getUnreadSummary();
553
+ console.log('Total unread conversations:', summary.totalConversationsWithUnread);
554
+ console.log('Total unread messages:', summary.totalUnreadMessages);
555
+
556
+ summary.unreadSummary.forEach(item => {
557
+ console.log(`${item.room_name}: ${item.unread_count} unread`);
558
+ });
559
+ ```
560
+
561
+ ### Auto-Mark as Read
562
+
563
+ ```tsx
564
+ // When user opens a conversation
565
+ sdk.chatUsers.startViewingConversation(conversationId);
566
+
567
+ // When user leaves the conversation
568
+ sdk.chatUsers.stopViewingConversation(conversationId);
569
+ ```
570
+
571
+ ---
572
+
573
+ ## 9. Block & Unblock Users
574
+
575
+ ```tsx
576
+ await sdk.users.blockUser(userIdToBlock);
577
+ await sdk.users.unblockUser(userIdToUnblock);
578
+ const blockedUsers = await sdk.users.getBlockedUsers();
579
+ ```
580
+
581
+ **Notes:**
582
+ - Blocking is per-conversation, not global
583
+ - Blocked users cannot send messages in that conversation
584
+ - The built-in `<ChatWindow />` has a block/unblock UI built in
585
+
586
+ ---
587
+
588
+ ## 10. Real-Time Events
589
+
590
+ ### Listen for Events
591
+
592
+ ```tsx
593
+ const sdk = ChatSDK.getInstance();
594
+
595
+ sdk.socket.on('message_received', (data) => {
596
+ console.log('New message:', data.message.content);
597
+ });
598
+
599
+ sdk.socket.on('typing_indicator', (data) => {
600
+ console.log(data.isTyping ? 'User is typing...' : 'User stopped typing');
601
+ });
602
+
603
+ sdk.socket.on('user_status_changed', (data) => {
604
+ console.log('User status:', data.status);
605
+ });
606
+
607
+ sdk.socket.on('connection_status', (status) => {
608
+ console.log('WebSocket:', status);
609
+ });
610
+ ```
611
+
612
+ ### Available Event Types
613
+
614
+ | Event | Description |
615
+ |-------|-------------|
616
+ | `message_received` | New message arrived |
617
+ | `typing_indicator` | User started/stopped typing |
618
+ | `user_status_changed` | User online/offline status changed |
619
+ | `conversation_updated` | Conversation metadata changed |
620
+ | `connection_status` | WebSocket connected/disconnected/error |
621
+
622
+ ### Socket Direct Operations
623
+
624
+ ```tsx
625
+ sdk.socket.joinConversation(conversationId);
626
+ sdk.socket.leaveConversation(conversationId);
627
+ sdk.socket.sendTypingIndicator(conversationId, true);
628
+ const isConnected = sdk.socket.isConnected();
629
+ ```
630
+
631
+ ---
632
+
633
+ ## 11. Theme Support
634
+
635
+ ```tsx
636
+ import { ThemeProvider, ThemeToggle, useTheme } from '@traiyani/chatsdk-react';
637
+
638
+ // Option 1: ThemeProvider + ThemeToggle
639
+ function App() {
640
+ return (
641
+ <ThemeProvider>
642
+ <ThemeToggle showLabel />
643
+ </ThemeProvider>
644
+ );
645
+ }
646
+
647
+ // Option 2: useTheme hook
648
+ function MyComponent() {
649
+ const { theme, actualTheme, setTheme, toggleTheme } = useTheme();
650
+ return <button onClick={toggleTheme}>Current: {actualTheme}</button>;
651
+ }
652
+
653
+ // Option 3: Imperative
654
+ import { initializeTheme } from '@traiyani/chatsdk-react';
655
+ initializeTheme();
656
+ ```
657
+
658
+ ---
659
+
660
+ ## 12. Internationalization (i18n)
661
+
662
+ Supported languages: **English** (`en`), **Arabic** (`ar` with RTL)
663
+
664
+ ```tsx
665
+ import { changeLanguage, getCurrentLanguage, isRTL, t } from '@traiyani/chatsdk-react';
666
+
667
+ const title = t('conversations_title');
668
+ changeLanguage('ar'); // Switches to Arabic + sets RTL
669
+ const lang = getCurrentLanguage(); // 'en' or 'ar'
670
+ const rtl = isRTL(); // true if Arabic
671
+ ```
672
+
673
+ ---
674
+
675
+ ## 13. Logout & Cleanup
676
+
677
+ ```tsx
678
+ const sdk = ChatSDK.getInstance();
679
+
680
+ // Disconnect WebSocket
681
+ sdk.socket.disconnect();
682
+
683
+ // Logout (clears token)
684
+ await sdk.chatUsers.logout();
685
+ ```
686
+
687
+ ---
688
+
689
+ ## 14. TypeScript Support
690
+
691
+ Full type declarations are included. No extra `@types/*` packages needed.
692
+
693
+ ```tsx
694
+ import type {
695
+ ChatSDKConfig, ChatSDKUser, ChatSDKMessage, ChatSDKConversation,
696
+ ProductContext, Product, ChatState, ChatWindowProps, ConversationListProps,
697
+ SendMessageOptions, MediaUploadOptions, MediaUploadResult,
698
+ CreateConversationOptions, EventCallback,
699
+ } from '@traiyani/chatsdk-react';
700
+ ```
701
+
702
+ ---
703
+
704
+ ## 15. Troubleshooting
705
+
706
+ | Problem | Solution |
707
+ |---------|----------|
708
+ | WebSocket not connecting | Ensure `autoConnect: true` in config, verify API URL is reachable, check CORS |
709
+ | Messages not loading | Ensure user is authenticated first, verify `conversationId` is valid |
710
+ | CSS not applying | Ensure `import '@traiyani/chatsdk-react/dist/chatsdk.css'` is in your entry file |
711
+ | Authentication fails | Verify `apiBaseUrl` and `appId`, check browser console, ensure CORS is configured |
712
+ | "SDK not initialized" | Ensure `await sdk.init()` is called before any other SDK method |
713
+
714
+ ## License
715
+
716
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@traiyani/chatsdk-react",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "ChatSDK React SDK - Pre-built, plug-and-play real-time chat components for React",
5
5
  "main": "dist/chatsdk-react.cjs",
6
6
  "module": "dist/chatsdk-react.mjs",