@product7/product7-js 0.2.6 → 0.2.9

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
@@ -3,67 +3,35 @@
3
3
  [![npm version](https://badge.fury.io/js/%40product7%2Fproduct7-js.svg)](https://badge.fury.io/js/%40product7%2Fproduct7-js)
4
4
  [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@product7/product7-js)](https://bundlephobia.com/package/@product7/product7-js)
5
5
 
6
- The official JavaScript SDK for Product7. Collect feedback, chat with users, run surveys, and share changelogs all through lightweight, embeddable widgets.
6
+ The official JavaScript SDK for [Product7](https://product7.io). Embed feedback collection, live chat, surveys, and changelogs into any web app.
7
7
 
8
8
  ---
9
9
 
10
- ## Features
11
-
12
- - **Display modes** — Side panel or centered modal
13
- - **Size options** — Small, medium, or large widget sizes
14
- - **Full color customization** — Background, text, and primary colors
15
- - **Custom triggers** — Use your own buttons instead of floating widget
16
- - **Mock mode** — Development without backend connection
17
- - **Multiple positions** — 7 position options including center
18
- - **Responsive design** — Works on desktop, tablet, and mobile
19
- - **Easy integration** — Simple JavaScript API, minimal setup
20
- - **Lightweight** — ~12KB gzipped
21
- - **TypeScript support** — Full type definitions included
22
- - **Accessible** — WCAG 2.1 compliant
23
- - **Secure** — CSP friendly, no `eval()` usage
24
- - **Messenger widget** — Real-time chat with WebSocket support
25
- - **Help center** — Integrated help articles and collections
26
- - **Changelog** — Display product updates and announcements
27
- - **Environment auto-detection** — Automatic staging/production switching
10
+ ## Installation
28
11
 
29
- ---
12
+ **npm**
30
13
 
31
- ## Quick Start
14
+ ```bash
15
+ npm install @product7/product7-js
16
+ ```
32
17
 
33
- ### CDN Installation
18
+ **CDN**
34
19
 
35
20
  ```html
36
21
  <script src="https://cdn.jsdelivr.net/npm/@product7/product7-js@latest/dist/product7-js.min.js"></script>
37
- <script>
38
- const sdk = new window.Product7.Product7SDK({
39
- workspace: 'your-workspace-name',
40
- metadata: {
41
- user_id: 'user_123',
42
- email: 'user@example.com',
43
- name: 'Jane Doe',
44
- },
45
- });
46
-
47
- await sdk.init();
48
-
49
- const widget = sdk.createWidget('button', { position: 'bottom-right' });
50
- widget.mount();
51
- </script>
52
22
  ```
53
23
 
54
- > `window.Product7.Product7SDK` is the constructable class exposed by the CDN bundle. Do not use `new window.Product7(...)` directly — `window.Product7` is a plain object, not a class.
24
+ ---
55
25
 
56
- ### NPM Installation
26
+ ## Quick Start
57
27
 
58
- ```bash
59
- npm install @product7/product7-js
60
- ```
28
+ ### npm / framework
61
29
 
62
30
  ```javascript
63
31
  import { Product7 } from '@product7/product7-js';
64
32
 
65
33
  const sdk = new Product7({
66
- workspace: 'your-workspace-name',
34
+ workspace: 'your-workspace',
67
35
  metadata: {
68
36
  user_id: 'user_123',
69
37
  email: 'user@example.com',
@@ -71,935 +39,97 @@ const sdk = new Product7({
71
39
  },
72
40
  });
73
41
 
74
- await sdk.init();
75
- const widget = sdk.createWidget('button', { position: 'bottom-right' });
76
- widget.mount();
77
- ```
78
-
79
- ---
80
-
81
- ## Documentation
82
-
83
- - [Installation Guide](src/docs/installation.md)
84
- - [Framework Integrations](src/docs/framework-integrations.md)
85
- - [API Reference](src/docs/api.md)
86
- - [Examples](src/docs/example.md)
87
-
88
- ---
89
-
90
- ## Widget Types
91
-
92
- **Button Widget with Side Panel**
93
-
94
- ```javascript
95
- const widget = sdk.createWidget('button', {
96
- position: 'bottom-right',
97
- displayMode: 'panel', // Slides in from the side
98
- size: 'medium',
99
- });
100
- widget.mount();
101
- ```
102
-
103
- **Button Widget with Modal**
104
-
105
- ```javascript
106
- const widget = sdk.createWidget('button', {
107
- position: 'bottom-right',
108
- displayMode: 'modal',
109
- size: 'large',
110
- backgroundColor: '#ffffff',
111
- textColor: '#1F2937',
112
- primaryColor: '#21244A',
113
- });
114
- widget.mount();
115
- ```
116
-
117
- **Inline Widget**
118
-
119
- ```javascript
120
- const inline = sdk.createWidget('inline');
121
- inline.mount('#feedback-container');
122
- ```
123
-
124
- **Messenger Widget**
125
-
126
- ```javascript
127
- const messenger = sdk.createWidget('messenger', {
128
- position: 'bottom-right',
129
- theme: 'light',
130
- teamName: 'Support',
131
- enableHelp: true,
132
- enableChangelog: true,
133
- });
134
- messenger.mount();
135
- ```
136
-
137
- ---
138
-
139
- ## Configuration
140
-
141
- ### SDK Configuration
142
-
143
- | Option | Type | Required | Default | Description |
144
- | ----------- | ------- | -------- | ----------- | -------------------------------------- |
145
- | `workspace` | string | ✅ | - | Your workspace subdomain |
146
- | `boardName` | string | ❌ | 'general' | Target board for feedback |
147
- | `metadata` | object | ❌ | null | User identification data |
148
- | `mock` | boolean | ❌ | false | Enable mock mode for development |
149
- | `debug` | boolean | ❌ | false | Enable debug logging |
150
- | `env` | string | ❌ | auto-detect | Environment: 'production' or 'staging' |
151
- | `apiUrl` | string | ❌ | null | Custom API URL (overrides env) |
152
-
153
- ### Widget Configuration
154
-
155
- | Option | Type | Default | Description |
156
- | ----------------- | ------ | -------------- | ---------------------------------------------- |
157
- | `displayMode` | string | 'panel' | `'panel'` (side slide) or `'modal'` (centered) |
158
- | `size` | string | 'medium' | `'small'`, `'medium'`, or `'large'` |
159
- | `position` | string | 'bottom-right' | Button position (see below) |
160
- | `backgroundColor` | string | '#ffffff' | Panel/modal background color |
161
- | `textColor` | string | '#1F2937' | Text color |
162
- | `primaryColor` | string | '#21244A' | Button and accent color |
163
-
164
- ### Position Options
165
-
166
- - `bottom-right` (default)
167
- - `bottom-left`
168
- - `top-right`
169
- - `top-left`
170
- - `bottom-center`
171
- - `top-center`
172
- - `center`
173
-
174
- ### Size Variants
175
-
176
- | Size | Modal Width | Panel Width |
177
- | ------ | ----------- | ----------- |
178
- | small | 360px | 320px |
179
- | medium | 480px | 420px |
180
- | large | 600px | 520px |
181
-
182
- ---
183
-
184
- ## Color Customization
185
-
186
- Instead of predefined themes, use direct color values for full flexibility:
187
-
188
- ```javascript
189
- const widget = sdk.createWidget('button', {
190
- displayMode: 'modal',
191
- backgroundColor: '#1a1a2e', // Dark background
192
- textColor: '#ffffff', // White text
193
- primaryColor: '#e94560', // Red accent
194
- });
195
- ```
196
-
197
- This approach works better than predefined themes because:
198
-
199
- - Supports any brand color
200
- - Works with both light and dark designs
201
- - No restrictions on color combinations
202
-
203
- ---
204
-
205
- ## Custom Triggers
206
-
207
- Hide the default floating button and trigger from your own UI:
208
-
209
- ```javascript
210
- const sdk = new Product7({
211
- workspace: 'your-workspace',
212
- metadata: { user_id: 'user_123', email: 'user@example.com', name: 'Jane Doe' },
213
- });
214
-
215
42
  await sdk.init();
216
43
 
217
- const widget = sdk.createWidget('button', {
218
- displayMode: 'modal',
219
- size: 'medium',
220
- });
44
+ const widget = sdk.createWidget('button', { position: 'bottom-right' });
221
45
  widget.mount();
222
- widget.hide(); // Hide the floating button
223
-
224
- // Trigger from your own button
225
- document.getElementById('my-feedback-btn').addEventListener('click', () => {
226
- widget.openPanel();
227
- });
228
46
  ```
229
47
 
230
- ---
231
-
232
- ## Mock Mode
233
-
234
- For development without a backend connection:
235
-
236
- ```javascript
237
- const sdk = new Product7({
238
- workspace: 'demo',
239
- mock: true, // No backend required
240
- metadata: {
241
- user_id: 'test_user',
242
- email: 'test@example.com',
243
- name: 'Test User',
244
- },
245
- });
48
+ ### CDN
246
49
 
247
- await sdk.init();
248
- ```
249
-
250
- Mock mode simulates:
251
-
252
- - Session initialization
253
- - Feedback submission (with 500ms delay)
254
- - Default configuration values
255
- - Messenger conversations and messages
256
- - Help articles and collections
257
- - Changelog entries
258
- - Agent availability status
259
-
260
- ---
261
-
262
- ## Environments
263
-
264
- The SDK supports multiple environments for development and production use.
265
-
266
- ### Production (Default)
267
-
268
- ```javascript
269
- const sdk = new Product7({
270
- workspace: 'your-workspace',
271
- env: 'production', // Default, can be omitted
272
- });
273
- ```
274
-
275
- **API URLs:**
276
-
277
- - `https://api.product7.io/api/v1`
278
- - `https://{workspace}.api.product7.io/api/v1`
279
-
280
- ### Staging
281
-
282
- ```javascript
283
- const sdk = new Product7({
284
- workspace: 'your-workspace',
285
- env: 'staging',
286
- });
287
- ```
288
-
289
- **API URLs:**
290
-
291
- - `https://staging.api.product7.io/api/v1`
292
- - `https://{workspace}.staging.api.product7.io/api/v1`
293
-
294
- ### Custom API URL
295
-
296
- For self-hosted or custom deployments:
297
-
298
- ```javascript
299
- const sdk = new Product7({
300
- workspace: 'your-workspace',
301
- apiUrl: 'https://your-custom-api.com/api/v1',
302
- });
303
- ```
304
-
305
- ---
306
-
307
- ## Configuration Priority
308
-
309
- Configuration values merge in this order (later overrides earlier):
310
-
311
- 1. **Default values** — Built-in SDK defaults
312
- 2. **Backend config** — Returned from `/widget/init` API
313
- 3. **Widget options** — Passed to `createWidget()`
314
-
315
- This allows backend-managed defaults while permitting per-widget customization.
316
-
317
- ---
318
-
319
- ## Events
320
-
321
- ```javascript
322
- sdk.eventBus.on('feedback:submitted', (data) => {
323
- console.log('Feedback submitted:', data);
324
- });
325
-
326
- sdk.eventBus.on('feedback:error', (error) => {
327
- console.error('Submission failed:', error);
328
- });
329
- ```
330
-
331
- ---
50
+ ```html
51
+ <script src="https://cdn.jsdelivr.net/npm/@product7/product7-js@latest/dist/product7-js.min.js"></script>
52
+ <script>
53
+ const sdk = new window.Product7.Product7SDK({
54
+ workspace: 'your-workspace',
55
+ metadata: {
56
+ user_id: 'user_123',
57
+ email: 'user@example.com',
58
+ name: 'Jane Doe',
59
+ },
60
+ });
332
61
 
333
- ## Development
62
+ await sdk.init();
334
63
 
335
- ```bash
336
- git clone https://github.com/product7/product7-js.git
337
- cd product7-js
338
- npm install
339
- npm run dev
340
- npm run build
341
- npm test
342
- npm run size
64
+ const widget = sdk.createWidget('button', { position: 'bottom-right' });
65
+ widget.mount();
66
+ </script>
343
67
  ```
344
68
 
345
- ---
346
-
347
- ## Browser Support
348
-
349
- - Chrome 60+
350
- - Firefox 55+
351
- - Safari 12+
352
- - Edge 79+
353
- - iOS Safari 12+
354
- - Android Chrome 60+
355
-
356
- ---
357
-
358
- ## Bundle Size
359
-
360
- - **Minified**: ~41KB
361
- - **Minified + Gzipped**: ~12KB
362
-
363
- ---
364
-
365
- ## Contributing
366
-
367
- We welcome contributions! See [Contributing Guide](CONTRIBUTING.md).
368
-
369
- 1. Fork the repository
370
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
371
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
372
- 4. Push to the branch (`git push origin feature/amazing-feature`)
373
- 5. Open a Pull Request
69
+ > Use `window.Product7.Product7SDK` on CDN — `window.Product7` is a plain object, not a constructor.
374
70
 
375
71
  ---
376
72
 
377
- ## License
73
+ ## Widgets
378
74
 
379
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
380
-
381
- ---
382
-
383
- ## Support
384
-
385
- - Docs: [docs.product7.io/product7-js](https://docs.product7.io/product7-js)
386
- - Issues: [GitHub Issues](https://github.com/product7/product7-js/issues)
387
- - Discord: [Join our community](https://discord.gg/product7)
388
- - Email: [support@product7.io](mailto:support@product7.io)
389
-
390
- ---
391
-
392
- ## Messenger Widget
393
-
394
- The SDK includes a full-featured messenger widget for real-time customer conversations, help articles, and changelog updates.
395
-
396
- ### Features
397
-
398
- - **Real-time messaging** — WebSocket-powered live chat with typing indicators
399
- - **Conversation management** — View and manage multiple conversations
400
- - **Help center integration** — Browse help articles and collections
401
- - **Changelog updates** — Display product updates and announcements
402
- - **Agent availability** — Show online status and response times
403
- - **Customizable UI** — Theme, colors, and position options
404
-
405
- ### Quick Start
75
+ | Widget | Type string | Description |
76
+ | --------------- | ------------- | ----------------------------------------------------- |
77
+ | Feedback button | `'button'` | Floating button that opens a feedback panel or modal |
78
+ | Messenger | `'messenger'` | Live chat, help articles, and changelog in one widget |
79
+ | Survey | `'survey'` | NPS, CSAT, CES, and custom multi-step surveys |
80
+ | Inline | `'inline'` | Embed feedback directly into a page element |
406
81
 
407
82
  ```javascript
408
- const sdk = new Product7({
409
- workspace: 'your-workspace',
410
- metadata: {
411
- user_id: 'user_123',
412
- email: 'user@example.com',
413
- name: 'John Doe',
414
- },
415
- });
416
-
417
- await sdk.init();
418
-
83
+ // Messenger
419
84
  const messenger = sdk.createWidget('messenger', {
420
85
  position: 'bottom-right',
421
- theme: 'light',
422
86
  teamName: 'Support Team',
423
- welcomeMessage: 'How can we help you today?',
424
87
  enableHelp: true,
425
88
  enableChangelog: true,
426
- primaryColor: '#155EEF',
427
89
  });
428
-
429
90
  messenger.mount();
430
- ```
431
-
432
- ### Messenger Configuration Options
433
-
434
- | Option | Type | Default | Description |
435
- | ------------------ | -------- | ------------------ | --------------------------------------- |
436
- | `position` | string | 'bottom-right' | Widget position on screen |
437
- | `theme` | string | 'light' | 'light' or 'dark' |
438
- | `teamName` | string | 'Support' | Team name displayed in header |
439
- | `teamAvatars` | array | [] | Array of team member avatar URLs |
440
- | `welcomeMessage` | string | 'How can we help?' | Welcome message on home view |
441
- | `enableHelp` | boolean | true | Show help articles section |
442
- | `enableChangelog` | boolean | true | Show changelog section |
443
- | `enableNews` | boolean | - | Alias for `enableChangelog` |
444
- | `autoLoadData` | boolean | true | Auto-fetch conversations/help/changelog |
445
- | `initialView` | string | 'home' | Initial view on mount |
446
- | `previewData` | object | null | Seed deterministic local data |
447
- | `logoUrl` | string | - | Custom logo URL |
448
- | `primaryColor` | string | '#155EEF' | Primary accent color |
449
- | `onSendMessage` | function | null | Callback when message is sent |
450
- | `onArticleClick` | function | null | Callback when help article is clicked |
451
- | `onChangelogClick` | function | null | Callback when changelog item is clicked |
452
-
453
- ### Messenger Views
454
-
455
- The messenger widget includes multiple views:
456
-
457
- | View | Description |
458
- | ----------- | --------------------------------- |
459
- | `home` | Welcome screen with quick actions |
460
- | `messages` | List of all conversations |
461
- | `chat` | Individual conversation chat view |
462
- | `help` | Help articles and collections |
463
- | `changelog` | Product updates and announcements |
464
-
465
- ### Programmatic Control
466
-
467
- ```javascript
468
- // Open/close messenger
469
- messenger.open();
470
- messenger.close();
471
- messenger.toggle();
472
-
473
- // Navigate to specific view
474
- messenger.navigateTo('messages');
475
- messenger.navigateTo('help');
476
- messenger.navigateTo('changelog');
477
-
478
- // Get current state
479
- const state = messenger.getState();
480
- console.log(state.isOpen, state.currentView, state.unreadCount);
481
-
482
- // Update unread count
483
- messenger.setUnreadCount(3);
484
- ```
485
-
486
- ### Real-time Events
487
-
488
- ```javascript
489
- // Message sent
490
- sdk.eventBus.on('messenger:messageSent', (data) => {
491
- console.log('Message sent:', data.message);
492
- });
493
-
494
- // Messenger opened/closed
495
- sdk.eventBus.on('messenger:opened', () => {
496
- console.log('Messenger opened');
497
- });
498
-
499
- sdk.eventBus.on('messenger:closed', () => {
500
- console.log('Messenger closed');
501
- });
502
- ```
503
-
504
- ### WebSocket Connection
505
-
506
- The messenger automatically establishes a WebSocket connection for real-time features:
507
-
508
- - **Incoming messages** — New messages appear instantly
509
- - **Typing indicators** — See when agents are typing
510
- - **Presence updates** — Real-time agent availability
511
-
512
- The WebSocket connection is managed automatically and reconnects on disconnection.
513
-
514
- ---
515
-
516
- ## Environment Auto-Detection
517
-
518
- The SDK automatically detects the environment based on the hostname:
519
-
520
- | Hostname Pattern | Environment |
521
- | ----------------------------------- | ----------- |
522
- | `localhost`, `127.0.0.1`, `*.local` | staging |
523
- | Contains `staging` | staging |
524
- | All other hostnames | production |
525
91
 
526
- ```javascript
527
- // Auto-detection (recommended)
528
- const sdk = new Product7({
529
- workspace: 'your-workspace',
530
- // env is auto-detected from window.location.hostname
531
- });
532
-
533
- // Manual override
534
- const sdk = new Product7({
535
- workspace: 'your-workspace',
536
- env: 'staging', // Force staging environment
537
- });
92
+ // Survey — fetch active surveys and show on load
93
+ const surveys = await sdk.getActiveSurveys({ includeEligibility: true });
94
+ if (surveys.length > 0) {
95
+ sdk.showSurveyById(surveys[0].surveyId, { position: 'center' });
96
+ }
538
97
  ```
539
98
 
540
99
  ---
541
100
 
542
- ## Survey Widget
543
-
544
- The SDK includes a powerful survey widget for collecting structured user feedback through NPS, CSAT, CES, and custom surveys. Surveys can be triggered manually, on specific events, or managed through the backend dashboard.
545
-
546
- ### Survey Types
547
-
548
- | Type | Description | Scale |
549
- | ---------- | --------------------- | ------------------------------------------------- |
550
- | **NPS** | Net Promoter Score | 1-5 numeric scale (default; configurable to 0-10) |
551
- | **CSAT** | Customer Satisfaction | 5-point emoji scale |
552
- | **CES** | Customer Effort Score | 5-level difficulty scale |
553
- | **Custom** | Multi-question forms | Flexible input types |
554
-
555
- ### Quick Start
101
+ ## Key Options
556
102
 
557
103
  ```javascript
558
- const sdk = new Product7({
559
- workspace: 'your-workspace',
104
+ new Product7({
105
+ workspace: 'your-workspace', // required
560
106
  metadata: {
107
+ // recommended — identifies the user
561
108
  user_id: 'user_123',
562
109
  email: 'user@example.com',
563
110
  name: 'Jane Doe',
111
+ custom_fields: { plan: 'pro' },
564
112
  },
565
- });
566
-
567
- await sdk.init();
568
-
569
- // Show NPS survey
570
- sdk.showSurvey({
571
- surveyType: 'nps',
572
- description: 'To what extent do you agree or disagree that our tools support the work you do?',
573
- ratingScale: 5,
574
- showTitle: false,
575
- showDescription: true,
576
- showFeedbackInput: false,
577
- showSubmitButton: false,
578
- autoSubmitOnSelect: true,
579
- onSubmit: (response) => {
580
- console.log('Survey submitted:', response);
581
- },
582
- });
583
- ```
584
-
585
- ### Survey Configuration Options
586
-
587
- ```javascript
588
- sdk.showSurvey({
589
- surveyId: 'backend-survey-id', // Optional: links response to backend survey
590
- surveyType: 'nps', // 'nps' | 'csat' | 'ces' | 'custom'
591
- position: 'bottom-right', // 'bottom-right' | 'bottom-left' | 'center' | 'bottom'
592
- theme: 'light', // 'light' | 'dark'
593
- title: 'Your survey title',
594
- description: 'Optional description',
595
- ratingScale: 5, // NPS scale (default 5, set 11 for 0-10)
596
- showTitle: false, // default false for single-step rating surveys
597
- showDescription: true, // default true for single-step rating surveys
598
- showFeedbackInput: false, // default false for single-step rating surveys
599
- showSubmitButton: false, // default false for single-step rating surveys
600
- autoSubmitOnSelect: true, // default true for single-step rating surveys
601
- lowLabel: 'Not likely', // Low end label (NPS/CES)
602
- highLabel: 'Very likely', // High end label (NPS/CES)
603
- customQuestions: [], // For custom surveys
604
- onSubmit: (response) => {},
605
- onDismiss: () => {},
606
- });
607
- ```
608
-
609
- ---
610
-
611
- ### Backend-Driven Surveys
612
-
613
- For surveys configured in the Product7 dashboard, use `showSurveyById()` to fetch and display them:
614
-
615
- ```javascript
616
- // Show a specific survey by its backend ID
617
- await sdk.showSurveyById('survey_abc123', {
618
- position: 'center',
619
- onSubmit: (response) => {
620
- console.log('Survey completed:', response);
621
- },
113
+ debug: false, // enable console logging
114
+ mock: false, // run without a backend (dev/testing)
622
115
  });
623
116
  ```
624
117
 
625
- ### Fetching Active Surveys
626
-
627
- Retrieve surveys that match the current user's targeting criteria:
628
-
629
- ```javascript
630
- // Get all active surveys for the current context
631
- const surveys = await sdk.getActiveSurveys({ includeEligibility: true });
632
-
633
- console.log('Available surveys:', surveys);
634
- // [{ surveyId: 'survey_123', surveyType: 'nps', title: '...', ... }]
635
-
636
- // Show the first matching survey
637
- if (surveys.length > 0) {
638
- await sdk.showSurveyById(surveys[0].surveyId, { position: 'center' });
639
- }
640
- ```
641
-
642
118
  ---
643
119
 
644
- ### Survey Types
645
-
646
- #### NPS Survey (Net Promoter Score)
647
-
648
- ```javascript
649
- sdk.showSurvey({
650
- surveyType: 'nps',
651
- description: 'To what extent do you agree or disagree that our tools support the work you do?',
652
- ratingScale: 5,
653
- showTitle: false,
654
- showDescription: true,
655
- showFeedbackInput: false,
656
- showSubmitButton: false,
657
- autoSubmitOnSelect: true,
658
- lowLabel: 'Strongly Disagree',
659
- highLabel: 'Strongly Agree',
660
- position: 'bottom-right',
661
- onSubmit: (response) => {
662
- console.log('Score:', response.score); // 1-5 by default
663
- console.log('Feedback:', response.feedback);
664
- },
665
- });
666
- ```
667
-
668
- #### CSAT Survey (Customer Satisfaction)
669
-
670
- ```javascript
671
- sdk.showSurvey({
672
- surveyType: 'csat',
673
- title: 'How satisfied are you with our service?',
674
- position: 'center',
675
- theme: 'dark',
676
- onSubmit: (response) => {
677
- console.log('Satisfaction:', response.score); // 1-5
678
- },
679
- });
680
- ```
681
-
682
- #### CES Survey (Customer Effort Score)
120
+ ## Cleanup
683
121
 
684
122
  ```javascript
685
- sdk.showSurvey({
686
- surveyType: 'ces',
687
- title: 'How easy was it to complete your task?',
688
- position: 'bottom',
689
- onSubmit: (response) => {
690
- console.log('Effort score:', response.score); // 1-5
691
- },
692
- });
693
- ```
694
-
695
- #### Custom Survey
696
-
697
- ```javascript
698
- sdk.showSurvey({
699
- surveyType: 'custom',
700
- title: 'Quick Feedback',
701
- customQuestions: [
702
- {
703
- id: 'feature',
704
- type: 'select',
705
- label: 'Which feature do you use most?',
706
- options: [
707
- { value: 'dashboard', label: 'Dashboard' },
708
- { value: 'reports', label: 'Reports' },
709
- { value: 'settings', label: 'Settings' },
710
- ],
711
- },
712
- {
713
- id: 'improvement',
714
- type: 'text',
715
- label: 'What could we improve?',
716
- placeholder: 'Your suggestions...',
717
- },
718
- ],
719
- onSubmit: (response) => {
720
- console.log('Answers:', response.customAnswers);
721
- // { feature: 'dashboard', improvement: 'Better charts' }
722
- },
723
- });
123
+ sdk.destroy(); // call on app unmount to prevent memory leaks
724
124
  ```
725
125
 
726
126
  ---
727
127
 
728
- ### Event-Triggered Surveys
729
-
730
- Trigger surveys based on user actions:
128
+ ## Docs & Support
731
129
 
732
- ```javascript
733
- // After completing a purchase
734
- document.getElementById('checkout-btn').addEventListener('click', async () => {
735
- await processPayment();
736
-
737
- sdk.showSurvey({
738
- surveyType: 'csat',
739
- title: 'How was your checkout experience?',
740
- position: 'center',
741
- });
742
- });
743
-
744
- // After closing support chat
745
- chatWidget.on('close', () => {
746
- sdk.showSurvey({
747
- surveyType: 'ces',
748
- title: 'How easy was it to get help?',
749
- position: 'bottom-right',
750
- });
751
- });
752
-
753
- // On page exit intent
754
- document.addEventListener('mouseleave', (e) => {
755
- if (e.clientY < 0 && !sessionStorage.getItem('exit_survey_shown')) {
756
- sessionStorage.setItem('exit_survey_shown', 'true');
757
- sdk.showSurvey({
758
- surveyType: 'nps',
759
- title: 'Before you go...',
760
- description: 'How likely are you to recommend us?',
761
- position: 'center',
762
- });
763
- }
764
- });
765
- ```
766
-
767
- ### Time-Based Surveys
768
-
769
- ```javascript
770
- // Show after 60 seconds on page
771
- setTimeout(() => {
772
- sdk.showSurvey({
773
- surveyType: 'nps',
774
- title: 'Enjoying our product?',
775
- position: 'bottom-right',
776
- });
777
- }, 60000);
778
-
779
- // Show after N page views
780
- const pageViews = parseInt(localStorage.getItem('page_views') || '0') + 1;
781
- localStorage.setItem('page_views', pageViews);
782
-
783
- if (pageViews === 5) {
784
- sdk.showSurvey({
785
- surveyType: 'csat',
786
- title: 'How are you finding things so far?',
787
- });
788
- }
789
- ```
790
-
791
- ---
792
-
793
- ### React Integration
794
-
795
- ```jsx
796
- import { useEffect, useRef } from 'react';
797
- import { Product7 } from '@product7/product7-js';
798
-
799
- function useSurvey() {
800
- const sdkRef = useRef(null);
801
-
802
- useEffect(() => {
803
- const sdk = new Product7({
804
- workspace: 'your-workspace',
805
- metadata: {
806
- user_id: currentUser.id,
807
- email: currentUser.email,
808
- },
809
- });
810
-
811
- sdk.init().then(() => {
812
- sdkRef.current = sdk;
813
- });
814
-
815
- return () => sdk.destroy();
816
- }, []);
817
-
818
- const showNPS = (options = {}) => {
819
- sdkRef.current?.showSurvey({ surveyType: 'nps', ...options });
820
- };
821
-
822
- const showCSAT = (options = {}) => {
823
- sdkRef.current?.showSurvey({ surveyType: 'csat', ...options });
824
- };
825
-
826
- return { showNPS, showCSAT };
827
- }
828
-
829
- // Usage in component
830
- function CheckoutSuccess() {
831
- const { showCSAT } = useSurvey();
832
-
833
- useEffect(() => {
834
- showCSAT({
835
- title: 'How was your checkout experience?',
836
- position: 'center',
837
- });
838
- }, []);
839
-
840
- return <div>Thank you for your purchase!</div>;
841
- }
842
- ```
843
-
844
- ### Vue.js Integration
845
-
846
- ```vue
847
- <script setup>
848
- import { onMounted, onUnmounted, ref } from 'vue';
849
- import { Product7 } from '@product7/product7-js';
850
-
851
- const sdk = ref(null);
852
-
853
- onMounted(async () => {
854
- sdk.value = new Product7({
855
- workspace: 'your-workspace',
856
- metadata: {
857
- user_id: currentUser.value.id,
858
- email: currentUser.value.email,
859
- },
860
- });
861
- await sdk.value.init();
862
- });
863
-
864
- onUnmounted(() => {
865
- sdk.value?.destroy();
866
- });
867
-
868
- const showSurvey = (type, options = {}) => {
869
- sdk.value?.showSurvey({ surveyType: type, ...options });
870
- };
871
-
872
- const handleFeedbackClick = () => {
873
- showSurvey('nps', {
874
- title: 'How likely are you to recommend us?',
875
- position: 'center',
876
- });
877
- };
878
- </script>
879
- ```
880
-
881
- ---
882
-
883
- ### Survey Events
884
-
885
- ```javascript
886
- // Survey displayed
887
- sdk.eventBus.on('survey:shown', (data) => {
888
- console.log('Survey displayed:', data.type);
889
- analytics.track('Survey Shown', { type: data.type });
890
- });
891
-
892
- // Survey submitted
893
- sdk.eventBus.on('survey:submitted', (data) => {
894
- console.log('Survey submitted:', data.response);
895
- analytics.track('Survey Completed', {
896
- type: data.response.type,
897
- score: data.response.score,
898
- });
899
- });
900
-
901
- // Survey dismissed without completing
902
- sdk.eventBus.on('survey:dismissed', (data) => {
903
- console.log('Survey dismissed');
904
- analytics.track('Survey Dismissed');
905
- });
906
- ```
907
-
908
- ### Response Data Format
909
-
910
- ```javascript
911
- // NPS/CSAT/CES response
912
- {
913
- type: 'nps',
914
- score: 9,
915
- feedback: 'Great product!',
916
- timestamp: '2025-01-26T10:30:00.000Z'
917
- }
918
-
919
- // Custom survey response
920
- {
921
- type: 'custom',
922
- score: null,
923
- feedback: 'Additional comments here',
924
- customAnswers: {
925
- feature: 'dashboard',
926
- improvement: 'Better mobile support'
927
- },
928
- timestamp: '2025-01-26T10:30:00.000Z'
929
- }
930
- ```
931
-
932
- ---
933
-
934
- ### Position Options
935
-
936
- | Position | Description |
937
- | -------------- | ----------------------------- |
938
- | `bottom-right` | Bottom right corner (default) |
939
- | `bottom-left` | Bottom left corner |
940
- | `center` | Centered modal with backdrop |
941
- | `bottom` | Full-width bottom bar |
942
-
943
- ### Theme Options
944
-
945
- | Theme | Description |
946
- | ------- | ------------------------------------- |
947
- | `light` | White background, dark text (default) |
948
- | `dark` | Dark background, light text |
949
-
950
- ---
951
-
952
- ### Programmatic Control
953
-
954
- ```javascript
955
- // Create survey widget for later use
956
- const survey = sdk.createWidget('survey', {
957
- surveyType: 'nps',
958
- title: 'Rate us',
959
- });
960
- survey.mount();
961
-
962
- // Show when ready
963
- survey.show();
964
-
965
- // Hide programmatically
966
- survey.hide();
967
-
968
- // Destroy when done
969
- survey.destroy();
970
- ```
971
-
972
- ### Survey Rate Limiting
973
-
974
- Avoid survey fatigue by tracking when surveys were last shown:
975
-
976
- ```javascript
977
- const SURVEY_COOLDOWN = 7 * 24 * 60 * 60 * 1000; // 7 days
978
-
979
- function canShowSurvey(surveyType) {
980
- const lastShown = localStorage.getItem(`survey_${surveyType}_shown`);
981
- if (!lastShown) return true;
982
- return Date.now() - parseInt(lastShown) > SURVEY_COOLDOWN;
983
- }
984
-
985
- function showSurveyWithCooldown(options) {
986
- if (!canShowSurvey(options.surveyType)) {
987
- console.log('Survey on cooldown');
988
- return null;
989
- }
990
-
991
- localStorage.setItem(`survey_${options.surveyType}_shown`, Date.now());
992
- return sdk.showSurvey(options);
993
- }
994
- ```
995
-
996
- ---
997
-
998
- ## Related
999
-
1000
- - [Product7 Platform](https://product7.io)
1001
- - [Vue.js Example](https://github.com/product7/product7-js-vue-example)
1002
- - [React Example](https://github.com/product7/product7-js-react-example)
130
+ - Full documentation: [docs.product7.io](https://docs.product7.io)
131
+ - Issues: [GitHub Issues](https://github.com/product7/product7-js/issues)
132
+ - Email: [support@product7.io](mailto:support@product7.io)
1003
133
 
1004
134
  ---
1005
135