@encatch/web-sdk 0.0.35-beta.8 → 1.0.0-beta.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.
Files changed (33) hide show
  1. package/README.md +140 -638
  2. package/dist/encatch.es.js +2 -0
  3. package/dist/encatch.es.js.map +1 -0
  4. package/dist/encatch.iife.js +2 -0
  5. package/dist/encatch.iife.js.map +1 -0
  6. package/dist/index.d.ts +191 -0
  7. package/package.json +32 -50
  8. package/dist-sdk/plugin/sdk/core-wrapper-BMvOyc0u.js +0 -22926
  9. package/dist-sdk/plugin/sdk/module-DC2Edddk.js +0 -481
  10. package/dist-sdk/plugin/sdk/module.js +0 -5
  11. package/dist-sdk/plugin/sdk/preview-sdk.html +0 -1182
  12. package/dist-sdk/plugin/sdk/vite.svg +0 -15
  13. package/dist-sdk/plugin/sdk/web-form-engine-core.css +0 -1
  14. package/index.d.ts +0 -207
  15. package/src/@types/encatch-type.ts +0 -111
  16. package/src/encatch-instance.ts +0 -161
  17. package/src/feedback-api-types.ts +0 -18
  18. package/src/hooks/useDevice.ts +0 -30
  19. package/src/hooks/useFeedbackInterval.ts +0 -71
  20. package/src/hooks/useFeedbackTriggers.ts +0 -342
  21. package/src/hooks/useFetchElligibleFeedbackConfiguration.ts +0 -363
  22. package/src/hooks/useFetchFeedbackConfigurationDetails.ts +0 -92
  23. package/src/hooks/usePageChangeTracker.ts +0 -88
  24. package/src/hooks/usePrepopulatedAnswers.ts +0 -123
  25. package/src/hooks/useRefineTextForm.ts +0 -55
  26. package/src/hooks/useSubmitFeedbackForm.ts +0 -134
  27. package/src/hooks/useUserSession.ts +0 -53
  28. package/src/module.tsx +0 -428
  29. package/src/store/formResponses.ts +0 -211
  30. package/src/utils/browser-details.ts +0 -36
  31. package/src/utils/duration-utils.ts +0 -158
  32. package/src/utils/feedback-frequency-storage.ts +0 -214
  33. package/src/utils/feedback-storage.ts +0 -166
package/README.md CHANGED
@@ -1,756 +1,258 @@
1
- # Encatch Web SDK
1
+ # @encatch/web-sdk
2
2
 
3
- A powerful, lightweight JavaScript SDK for collecting user feedback and running surveys on web applications. Built with Preact and TypeScript, the Encatch Web SDK provides intelligent trigger-based feedback collection with advanced targeting and frequency control.
3
+ A lightweight, type-safe JavaScript SDK for integrating Encatch forms and surveys into your web application.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Intelligent Triggers**: Automatically display feedback based on user behavior
8
- - Page load triggers
9
- - Custom event triggers
10
- - Scroll-based triggers
11
- - Time-delayed triggers
12
- - **User Session Management**: Track and manage user sessions with device fingerprinting
13
- - **Frequency Control**: Configure feedback display frequency and scheduling
14
- - **Multi-language Support**: Display feedback in multiple languages
15
- - **Theme Support**: Light and dark mode with custom CSS
16
- - **Prepopulated Answers**: Pre-fill feedback forms with known data
17
- - **Event Tracking**: Track user interactions and custom events
18
- - **TypeScript Support**: Fully typed API for better developer experience
19
- - **Lightweight**: Minimal bundle size with optimized performance
7
+ - **Lightweight**: Minimal stub that loads the full implementation asynchronously
8
+ - **Type-safe**: Full TypeScript support with comprehensive type definitions
9
+ - **Queue-based**: Commands are queued until the SDK is ready, ensuring no calls are lost
10
+ - **Framework agnostic**: Works with any JavaScript framework or vanilla JS
20
11
 
21
12
  ## Installation
22
13
 
