@data-netmonk/mona-chat-widget 2.2.0 → 2.3.0

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
@@ -2,6 +2,83 @@
2
2
 
3
3
  Chat widget package developed by Netmonk data & solution team to be imported in Netmonk products
4
4
 
5
+ ---
6
+
7
+ ### Recent Updates & Breaking Changes
8
+
9
+ ---
10
+
11
+ **Latest Version Changes:**
12
+
13
+ ⚠️ **Breaking Changes:**
14
+ 1. **Removed `type` and `agentType` props** - These parameters are no longer used and have been removed from all components
15
+ 2. **Renamed `botServerUrl` to `webhookUrl`** - For better clarity and consistency
16
+ 3. **`webhookUrl` is now required** - Must be provided as a prop
17
+ 4. **`authUrl` and `username` are now direct props** - No longer part of `data` prop for better clarity and type safety
18
+ 5. **`userId` is now optional** - Widget automatically generates visitor ID for guest users via browser fingerprinting when `userId` is not provided
19
+
20
+ ✨ **New Features:**
21
+ 1. **Guest user support** - Users can chat without logging in
22
+ - Automatic visitor ID generation using browser fingerprinting (FingerprintJS + SHA256)
23
+ - `auth: false` flag automatically added to API requests for guest users
24
+ - Persistent sessions across page reloads for anonymous visitors
25
+ 2. **Authentication support** - Automatic token management with refresh on 401 errors
26
+ - Pass `authUrl` as a direct prop
27
+ - Widget handles token lifecycle automatically
28
+ 3. **Enhanced user authentication handling** - Smart detection of authenticated vs guest users
29
+ - Compares `userId` with visitor ID to determine authentication status
30
+ - Automatic `auth` flag management in all API requests
31
+ 4. **Enhanced data prop** - Support for custom variables passed to backend via `data` prop
32
+ 5. **Improved error handling** - Better fallback mechanisms and error messages
33
+ 6. **Direct `username` prop** - Pass username as a top-level prop instead of in data string
34
+
35
+ 📝 **Migration Guide:**
36
+ ```jsx
37
+ // Old usage (deprecated)
38
+ <ChatWidget
39
+ userId="user123"
40
+ sourceId="source456"
41
+ type="prime"
42
+ botServerUrl="https://api.example.com"
43
+ />
44
+
45
+ // Previous version (with data prop)
46
+ <ChatWidget
47
+ userId="user123"
48
+ sourceId="source456"
49
+ webhookUrl="https://api.example.com/webhook"
50
+ data="authUrl=https://api.example.com/login/chatwidget~username=John"
51
+ />
52
+
53
+ // New usage - Authenticated user (current - recommended)
54
+ <ChatWidget
55
+ userId="user123"
56
+ sourceId="source456"
57
+ webhookUrl="https://api.example.com/webhook"
58
+ authUrl="https://api.example.com/login/chatwidget"
59
+ username="John"
60
+ data="email=john@example.com~phone=+1234567890"
61
+ />
62
+
63
+ // New usage - Guest user (without login)
64
+ <ChatWidget
65
+ sourceId="source456"
66
+ webhookUrl="https://api.example.com/webhook"
67
+ username="Guest"
68
+ />
69
+ // Widget automatically generates visitor ID and adds auth: false flag
70
+
71
+ // New usage - Conditional (handles both logged-in and guest users)
72
+ <ChatWidget
73
+ userId={currentUser?.id} // undefined for guests
74
+ sourceId="source456"
75
+ webhookUrl="https://api.example.com/webhook"
76
+ username={currentUser?.name || "Guest"}
77
+ />
78
+ ```
79
+
80
+ ---
81
+
5
82
  ## 🚅 Quick start
6
83
 
7
84
  ### Prerequisites
@@ -79,7 +156,7 @@ For responses with buttons:
79
156
 
80
157
  ---
81
158
 
