@product7/product7-js 0.2.6 → 0.2.7
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 +66 -937
- package/dist/README.md +66 -937
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,1003 +3,132 @@
|
|
|
3
3
|
[](https://badge.fury.io/js/%40product7%2Fproduct7-js)
|
|
4
4
|
[](https://bundlephobia.com/package/@product7/product7-js)
|
|
5
5
|
|
|
6
|
-
The official JavaScript SDK for Product7.
|
|
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
|
-
##
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
## Quick Start
|
|
32
|
-
|
|
33
|
-
### CDN Installation
|
|
34
|
-
|
|
35
|
-
```html
|
|
36
|
-
<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
|
-
```
|
|
53
|
-
|
|
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.
|
|
55
|
-
|
|
56
|
-
### NPM Installation
|
|
12
|
+
**npm**
|
|
57
13
|
|
|
58
14
|
```bash
|
|
59
15
|
npm install @product7/product7-js
|
|
60
16
|
```
|
|
61
17
|
|
|
62
|
-
|
|
63
|
-
import { Product7 } from '@product7/product7-js';
|
|
64
|
-
|
|
65
|
-
const sdk = new Product7({
|
|
66
|
-
workspace: 'your-workspace-name',
|
|
67
|
-
metadata: {
|
|
68
|
-
user_id: 'user_123',
|
|
69
|
-
email: 'user@example.com',
|
|
70
|
-
name: 'Jane Doe',
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
|
|
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**
|
|
18
|
+
**CDN**
|
|
125
19
|
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
position: 'bottom-right',
|
|
129
|
-
theme: 'light',
|
|
130
|
-
teamName: 'Support',
|
|
131
|
-
enableHelp: true,
|
|
132
|
-
enableChangelog: true,
|
|
133
|
-
});
|
|
134
|
-
messenger.mount();
|
|
20
|
+
```html
|
|
21
|
+
<script src="https://cdn.jsdelivr.net/npm/@product7/product7-js@latest/dist/product7-js.min.js"></script>
|
|
135
22
|
```
|
|
136
23
|
|
|
137
24
|
---
|
|
138
25
|
|
|
139
|
-
##
|
|
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
|
|
26
|
+
## Quick Start
|
|
185
27
|
|
|
186
|
-
|
|
28
|
+
### npm / framework
|
|
187
29
|
|
|
188
30
|
```javascript
|
|
189
|
-
|
|
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:
|
|
31
|
+
import { Product7 } from '@product7/product7-js';
|
|
208
32
|
|
|
209
|
-
```javascript
|
|
210
33
|
const sdk = new Product7({
|
|
211
|
-
|
|
212
|
-
|
|
34
|
+
workspace: 'your-workspace',
|
|
35
|
+
metadata: {
|
|
36
|
+
user_id: 'user_123',
|
|
37
|
+
email: 'user@example.com',
|
|
38
|
+
name: 'Jane Doe',
|
|
39
|
+
},
|
|
213
40
|
});
|
|
214
41
|
|
|
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
|
-
```
|
|
229
|
-
|
|
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
|
-
});
|
|
246
|
-
|
|
247
|
-
await sdk.init();
|
|
248
46
|
```
|
|
249
47
|
|
|
250
|
-
|
|
48
|
+
### CDN
|
|
251
49
|
|
|
252
|
-
|
|
253
|
-
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
---
|
|
332
|
-
|
|
333
|
-
## Development
|
|
334
|
-
|
|
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
|
|
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
|
+
});
|
|
61
|
+
|
|
62
|
+
await sdk.init();
|
|
63
|
+
|
|
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
|
|
374
|
-
|
|
375
|
-
---
|
|
376
|
-
|
|
377
|
-
## License
|
|
378
|
-
|
|
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)
|
|
69
|
+
> Use `window.Product7.Product7SDK` on CDN — `window.Product7` is a plain object, not a constructor.
|
|
389
70
|
|
|
390
71
|
---
|
|
391
72
|
|
|
392
|
-
##
|
|
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
|
|
73
|
+
## Widgets
|
|
404
74
|
|
|
405
|
-
|
|
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
|
-
|
|
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
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
enableHelp: true,
|
|
425
|
-
enableChangelog: true,
|
|
426
|
-
primaryColor: '#155EEF',
|
|
85
|
+
position: 'bottom-right',
|
|
86
|
+
teamName: 'Support Team',
|
|
87
|
+
enableHelp: true,
|
|
88
|
+
enableChangelog: true,
|
|
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
91
|
|
|
516
|
-
|
|
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
|
-
|
|
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
|
-
});
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
---
|
|
541
|
-
|
|
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
|
|
556
|
-
|
|
557
|
-
```javascript
|
|
558
|
-
const sdk = new Product7({
|
|
559
|
-
workspace: 'your-workspace',
|
|
560
|
-
metadata: {
|
|
561
|
-
user_id: 'user_123',
|
|
562
|
-
email: 'user@example.com',
|
|
563
|
-
name: 'Jane Doe',
|
|
564
|
-
},
|
|
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
|
-
},
|
|
622
|
-
});
|
|
623
|
-
```
|
|
624
|
-
|
|
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
|
|
92
|
+
// Survey — fetch active surveys and show on load
|
|
631
93
|
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
94
|
if (surveys.length > 0) {
|
|
638
|
-
|
|
639
|
-
}
|
|
640
|
-
```
|
|
641
|
-
|
|
642
|
-
---
|
|
643
|
-
|
|
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)
|
|
683
|
-
|
|
684
|
-
```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
|
-
});
|
|
724
|
-
```
|
|
725
|
-
|
|
726
|
-
---
|
|
727
|
-
|
|
728
|
-
### Event-Triggered Surveys
|
|
729
|
-
|
|
730
|
-
Trigger surveys based on user actions:
|
|
731
|
-
|
|
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
|
-
});
|
|
95
|
+
sdk.showSurveyById(surveys[0].surveyId, { position: 'center' });
|
|
788
96
|
}
|
|
789
97
|
```
|
|
790
98
|
|
|
791
99
|
---
|
|
792
100
|
|
|
793
|
-
|
|
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
|
|
101
|
+
## Key Options
|
|
909
102
|
|
|
910
103
|
```javascript
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
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'
|
|
104
|
+
new Product7({
|
|
105
|
+
workspace: 'your-workspace', // required
|
|
106
|
+
metadata: { // recommended — identifies the user
|
|
107
|
+
user_id: 'user_123',
|
|
108
|
+
email: 'user@example.com',
|
|
109
|
+
name: 'Jane Doe',
|
|
110
|
+
custom_fields: { plan: 'pro' },
|
|
927
111
|
},
|
|
928
|
-
|
|
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',
|
|
112
|
+
debug: false, // enable console logging
|
|
113
|
+
mock: false, // run without a backend (dev/testing)
|
|
959
114
|
});
|
|
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
115
|
```
|
|
971
116
|
|
|
972
|
-
|
|
117
|
+
---
|
|
973
118
|
|
|
974
|
-
|
|
119
|
+
## Cleanup
|
|
975
120
|
|
|
976
121
|
```javascript
|
|
977
|
-
|
|
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
|
-
}
|
|
122
|
+
sdk.destroy(); // call on app unmount to prevent memory leaks
|
|
994
123
|
```
|
|
995
124
|
|
|
996
125
|
---
|
|
997
126
|
|
|
998
|
-
##
|
|
127
|
+
## Docs & Support
|
|
999
128
|
|
|
1000
|
-
- [
|
|
1001
|
-
- [
|
|
1002
|
-
- [
|
|
129
|
+
- Full documentation: [docs.product7.io](https://docs.product7.io)
|
|
130
|
+
- Issues: [GitHub Issues](https://github.com/product7/product7-js/issues)
|
|
131
|
+
- Email: [support@product7.io](mailto:support@product7.io)
|
|
1003
132
|
|
|
1004
133
|
---
|
|
1005
134
|
|