23
- ### Via Script Tag (Recommended)
24
-
25
- Add the following script to your HTML file before the closing `</head>` tag:
26
-
27
- ```html
28
- <script>
29
- !function(){if(!window.encatch){var e={_i:[],apiKey:"",config:{host:"https://your-host.com",autoStartEnabled:!1,autoStartSessionDisabled:!0,themeMode:"light",language:"en",customCssLink:""},initialized:!1,chunkUrlLoader:function(e){return window.encatch.config.host+e},init:function(n,t){if(!("initialized"in window.encatch&&window.encatch.initialized)){if(window.encatch.apiKey=n,t?.host&&(window.encatch.config.host=t.host),t?.identity&&(window.encatch.config.identity=t.identity),void 0!==t?.autoStartSessionDisabled&&(window.encatch.config.autoStartSessionDisabled=t.autoStartSessionDisabled),void 0!==t?.processAfterIdentitySet?window.encatch.config.processAfterIdentitySet=t.processAfterIdentitySet:window.encatch.config.processAfterIdentitySet=!1,void 0!==t?.autoStartEnabled&&(window.encatch.config.autoStartEnabled=t.autoStartEnabled),t?.themeMode?window.encatch.config.themeMode=t.themeMode:window.encatch.config.themeMode="light",t?.language?window.encatch.config.language=t.language:window.encatch.config.language="en",t?.customCssLink&&(window.encatch.config.customCssLink=t.customCssLink),t?.setUser&&(window.encatch.config.setUser=t.setUser),window.encatch.initialized=!0,!import.meta.env.VITE_PATH_PREFIX||import.meta.env.VITE_PATH_PREFIX.startsWith("/")||(import.meta.env.VITE_PATH_PREFIX="/"+import.meta.env.VITE_PATH_PREFIX),import.meta.env.VITE_PATH_PREFIX=import.meta.env.VITE_PATH_PREFIX.replace(/\/+$/,""),scriptSrc=`${window.encatch.config.host}${import.meta.env.VITE_PATH_PREFIX||""}/encatch-web-sdk.js`,(script=document.createElement("script")).src=scriptSrc,script.type="module",script.async=!0,firstHeadElement=document.head.firstChild)firstHeadElement?document.head.insertBefore(script,firstHeadElement):document.head.appendChild(script);var o=document.createElement("div");o.id="enisght-root",document.body.appendChild(o)}}};window.encatch=e,["trackEvent","stop","start","setUser","setThemeMode","setLanguage","openFeedbackById","openFeedbackByName","verifyFeedbackIds","forceFetchEligibleFeedbacks","capturePageScrollEvent"].forEach((function(n){e[n]=function(){for(var t=arguments.length,o=new Array(t),i=0;i<t;i++)o[i]=arguments[i];window.encatch._i.push([n].concat(o))}}))}}();
30
- </script>
31
- ```
32
-
33
- Then initialize the SDK:
34
-
35
- ```html
36
- <script>
37
- encatch.init('YOUR_API_KEY', {
38
- host: 'https://your-host.com',
39
- autoStartEnabled: true
40
- });
41
- </script>
42
- ```
43
-
44
- ### Via NPM (For Module Bundlers)
14
+ ### NPM / Yarn / PNPM
45
15
 
46
16
  ```bash
47
17
  npm install @encatch/web-sdk
18
+ # or
19
+ yarn add @encatch/web-sdk
20
+ # or
21
+ pnpm add @encatch/web-sdk
48
22
  ```
49
23
 
50
- ```javascript
51
- import '@encatch/web-sdk';
24
+ ### CDN / Script Tag
52
25
 
53
- encatch.init('YOUR_API_KEY', {
54
- host: 'https://your-host.com',
55
- autoStartEnabled: true
56
- });
26
+ ```html
27
+ <script src="https://unpkg.com/@encatch/web-sdk/dist/encatch.iife.js"></script>
57
28
  ```
58
29
 
59
30
  ## Quick Start
60
31
 
61
- ### Basic Setup
32
+ ### ES Modules
62
33
 
63
34
  ```javascript
64
- // Initialize the SDK
65
- encatch.init('YOUR_API_KEY', {
66
- host: 'https://your-host.com',
67
- autoStartEnabled: true,
68
- themeMode: 'light',
69
- language: 'en'
70
- });
35
+ import { _encatch } from '@encatch/web-sdk';
71
36
 
72
- // Set user identity (optional)
73
- encatch.setUser('user-123', {
74
- $set: {
75
- email: 'user@example.com',
76
- name: 'John Doe',
77
- plan: 'premium'
78
- }
79
- });
37
+ // Initialize with your API key
38
+ _encatch.init('YOUR_API_KEY');
80
39
 