82
- 1. **How to run Storybook locally** (access at http://localhost:6006)
159
+ 1. **How to run Storybook locally** (access at http://localhost:5177)
83
160
 
84
161
  ```
85
162
  npm run storybook
@@ -99,45 +176,6 @@ For responses with buttons:
99
176
 
100
177
  ---
101
178
 
102
- ### Recent Updates & Breaking Changes
103
-
104
- ---
105
-
106
- **Latest Version Changes:**
107
-
108
- ⚠️ **Breaking Changes:**
109
- 1. **Removed `type` and `agentType` props** - These parameters are no longer used and have been removed from all components
110
- 2. **Renamed `botServerUrl` to `webhookUrl`** - For better clarity and consistency
111
- 3. **`webhookUrl` is now required** - Must be provided as a prop (falls back to env vars if not provided)
112
-
113
- ✨ **New Features:**
114
- 1. **Authentication support** - Automatic token management with refresh on 401 errors
115
- - Pass `authUrl` in the `data` prop
116
- - Widget handles token lifecycle automatically
117
- 2. **Enhanced data prop** - Support for custom variables passed to backend via `data` prop
118
- 3. **Improved error handling** - Better fallback mechanisms and error messages
119
-
120
- 📝 **Migration Guide:**
121
- ```jsx
122
- // Old usage (deprecated)
123
- <ChatWidget
124
- userId="user123"
125
- sourceId="source456"
126
- type="prime"
127
- botServerUrl="https://api.example.com"
128
- />
129
-
130
- // New usage (current)
131
- <ChatWidget
132
- userId="user123"
133
- sourceId="source456"
134
- webhookUrl="https://api.example.com/webhook"
135
- data="authUrl=https://api.example.com/login/chatwidget~username=John"
136
- />
137
- ```
138
-
139
- ---
140
-
141
179
  ### Library (how to update and publish)
142
180
 
143
181
  ---
@@ -222,15 +260,17 @@ For responses with buttons:
222
260
 
223
261
  | Prop | Type | Description |
224
262
  |------|------|-------------|
225
- | `userId` | `string` | **Required.** Unique identifier for the user |
226
263
  | `sourceId` | `string` | **Required.** Source/channel identifier for the chat |
227
- | `webhookUrl` | `string` | **Required.** Backend webhook URL (falls back to env vars if not provided) |
264
+ | `webhookUrl` | `string` | **Required.** Backend webhook URL |
228
265
 
229
266
  #### Optional Props
230
267
 
231
268
  | Prop | Type | Default | Description |
232
269
  |------|------|---------|-------------|
233
- | `data` | `string` | - | Custom variables and auth URL in format `key1=value1~key2=value2~authUrl=https://...` |
270
+ | `userId` | `string` | Generated visitor ID | Unique identifier for the user. **Optional** - if not provided, a unique visitor ID is automatically generated using browser fingerprinting for guest users |
271
+ | `authUrl` | `string` | - | Authentication endpoint URL for token-based authentication |
272
+ | `username` | `string` | - | Username for the session (sent to backend in variables) |
273
+ | `data` | `string` | - | Additional custom variables in format `key1=value1~key2=value2` |
234
274
  | `width` | `string` | `"25vw"` | Widget width (CSS value) |
235
275
  | `height` | `string` | `"90vh"` | Widget height (CSS value) |
236
276
  | `right` | `string` | `"1.25rem"` | Distance from right edge |
@@ -241,11 +281,45 @@ For responses with buttons:
241
281
 
242
282
  ---
243
283
 
284
+ ### Guest User Support
285
+
286
+ ---
287
+
288
+ The widget now supports **guest users** (users who haven't logged in or before logging in). When `userId` is not provided, the widget automatically generates a unique visitor ID using browser fingerprinting.
289
+
290
+ **How it works:**
291
+
292
+ 1. **Browser Fingerprinting**: Uses FingerprintJS to generate a unique identifier based on:
293
+ - Browser characteristics (user agent, screen resolution, timezone, etc.)
294
+ - Incognito/private browsing detection
295
+ - Combined into a SHA256 hash for consistency
296
+
297
+ 2. **Automatic Guest Detection**: The widget automatically detects guest users and:
298
+ - Generates a visitor ID if `userId` is not provided
299
+ - Adds `auth: false` flag to all API requests for guest users
300
+ - Uses the visitor ID as the effective user ID throughout the session
301
+
302
+ 3. **Persistent Sessions**: The visitor ID remains consistent across page reloads (unless browser fingerprint changes or user clears data)
303
+
304
+ **When to use guest mode:**
305
+ - Public-facing websites where users can chat without logging in
306
+ - Support widgets for anonymous visitors
307
+ - Pre-login customer service interactions
308
+ - Any scenario where user authentication is optional
309
+
310
+ **When to provide userId:**
311
+ - Users who are logged into your application
312
+ - When you need to track chat history across devices
313
+ - When authentication is required for personalized responses
314
+ - Enterprise or internal applications
315
+
316
+ ---
317
+
244
318
  ### Usage Examples
245
319
 
246
320
  ---
247
321
 
248
- #### Basic Usage
322
+ #### Basic Usage (Authenticated User)
249
323
 
250
324
  ```jsx
251
325
  import { ChatWidget } from "@data-netmonk/mona-chat-widget";
@@ -262,16 +336,67 @@ function App() {
262
336
  }
263
337
  ```
264
338
 
339
+ #### Guest User (Without Login)
340
+
341
+ For anonymous visitors or users who haven't logged in:
342
+
343
+ ```jsx
344
+ import { ChatWidget } from "@data-netmonk/mona-chat-widget";
345
+ import "@data-netmonk/mona-chat-widget/dist/style.css";
346
+
347
+ function App() {
348
+ return (
349
+ <ChatWidget
350
+ sourceId="691e1b5952068ff7aaeccffc9"
351
+ webhookUrl="https://api.example.com/webhook"
352
+ />
353
+ );
354
+ }
355
+ ```
356
+
357
+ **What happens:**
358
+ - Widget automatically generates a visitor ID using browser fingerprinting
359
+ - All API requests include `auth: false` in variables to indicate guest user
360
+ - No login required - users can start chatting immediately
361
+
362
+ #### Conditional userId (Logged in or Guest)
363
+
364
+ Handle both logged-in users and guests dynamically:
365
+
366
+ ```jsx
367
+ import { ChatWidget } from "@data-netmonk/mona-chat-widget";
368
+ import "@data-netmonk/mona-chat-widget/dist/style.css";
369
+
370
+ function App() {
371
+ const currentUser = getCurrentUser(); // Your auth function
372
+
373
+ return (
374
+ <ChatWidget
375
+ userId={currentUser?.id} // Provide userId if logged in, undefined if not
376
+ sourceId="691e1b5952068ff7aaeccffc9"
377
+ webhookUrl="https://api.example.com/webhook"
378
+ username={currentUser?.name}
379
+ />
380
+ );
381
+ }
382
+ ```
383
+
384
+ **Behavior:**
385
+ - If `currentUser.id` exists → Uses provided userId (authenticated user)
386
+ - If `currentUser.id` is `null`/`undefined` → Generates visitor ID (guest user)
387
+ - Backend receives `auth: false` flag only for guest users
388
+
265
389
  #### With Custom Variables
266
390
 
267
- Pass custom user data like username, phone number, etc. to the backend:
391
+ Pass custom user data like email, phone number, etc. to the backend:
268
392
 
269
393
  ```jsx
270
394
  <ChatWidget
271
395
  userId="user123"
272
396
  sourceId="691e1b5952068ff7aaeccffc9"
273
397
  webhookUrl="https://api.example.com/webhook"
274
- data="username=John Doe~telephone_number=+628123456789~email=john@example.com"
398
+ username="John Doe"
399
+ data="telephone_number=+628123456789~email=john@example.com"
275
400
  />
276
401
  ```
277
402
 
@@ -290,7 +415,8 @@ Pass custom user data like username, phone number, etc. to the backend:
290
415
  }
291
416
  }
292
417
  ```
293
-
418
+ }
419
+ ```
294
420
  #### With Authentication (NEW!)
295
421
 
296
422
  The widget supports automatic authentication with token refresh on expiry:
@@ -300,34 +426,34 @@ The widget supports automatic authentication with token refresh on expiry:
300
426
  userId="user123"
301
427
  sourceId="691e1b5952068ff7aaeccffc9"
302
428
  webhookUrl="https://api.example.com/webhook"
303
- data="authUrl=https://api.example.com/login/chatwidget~username=John Doe"
429
+ authUrl="https://api.example.com/login/chatwidget"
430
+ username="John Doe"
304
431
  />
305
432
  ```
306
433
 
307
434
  **How authentication works:**
308
435
 
309
- 1. **Initial Authentication**: When the widget loads (on Launcher mount), if `authUrl` is provided in the `data` prop, it automatically calls the auth API:
436
+ 1. **Initial Authentication**: When the widget loads (on Launcher mount), if `authUrl` is provided as a prop, it automatically calls the auth API:
310
437
  ```
311
438
  POST {authUrl}
312
439
  Body: { "user_id": "user123" }
313
440
  Response: { "token": "eyJ..." }
314
441
  ```
315
442
 
316
- 2. **Token Usage**: The received token is automatically included in all webhook API calls as `authToken` in the `variables` object:
317
- ```json
318
- {
319
- "chat_id": "...",
443
+ 2. **Session Initialization**: After getting the token, the widget calls the init endpoint to establish the session:
444
+ ```
445
+ POST {webhookUrl}/{sourceId}/init
446
+ Body: {
447
+ "session_id": "...",
320
448
  "user_id": "user123",
321
- "message": "Hello",
322
- "variables": {
323
- "authToken": "eyJ...",
324
- "username": "John Doe"
325
- }
449
+ "token": "eyJ...",
450
+ "username": "John Doe"
326
451
  }
327
452
  ```
328
453
 
329
454
  3. **Automatic Token Refresh**: If the webhook returns **401 Unauthorized** (token expired/revoked), the widget automatically:
330
455
  - Calls the `authUrl` again to get a fresh token
456
+ - Re-initializes the session with the new token
331
457
  - Updates the `authToken` in variables
332
458
  - Retries the failed request with the new token
333
459
  - This happens transparently without user interaction
@@ -338,18 +464,61 @@ The widget supports automatic authentication with token refresh on expiry:
338
464
  userId="user123"
339
465
  sourceId="691e1b5952068ff7aaeccffc9"
340
466
  webhookUrl="https://api.example.com/webhook"
341
- data="authUrl=https://api.example.com/login/chatwidget~username=John~email=john@example.com~phone=+628123456789"
467
+ authUrl="https://api.example.com/login/chatwidget"
468
+ username="John"
469
+ data="email=john@example.com~phone=+628123456789"
342
470
  />
343
471
  ```
344
472
 
345
- **Note:** The `data` prop is for optional parameters only (custom variables and `authUrl`). Required parameters (`userId`, `sourceId`, `webhookUrl`) must be passed as direct props.
473
+ **Auth Flag (`auth` variable):**
474
+ The widget automatically adds an `auth: false` flag to the `variables` object when the user is a guest (not authenticated):
475
+ - When `userId === visitorId` (browser fingerprint), the widget adds `auth: false` to variables
476
+ - When `userId !== visitorId` (authenticated user), no `auth` flag is added to variables
477
+
478
+ **Guest user example** (userId equals browser fingerprint):
479
+ ```json
480
+ {
481
+ "chat_id": "...",
482
+ "session_id": "...",
483
+ "user_id": "visitor_abc123",
484
+ "message": "Hello",
485
+ "type": "text",
486
+ "variables": {
487
+ "username": "Guest",
488
+ "auth": false
489
+ }
490
+ }
491
+ ```
492
+
493
+ **Authenticated user example** (userId is different from browser fingerprint):
494
+ ```json
495
+ {
496
+ "chat_id": "...",
497
+ "session_id": "...",
498
+ "user_id": "user123",
499
+ "message": "Hello",
500
+ "type": "text",
501
+ "variables": {
502
+ "username": "John Doe",
503
+ "email": "john@example.com"
504
+ }
505
+ }
506
+ ```
507
+
508
+ This `auth: false` flag is automatically added in:
509
+ - Session initialization payload (when guest)
510
+ - All message requests (when guest)
511
+ - Button postback requests (when guest)
512
+
513
+ **Note:** The `data` prop is for additional custom variables only. Required parameters (`userId`, `sourceId`, `webhookUrl`) and common optional parameters (`authUrl`, `username`) should be passed as direct props for better type safety and clarity.
346
514
 
347
515
  #### Custom Styling
348
516
 
349
517
  ```jsx
350
518
  <ChatWidget
351
- userId="user123"
519
+ userId="user123" // Optional
352
520
  sourceId="691e1b5952068ff7aaeccffc9"
521
+ webhookUrl="https://api.example.com/webhook"
353
522
  width="400px"
354
523
  height="600px"
355
524
  right="20px"
@@ -364,8 +533,9 @@ The widget supports automatic authentication with token refresh on expiry:
364
533
  <div style={{ display: 'grid', gridTemplateColumns: '1fr 400px' }}>
365
534
  <div>Main content</div>
366
535
  <ChatWidget
367
- userId="user123"
536
+ userId="user123" // Optional
368
537
  sourceId="691e1b5952068ff7aaeccffc9"
538
+ webhookUrl="https://api.example.com/webhook"
369
539
  position="relative"
370
540
  width="100%"
371
541
  height="100vh"
@@ -384,8 +554,9 @@ function App() {
384
554
 
385
555
  return (
386
556
  <ChatWidget
387
- userId="user123"
557
+ userId="user123" // Optional
388
558
  sourceId="691e1b5952068ff7aaeccffc9"
559
+ webhookUrl="https://api.example.com/webhook"
389
560
  onToggle={handleToggle}
390
561
  />
391
562
  );
@@ -396,8 +567,9 @@ function App() {
396
567
 
397
568
  ```jsx
398
569
  <ChatWidget
399
- userId="user123"
570
+ userId="user123" // Optional - supports guest users
400
571
  sourceId="691e1b5952068ff7aaeccffc9"
572
+ webhookUrl="https://api.example.com/webhook"
401
573
  width="100vw"
402
574
  height="100vh"
403
575
  right="0"
@@ -411,23 +583,16 @@ function App() {
411
583
 
412
584
  ---
413
585
 
414
- The `data` prop allows you to pass custom variables and authentication URL via a single string. This is especially useful when you need to dynamically pass user-specific data or pass it through URL parameters.
586
+ The `data` prop allows you to pass additional custom variables via a single string. This is especially useful when you need to dynamically pass user-specific data or pass it through URL parameters.
415
587
 
416
588
  **Format:** `key=value` pairs separated by `~`
417
589
 
418
590
  **Example data string:**
419
591
  ```
420
- username=John Doe~phone=+1234567890~email=john@example.com
421
- ```
422
-
423
- **With authentication:**
424
- ```
425
- authUrl=https://api.example.com/login/chatwidget~username=John Doe~email=john@example.com
592
+ email=john@example.com~phone=+1234567890~department=Engineering
426
593
  ```
427
594
 
428
- **Special keys:**
429
- - `authUrl`: Authentication endpoint URL (see "With Authentication" section above)
430
- - All other keys: Custom variables passed to webhook in `variables` object
595
+ **Note:** `authUrl` and `username` are now **direct props** and should not be included in the `data` string.
431
596
 
432
597
  #### Building Data String Programmatically
433
598
 
@@ -443,40 +608,27 @@ Instead of manually constructing the data string, you can create a helper functi
443
608
  /**
444
609
  * Builds the data string for ChatWidget component
445
610
  * @param {Object} params - Object containing all parameters
446
- * @param {string} params.authUrl - Optional: Authentication endpoint URL
447
- * @param {string} params.username - Optional: User's display name
448
611
  * @param {string} params.email - Optional: User's email address
449
612
  * @param {string} params.phone - Optional: User's phone number
450
613
  * @param {Object} params.customFields - Optional: Any additional custom fields as key-value pairs
451
614
  * @returns {string} Formatted data string for ChatWidget (always returns a string)
452
615
  *
453
616
  * @example
454
- * // Returns: "authUrl=https://api.com~username=John~email=john@example.com"
617
+ * // Returns: "email=john@example.com~phone=+1234567890~department=Engineering"
455
618
  * buildChatWidgetData({
456
- * authUrl: "https://api.com",
457
- * username: "John",
458
- * email: "john@example.com"
619
+ * email: "john@example.com",
620
+ * phone: "+1234567890",
621
+ * customFields: { department: "Engineering" }
459
622
  * });
460
623
  */
461
624
  export const buildChatWidgetData = ({
462
- authUrl,
463
- username,
464
625
  email,
465
626
  phone,
466
627
  customFields = {}
467
628
  }) => {
468
629
  const parts = [];
469
630
 
470
- // Add authUrl first if provided (for authentication)
471
- if (authUrl) {
472
- parts.push(`authUrl=${authUrl}`);
473
- }
474
-
475
631
  // Add standard fields
476
- if (username) {
477
- parts.push(`username=${encodeURIComponent(username)}`);
478
- }
479
-
480
632
  if (email) {
481
633
  parts.push(`email=${encodeURIComponent(email)}`);
482
634
  }
@@ -494,7 +646,7 @@ export const buildChatWidgetData = ({
494
646
  }
495
647
  });
496
648
 
497
- // Returns a string like: "authUrl=...~username=John~email=john@example.com~department=Engineering"
649
+ // Returns a string like: "email=john@example.com~phone=+1234567890~department=Engineering"
498
650
  return parts.join("~");
499
651
  };
500
652
  ```
@@ -517,10 +669,8 @@ function App() {
517
669
  phone: "+628123456789"
518
670
  };
519
671
 
520
- // Build the data string
672
+ // Build the data string with custom variables only
521
673
  const customData = buildChatWidgetData({
522
- authUrl: "https://api.example.com/login/chatwidget",
523
- username: user.name,
524
674
  email: user.email,
525
675
  phone: user.phone,
526
676
  customFields: {
@@ -531,14 +681,16 @@ function App() {
531
681
  });
532
682
 
533
683
  // customData is now a STRING like:
534
- // "authUrl=https://api.example.com/login/chatwidget~username=John%20Doe~email=john@example.com~phone=%2B628123456789~department=Engineering~role=Developer~company=Acme%20Corp"
684
+ // "email=john@example.com~phone=%2B628123456789~department=Engineering~role=Developer~company=Acme%20Corp"
535
685
 
536
686
  return (
537
687
  <ChatWidget
538
688
  userId={user.id}
539
689
  sourceId="691e1b5952068ff7aaeccffc9"
540
690
  webhookUrl="https://api.example.com/webhook"
541
- data={customData} // Pass the STRING to data prop
691
+ authUrl="https://api.example.com/login/chatwidget" // Direct prop
692
+ username={user.name} // Direct prop
693
+ data={customData} // Only additional variables
542
694
  />
543
695
  );
544
696
  }
@@ -553,9 +705,10 @@ function App() {
553
705
  : null;
554
706
 
555
707
  const customData = buildChatWidgetData({
556
- authUrl: authUrl, // Only included if authentication is enabled
557
- username: getCurrentUser().name,
558
- email: getCurrentUser().email
708
+ email: getCurrentUser().email,
709
+ customFields: {
710
+ department: "Sales"
711
+ }
559
712
  });
560
713
 
561
714
  return (
@@ -563,7 +716,9 @@ function App() {
563
716
  userId={getCurrentUser().id}
564
717
  sourceId="691e1b5952068ff7aaeccffc9"
565
718
  webhookUrl={import.meta.env.VITE_WEBHOOK_URL}
566
- data={customData}
719
+ authUrl={authUrl} // Direct prop (conditionally set)
720
+ username={getCurrentUser().name} // Direct prop
721
+ data={customData} // Only additional variables
567
722
  />
568
723
  );
569
724
  }