81
- // Track custom events
82
- encatch.trackEvent('button_clicked', {
83
- path: '/dashboard',
84
- button_id: 'upgrade-button'
40
+ // Identify the user
41
+ _encatch.identifyUser('user-123', {
42
+ email: 'user@example.com',
43
+ name: 'John Doe',
85
44
  });
86
45
  ```
87
46
 
88
- ### Manual Trigger
47
+ ### Script Tag
89
48
 
90
- ```javascript
91
- // Open feedback by ID
92
- encatch.openFeedbackById('feedback-config-id-123');
93
-
94
- // Open feedback by name
95
- encatch.openFeedbackByName('Customer Satisfaction Survey');
96
-
97
- // With theme and language override
98
- encatch.openFeedbackById('feedback-config-id-123', 'dark', 'es');
99
- ```
100
-
101
- ## Configuration Options
102
-
103
- ### Initialization Options
104
-
105
- | Option | Type | Default | Description |
106
- |--------|------|---------|-------------|
107
- | `host` | `string` | - | **Required**. The host URL for the Encatch API |
108
- | `autoStartEnabled` | `boolean` | `false` | Automatically start fetching eligible feedbacks |
109
- | `autoStartSessionDisabled` | `boolean` | `true` | Disable automatic session management |
110
- | `processAfterIdentitySet` | `boolean` | `false` | Wait for user identity before processing |
111
- | `themeMode` | `'light' \| 'dark'` | `'light'` | Default theme mode |
112
- | `language` | `string` | `'en'` | Default language code |
113
- | `customCssLink` | `string` | - | URL to custom CSS file |
114
- | `setUser` | `UserInfo` | - | Initial user identity |
115
- | `customProperties` | `Record<string, string>` | - | Custom properties for targeting |
116
- | `onSessionDisabled` | `(action, message) => void` | - | Callback when session functions are disabled |
117
-
118
- ### Example: Complete Configuration
119
-
120
- ```javascript
121
- encatch.init('YOUR_API_KEY', {
122
- host: 'https://your-host.com',
123
- autoStartEnabled: true,
124
- autoStartSessionDisabled: false,
125
- themeMode: 'light',
126
- language: 'en',
127
- customCssLink: 'https://your-cdn.com/custom-theme.css',
128
- setUser: {
129
- userId: 'user-123',
130
- traits: {
131
- $set: {
132
- email: 'user@example.com',
133
- plan: 'premium'
134
- }
135
- }
136
- },
137
- onSessionDisabled: (action, message) => {
138
- console.warn(`Session action blocked: ${action} - ${message}`);
139
- }
140
- });
49
+ ```html
50
+ <script src="https://unpkg.com/@encatch/web-sdk/dist/encatch.iife.js"></script>
51
+ <script>
52
+ // The SDK is available as window._encatch
53
+ _encatch.init('YOUR_API_KEY');
54
+
55
+ _encatch.identifyUser('user-123', {
56
+ email: 'user@example.com',
57
+ name: 'John Doe',
58
+ });
59
+ </script>
141
60
  ```
142
61
 
143
62
  ## API Reference
144
63
 
145
- ### `init(apiKey, options)`
64
+ ### `init(apiKey, config?)`
146
65
 
147
- Initialize the Encatch SDK.
66
+ Initialize the SDK with your API key. This must be called before any other methods. It triggers the loading of the remote implementation script.
148
67
 
149
68
  ```javascript
150
- encatch.init('YOUR_API_KEY', {
151
- host: 'https://your-host.com',
152
- autoStartEnabled: true
69
+ _encatch.init('YOUR_API_KEY', {
70
+ webHost: 'https://custom-cdn.example.com', // Optional: override default web host (script will be loaded from webHost + '/s/sdk/v1/encatch.js')
71
+ theme: 'dark', // Optional: 'light', 'dark', or 'system' (default: 'system')
153
72
  });
154
73
  ```
155
74
 
156
- ### `start(userId?, traits?)`
75
+ ### `identifyUser(id, traits?, options?)`
157
76
 
158
- Start the SDK and optionally set user identity. Useful when `autoStartEnabled: false`.
77
+ Identify the current user. The `id` is required, traits and options are optional.
159
78
 
160
79
  ```javascript
161
- // Start without user
162
- encatch.start();
163
-
164
- // Start with user identity
165
- encatch.start('user-123', {
166
- $set: {
167
- email: 'user@example.com',
168
- name: 'John Doe'
169
- }
80
+ // Simple - just ID
81
+ _encatch.identifyUser('user-123');
82
+
83
+ // With traits
84
+ _encatch.identifyUser('user-123', {
85
+ email: 'user@example.com', // Optional: user's email
86
+ name: 'John Doe', // Optional: user's full name
87
+ plan: 'premium', // Optional: custom traits
88
+ signed_up_at: new Date(), // Optional: date fields (must end with _at or _date)
170
89
  });
171
- ```
172
90
 
173
- ### `stop()`
174
-
175
- Stop the SDK. Behavior depends on initialization:
176
-
177
- - If initialized with `autoStartEnabled: false`: Clears all data, feedbacks, and frequency tracking
178
- - If initialized with `autoStartEnabled: true`: Makes user anonymous but retains feedbacks
179
-
180
- ```javascript
181
- encatch.stop();
182
- ```
183
-
184
- ### `setUser(userId?, traits?)`
185
-
186
- Set or update user identity.
187
-
188
- ```javascript
189
- // Set user identity
190
- encatch.setUser('user-123', {
191
- $set: { email: 'user@example.com', plan: 'premium' },
192
- $set_once: { signup_date: '2024-01-01' },
193
- $counter: { logins: 1 },
194
- $unset: ['temp_property']
195
- });
196
-
197
- // Make user anonymous
198
- encatch.setUser();
199
- ```
200
-
201
- #### User Traits Operators
202
-
203
- - `$set`: Set property value (overwrites existing)
204
- - `$set_once`: Set only if property doesn't exist
205
- - `$counter`: Increment counter by value
206
- - `$unset`: Remove properties (array of property names)
207
-
208
- ### `trackEvent(eventName, properties?)`
209
-
210
- Track custom events for trigger matching.
211
-
212
- ```javascript
213
- encatch.trackEvent('purchase_completed', {
214
- path: '/checkout/success',
215
- product_id: 'prod-123',
216
- amount: 99.99
91
+ // With traits and options
92
+ _encatch.identifyUser('user-123', {
93
+ email: 'user@example.com',
94
+ name: 'John Doe',
95
+ }, {
96
+ locale: 'en', // Optional: user's locale
97
+ country: 'US', // Optional: user's country
217
98
  });
218
99
  ```
219
100
 
220
- ### `openFeedbackById(feedbackConfigId, theme?, language?, event?, customProperties?, prepopulatedAnswers?)`
101
+ ### `setLocale(locale)`
221
102
 
222
- Manually open a feedback form by its configuration ID.
103
+ Set the user's preferred language.
223
104
 
224
105
  ```javascript
225
- // Basic usage
226
- encatch.openFeedbackById('feedback-config-id-123');
227
-
228
- // With theme and language override
229
- encatch.openFeedbackById('feedback-config-id-123', 'dark', 'es');
230
-
231
- // With prepopulated answers
232
- encatch.openFeedbackById('feedback-config-id-123', 'light', 'en', undefined, undefined, [
233
- {
234
- sectionIndex: 0,
235
- questionIndex: 0,
236
- value: { text: 'Pre-filled answer' }
237
- }
238
- ]);
106
+ _encatch.setLocale('fr,en,es'); // Comma-separated ISO 639-1 codes
239
107
  ```
240
108
 
241
- ### `openFeedbackByName(feedbackName, theme?, language?, event?, customProperties?, prepopulatedAnswers?)`
109
+ ### `setCountry(country)`
242
110
 
243
- Manually open a feedback form by its name.
111
+ Set the user's country.
244
112
 
245
113
  ```javascript
246
- encatch.openFeedbackByName('Customer Satisfaction Survey');
247
-
248
- // With options
249
- encatch.openFeedbackByName('NPS Survey', 'dark', 'es');
114
+ _encatch.setCountry('FR'); // ISO 3166 country code
250
115
  ```
251
116
 
252
- ### `setThemeMode(theme)`
117
+ ### `setTheme(theme)`
253
118
 
254
- Change the theme mode dynamically.
119
+ Set the theme. Default is 'system'.
255
120
 
256
121
  ```javascript
257
- encatch.setThemeMode('dark');
258
- encatch.setThemeMode('light');
122
+ _encatch.setTheme('dark'); // 'light', 'dark', or 'system'
123
+ _encatch.setTheme('light');
124
+ _encatch.setTheme('system'); // Follows system preference
259
125
  ```
260
126
 
261
- ### `setLanguage(language)`
127
+ ### `trackEvent(eventName)`
262
128
 
263
- Change the language dynamically.
129
+ Track a custom event.
264
130
 
265
131
  ```javascript
266
- encatch.setLanguage('es'); // Spanish
267
- encatch.setLanguage('fr'); // French
268
- encatch.setLanguage('en'); // English
132
+ _encatch.trackEvent('button_clicked');
133
+ _encatch.trackEvent('purchase_completed');
269
134
  ```
270
135
 
271
- ### `forceFetchEligibleFeedbacks()`
136
+ ### `startSession()`
272
137
 
273
- Force refresh the list of eligible feedbacks.
138
+ Manually start a new session. Useful after user login.
274
139
 
275
140
  ```javascript
276
- await encatch.forceFetchEligibleFeedbacks();
141
+ _encatch.startSession();
277
142
  ```
278
143
 
279
- ### `verifyFeedbackIds(feedbackIds)`
144
+ ### `resetUser()`
280
145
 
281
- Verify which feedback IDs are currently eligible.
146
+ Reset the current user (logout). Reverts the SDK to anonymous mode.
282
147
 
283
148
  ```javascript
284
- const validIds = encatch.verifyFeedbackIds([
285
- 'feedback-id-1',
286
- 'feedback-id-2',
287
- 'feedback-id-3'
288
- ]);
289
- console.log('Valid feedback IDs:', validIds);
149
+ _encatch.resetUser();
290
150
  ```
291
151
 
292
- ### `capturePageScrollEvent(scrollPercent)`
152
+ ### `showForm(formId, force?)`
293
153
 
294
- Manually trigger scroll-based feedback.
154
+ Show a specific form by ID.
295
155
 
296
156
  ```javascript
297
- // Track scroll percentage
298
- window.addEventListener('scroll', () => {
299
- const scrollPercent = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;
300
- encatch.capturePageScrollEvent(`${scrollPercent}%`);
301
- });
157
+ _encatch.showForm('form-abc-123');
158
+ _encatch.showForm('form-abc-123', true); // Force show even if already shown
302
159
  ```
303
160
 
304
- ## Event Tracking
161
+ ### `addToResponse(questionId, value)`
305
162
 
306
- ### Automatic Page Tracking
307
-
308
- The SDK automatically tracks page changes in single-page applications:
163
+ Prepopulate a form response.
309
164
 
310
165
  ```javascript
311
- // Page changes are tracked automatically
312
- // Triggers "pageLoad" event for configured triggers
166
+ _encatch.addToResponse('question-1', 'Pre-filled answer');
313
167
  ```
314
168
 
315
- ### Custom Events
169
+ ### `on(event, callback)`
316
170
 
317
- Track custom events for business logic:
171
+ Subscribe to SDK events. Returns an unsubscribe function.
318
172
 
319
173
  ```javascript
320
- // E-commerce example
321
- encatch.trackEvent('product_viewed', {
322
- path: '/products/123',
323
- category: 'electronics',
324
- price: 299.99
174
+ const unsubscribe = _encatch.on('form:submit', (payload) => {
175
+ console.log('Form submitted:', payload);
325
176
  });
326
177
 
327
- encatch.trackEvent('add_to_cart', {
328
- path: '/products/123',
329
- product_id: 'prod-123'
330
- });
331
-
332
- encatch.trackEvent('checkout_started', {
333
- path: '/checkout',
334
- cart_value: 599.98
335
- });
178
+ // Later, to unsubscribe:
179
+ unsubscribe();
336
180
  ```
337
181
 
338
- ### Scroll Tracking
339
-
340
- ```javascript
341
- // Automatic scroll tracking (if configured in feedback triggers)
342
- // Or manual tracking:
343
- let scrollTriggered = false;
182
+ ### `off(event, callback)`
344
183
 
345
- window.addEventListener('scroll', () => {
346
- const scrollPercent = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;
347
-
348
- if (scrollPercent > 50 && !scrollTriggered) {
349
- encatch.capturePageScrollEvent('50%');
350
- scrollTriggered = true;
351
- }
352
- });
353
- ```
354
-
355
- ## Advanced Usage
356
-
357
- ### Prepopulated Answers
358
-
359
- Pre-fill feedback forms with known data:
184
+ Unsubscribe from SDK events.
360
185
 
361
186
  ```javascript
362
- encatch.openFeedbackById('feedback-config-id', 'light', 'en', undefined, undefined, [
363
- {
364
- sectionIndex: 0, // First section
365
- questionIndex: 0, // First question
366
- value: { text: 'Pre-filled text answer' }
367
- },
368
- {
369
- sectionIndex: 0,
370
- questionIndex: 1,
371
- value: { rating: 5 }
372
- }
373
- ]);
374
- ```
375
-
376
- ### Custom Properties for Targeting
377
-
378
- Pass custom properties for advanced targeting:
379
-
380
- ```javascript
381
- encatch.openFeedbackById(
382
- 'feedback-config-id',
383
- 'light',
384
- 'en',
385
- undefined,
386
- {
387
- user_segment: 'premium',
388
- feature_flag: 'beta_features',
389
- experiment_group: 'variant_a'
390
- }
391
- );
392
- ```
393
-
394
- ### Session Management
395
-
396
- ```javascript
397
- // Disable automatic session management
398
- encatch.init('YOUR_API_KEY', {
399
- host: 'https://your-host.com',
400
- autoStartSessionDisabled: false
401
- });
402
-
403
- // Manual session control (when autoStartSessionDisabled: false)
404
- encatch.start(); // Start a new session
405
- encatch.stop(); // End current session
406
- ```
407
-
408
- ### Dynamic Theme Switching
409
-
410
- ```javascript
411
- // Listen to system theme changes
412
- const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
413
-
414
- darkModeQuery.addEventListener('change', (e) => {
415
- encatch.setThemeMode(e.matches ? 'dark' : 'light');
416
- });
417
-
418
- // Or use a theme toggle
419
- function toggleTheme() {
420
- const currentTheme = getCurrentTheme(); // Your theme logic
421
- encatch.setThemeMode(currentTheme === 'dark' ? 'light' : 'dark');
422
- }
423
- ```
424
-
425
- ### Custom CSS Styling
426
-
427
- ```javascript
428
- // Option 1: Provide custom CSS URL during initialization
429
- encatch.init('YOUR_API_KEY', {
430
- host: 'https://your-host.com',
431
- customCssLink: 'https://your-cdn.com/custom-encatch-theme.css'
432
- });
433
-
434
- // Option 2: Configure custom CSS per feedback in the Encatch dashboard
435
- ```
436
-
437
- ### Conditional Feedback Display
438
-
439
- ```javascript
440
- // Only show feedback to premium users
441
- if (user.plan === 'premium') {
442
- encatch.openFeedbackById('premium-user-feedback');
187
+ function handleSubmit(payload) {
188
+ console.log('Form submitted:', payload);
443
189
  }
444
190
 
445
- // Show different feedback based on user journey
446
- if (isNewUser) {
447
- encatch.openFeedbackByName('Onboarding Feedback');
448
- } else {
449
- encatch.openFeedbackByName('Feature Usage Survey');
450
- }
451
- ```
452
-
453
- ## Form Event Listeners
454
-
455
- The SDK provides two approaches for listening to feedback form events: **config-based** and **runtime-based**.
456
-
457
- ### Available Form Events
458
-
459
- | Event | Payload | Description |
460
- |-------|---------|-------------|
461
- | `form:submit` | `{ feedbackIdentifier: string, feedbackConfigurationId: string, completionTimeInSeconds: number, response: Object }` | Emitted when the user completes and submits the feedback form |
462
- | `form:view` | `{ feedbackIdentifier: string, feedbackConfigurationId: string }` | Emitted when the feedback form is displayed to the user |
463
- | `form:close` | `{ feedbackIdentifier: string, feedbackConfigurationId: string }` | Emitted when the user closes the feedback form (with or without submitting) |
464
- | `form:questionAnswered` | `{ questionId: string, answer: Object }` | Emitted when the user answers a question |
465
- | `form:sectionChange` | `{ sectionIndex: number }` | Emitted when the user navigates to a different section |
466
- | `form:error` | `{ error: string }` | Emitted when an error occurs during form interaction |
467
-
468
- ### Approach 1: Config-Based (Recommended)
469
-
470
- Define event handlers during SDK initialization using the `onFormEvent` callback:
471
-
472
- ```javascript
473
- encatch.init('YOUR_API_KEY', {
474
- host: 'https://your-host.com',
475
- autoStartEnabled: true,
476
- onFormEvent: (formEvent) => {
477
- // Listen to form submission
478
- formEvent.onSubmit((data) => {
479
- console.log('Form submitted:', data);
480
- console.log('Feedback ID:', data.feedbackIdentifier);
481
- console.log('Config ID:', data.feedbackConfigurationId);
482
- console.log('Completion time:', data.completionTimeInSeconds);
483
-
484
- // Send to analytics
485
- analytics.track('Feedback Submitted', {
486
- feedbackId: data.feedbackIdentifier,
487
- configId: data.feedbackConfigurationId
488
- });
489
- });
490
-
491
- // Listen to form view
492
- formEvent.onView((data) => {
493
- console.log('Form viewed:', data);
494
- });
495
-
496
- // Listen to form close
497
- formEvent.onClose((data) => {
498
- console.log('Form closed:', data);
499
- });
500
-
501
- // Listen to question answered
502
- formEvent.onQuestionAnswered((data) => {
503
- console.log('Question answered:', data.questionId, data.answer);
504
- });
505
-
506
- // Listen to section change
507
- formEvent.onSectionChange((data) => {
508
- console.log('Section changed to:', data.sectionIndex);
509
- });
510
-
511
- // Listen to errors
512
- formEvent.onError((data) => {
513
- console.error('Form error:', data.error);
514
- });
515
- }
516
- });
517
- ```
518
-
519
- ### Approach 2: Runtime-Based
520
-
521
- Subscribe to events at runtime using the `encatch.on()` method:
522
-
523
- ```javascript
524
- // Subscribe to form submission
525
- const unsubscribeSubmit = encatch.on('form:submit', (data) => {
526
- console.log('Form submitted:', data);
527
- alert(`Feedback submitted! ID: ${data.feedbackIdentifier}`);
528
- });
529
-
530
- // Subscribe to form view
531
- const unsubscribeView = encatch.on('form:view', (data) => {
532
- console.log('Form viewed:', data);
533
- });
534
-
535
- // Subscribe to form close
536
- const unsubscribeClose = encatch.on('form:close', (data) => {
537
- console.log('Form closed:', data);
538
- });
539
-
540
- // Subscribe to question answered
541
- const unsubscribeQuestion = encatch.on('form:questionAnswered', (data) => {
542
- console.log('Question answered:', data);
543
- });
544
-
545
- // Subscribe to section change
546
- const unsubscribeSection = encatch.on('form:sectionChange', (data) => {
547
- console.log('Section changed:', data);
548
- });
549
-
550
- // Subscribe to errors
551
- const unsubscribeError = encatch.on('form:error', (data) => {
552
- console.error('Form error:', data);
553
- });
554
-
555
- // Unsubscribe when no longer needed
556
- unsubscribeSubmit();
557
- unsubscribeView();
558
- ```
559
-
560
- ### Integration Examples
561
-
562
- #### Google Analytics Integration
563
-
564
- ```javascript
565
- encatch.init('YOUR_API_KEY', {
566
- host: 'https://your-host.com',
567
- autoStartEnabled: true,
568
- onFormEvent: (formEvent) => {
569
- formEvent.onView((data) => {
570
- gtag('event', 'feedback_viewed', {
571
- feedback_id: data.feedbackIdentifier,
572
- config_id: data.feedbackConfigurationId
573
- });
574
- });
575
-
576
- formEvent.onSubmit((data) => {
577
- gtag('event', 'feedback_submitted', {
578
- feedback_id: data.feedbackIdentifier,
579
- config_id: data.feedbackConfigurationId,
580
- completion_time: data.completionTimeInSeconds
581
- });
582
- });
583
-
584
- formEvent.onClose((data) => {
585
- gtag('event', 'feedback_closed', {
586
- feedback_id: data.feedbackIdentifier
587
- });
588
- });
589
- }
590
- });
591
- ```
191
+ _encatch.on('form:submit', handleSubmit);
592
192
 
593
- #### Segment Analytics Integration
594
-
595
- ```javascript
596
- encatch.init('YOUR_API_KEY', {
597
- host: 'https://your-host.com',
598
- autoStartEnabled: true,
599
- onFormEvent: (formEvent) => {
600
- formEvent.onSubmit((data) => {
601
- analytics.track('Feedback Completed', {
602
- feedbackId: data.feedbackIdentifier,
603
- configId: data.feedbackConfigurationId,
604
- duration: data.completionTimeInSeconds
605
- });
606
- });
607
-
608
- formEvent.onQuestionAnswered((data) => {
609
- analytics.track('Question Answered', {
610
- questionId: data.questionId,
611
- answerType: data.answer.answer_type
612
- });
613
- });
614
- }
615
- });
193
+ // Later:
194
+ _encatch.off('form:submit', handleSubmit);
616
195
  ```
617
196
 
618
- #### Custom Data Layer (GTM)
197
+ ## Event Types
619
198
 
620
- ```javascript
621
- encatch.init('YOUR_API_KEY', {
622
- host: 'https://your-host.com',
623
- autoStartEnabled: true,
624
- onFormEvent: (formEvent) => {
625
- formEvent.onSubmit((data) => {
626
- window.dataLayer = window.dataLayer || [];
627
- window.dataLayer.push({
628
- event: 'feedback_submitted',
629
- feedbackId: data.feedbackIdentifier,
630
- configId: data.feedbackConfigurationId,
631
- completionTime: data.completionTimeInSeconds
632
- });
633
- });
634
- }
635
- });
636
- ```
637
-
638
- #### CRM Integration (e.g., Salesforce, HubSpot)
639
-
640
- ```javascript
641
- encatch.init('YOUR_API_KEY', {
642
- host: 'https://your-host.com',
643
- autoStartEnabled: true,
644
- onFormEvent: (formEvent) => {
645
- formEvent.onSubmit(async (data) => {
646
- // Send to your CRM
647
- await fetch('https://your-crm.com/api/feedback', {
648
- method: 'POST',
649
- headers: { 'Content-Type': 'application/json' },
650
- body: JSON.stringify({
651
- feedbackId: data.feedbackIdentifier,
652
- userId: window.currentUserId,
653
- response: data.response,
654
- timestamp: new Date().toISOString()
655
- })
656
- });
657
- });
658
- }
659
- });
660
- ```
199
+ | Event | Description |
200
+ |-------|-------------|
201
+ | `form:show` | Fired when a form is displayed |
202
+ | `form:submit` | Fired when a form is submitted |
203
+ | `form:close` | Fired when a form is closed |
204
+ | `form:complete` | Fired when a form is completed |
205
+ | `form:error` | Fired when an error occurs |
661
206
 
662
207
  ## TypeScript Support
663
208
 
664
- The SDK is fully typed. TypeScript definitions are included:
209
+ The SDK is written in TypeScript and includes full type definitions.
665
210
 
666
211
  ```typescript
667
- import '@encatch/web-sdk';
668
-
669
- // All methods are typed
670
- encatch.init('YOUR_API_KEY', {
671
- host: 'https://your-host.com',
672
- autoStartEnabled: true,
673
- themeMode: 'light', // Type: 'light' | 'dark'
674
- language: 'en'
675
- });
676
-
677
- // User traits are typed
678
- encatch.setUser('user-123', {
679
- $set: { email: 'user@example.com' },
680
- $set_once: { signup_date: '2024-01-01' },
681
- $counter: { logins: 1 },
682
- $unset: ['temp_field']
683
- });
684
-
685
- // Event properties are typed
686
- encatch.trackEvent('custom_event', {
687
- path: '/page',
688
- event: 'click'
689
- });
690
- ```
212
+ import { _encatch, UserTraits, EncatchConfig, EventType } from '@encatch/web-sdk';
691
213
 
692
- ## Development
693
-
694
- ### Prerequisites
695
-
696
- - Node.js 18+
697
- - pnpm
698
-
699
- ### Setup
700
-
701
- ```bash
702
- # Install dependencies
703
- pnpm install
704
-
705
- # Start development server
706
- pnpm dev
214
+ // Example with $set operation
215
+ const userTraits: UserTraits = {
216
+ $set: {
217
+ email: 'user@example.com',
218
+ name: 'John Doe',
219
+ customField: 'value',
220
+ },
221
+ };
707
222
 
708
- # Build for production
709
- pnpm build
223
+ _encatch.identifyUser('user-123', userTraits);
710
224
 
711
- # Preview production build
712
- pnpm preview
225
+ // Example with multiple operations
226
+ const userTraitsAdvanced: UserTraits = {
227
+ $set: { email: 'user@example.com', name: 'John Doe' },
228
+ $setOnce: { firstSeenAt: new Date() },
229
+ $increment: { loginCount: 1 },
230
+ $unset: ['oldField'],
231
+ };
713
232
  ```
714
233
 
715
- ### Project Structure
234
+ ## How It Works
716
235
 
717
- ```
718
- packages/web-sdk/
719
- ├── src/
720
- │ ├── @types/ # TypeScript type definitions
721
- │ ├── hooks/ # Preact hooks for functionality
722
- │ ├── utils/ # Utility functions
723
- │ ├── index.tsx # Main SDK initialization
724
- │ ├── core-wrapper.tsx # Core SDK logic
725
- │ └── surveySDK.ts # Event SDK
726
- ├── dist-sdk/ # Build output
727
- ├── package.json
728
- ├── vite.config.ts # Vite configuration
729
- └── README.md
730
- ```
731
-
732
- ### Build Output
236
+ The SDK uses a "stub + async loader" pattern:
733
237
 
734
- The build produces:
238
+ 1. The lightweight stub is loaded immediately and exposes the `_encatch` object
239
+ 2. All method calls are queued in an internal array
240
+ 3. When `init()` is called, the full implementation script is loaded from the CDN
241
+ 4. Once loaded, the queued commands are processed in order
242
+ 5. Future calls go directly to the real implementation
735
243
 
736
- - `encatch-web-sdk.js` - Main SDK bundle
737
- - `encatch-web-sdk.css` - Default styles
738
- - `preview-sdk.js` - Preview/demo version
739
- - `embedded-sdk.js` - Embedded version
244
+ This pattern ensures:
245
+ - Fast initial page load (tiny stub)
246
+ - No lost commands (queue preserves all calls)
247
+ - Type safety (full TypeScript definitions)
740
248
 
741
249
  ## Browser Support
742
250
 
743
- - Chrome 62+
744
- - Firefox 59+
745
- - Safari 12+
746
- - iOS Safari 10.3+
747
- - Opera 50+
748
- - Edge (Chromium-based)
251
+ - Chrome 80+
252
+ - Firefox 75+
253
+ - Safari 13.1+
254
+ - Edge 80+
749
255
 
750
256
  ## License
751
257
 
752
- Private - Copyright (c) Encatch
753
-
754
- ## Support
755
-
756
- For issues, questions, or feature requests, please contact your Encatch account manager or visit the [Encatch Dashboard](https://app.encatch.com).
258
+ MIT