@product7/feedback-sdk 1.6.5 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@product7/feedback-sdk",
3
- "version": "1.6.5",
3
+ "version": "1.6.7",
4
4
  "description": "JavaScript SDK for integrating Product7 feedback widgets into any website",
5
5
  "main": "dist/feedback-sdk.js",
6
6
  "module": "src/index.js",
@@ -1,4 +1,4 @@
1
- import { MOCK_CHANGELOGS } from '../mock-data';
1
+ import { MOCK_CHANGELOGS } from '../mock-data/index.js';
2
2
  import { delay } from '../utils/helpers.js';
3
3
 
4
4
  export class ChangelogService {
@@ -1,4 +1,4 @@
1
- import { MOCK_HELP_COLLECTIONS } from '../mock-data';
1
+ import { MOCK_HELP_COLLECTIONS } from '../mock-data/index.js';
2
2
  import { delay } from '../utils/helpers.js';
3
3
 
4
4
  export class HelpService {
@@ -1,4 +1,4 @@
1
- import { MOCK_CONVERSATIONS, MOCK_MESSAGES } from '../mock-data';
1
+ import { MOCK_CONVERSATIONS, MOCK_MESSAGES } from '../mock-data/index.js';
2
2
  import { delay } from '../utils/helpers.js';
3
3
 
4
4
  export class MessengerService {
@@ -1,5 +1,5 @@
1
1
  import { APIError } from '../../utils/errors.js';
2
- import { MOCK_SURVEYS } from '../mock-data';
2
+ import { MOCK_SURVEYS } from '../mock-data/index.js';
3
3
  import { delay, getDeviceInfo } from '../utils/helpers.js';
4
4
 
5
5
  export class SurveyService {
@@ -90,15 +90,19 @@ export class BaseAPIService {
90
90
  body: JSON.stringify(payload),
91
91
  headers: { 'Content-Type': 'application/json' },
92
92
  });
93
+ const initData = this._extractInitResponseData(response);
93
94
 
94
- this.sessionToken = response.session_token;
95
- this.sessionExpiry = new Date(Date.now() + response.expires_in * 1000);
95
+ this.sessionToken = initData.sessionToken;
96
+ this.sessionExpiry = new Date(Date.now() + initData.expiresIn * 1000);
96
97
  this._storeSession();
97
98
 
98
99
  return {
99
100
  sessionToken: this.sessionToken,
100
- config: response.config || {},
101
- expiresIn: response.expires_in,
101
+ config: initData.config,
102
+ expiresIn: initData.expiresIn,
103
+ status: initData.status,
104
+ message: initData.message,
105
+ configVersion: initData.configVersion,
102
106
  };
103
107
  } catch (error) {
104
108
  throw new APIError(
@@ -109,6 +113,34 @@ export class BaseAPIService {
109
113
  }
110
114
  }
111
115
 
116
+ _extractInitResponseData(response) {
117
+ const payload =
118
+ response && typeof response.data === 'object' ? response.data : response || {};
119
+
120
+ const sessionToken = payload.session_token || payload.sessionToken;
121
+ const expiresIn = Number(payload.expires_in ?? payload.expiresIn);
122
+
123
+ if (!sessionToken) {
124
+ throw new APIError(500, 'Invalid init response: missing session_token');
125
+ }
126
+
127
+ if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
128
+ throw new APIError(500, 'Invalid init response: missing expires_in');
129
+ }
130
+
131
+ return {
132
+ sessionToken,
133
+ expiresIn,
134
+ config:
135
+ payload.config && typeof payload.config === 'object'
136
+ ? payload.config
137
+ : {},
138
+ configVersion: payload.config_version ?? payload.configVersion ?? null,
139
+ status: response?.status ?? payload?.status ?? true,
140
+ message: response?.message ?? payload?.message ?? null,
141
+ };
142
+ }
143
+
112
144
  async _ensureSession() {
113
145
  if (!this.isSessionValid()) {
114
146
  await this.init();
@@ -65,6 +65,10 @@ export class FeedbackSDK {
65
65
  const widgetId = generateId('widget');
66
66
  const widgetConfig = this._getWidgetTypeConfig(type);
67
67
  const explicitOptions = this._omitUndefined(options);
68
+ const widgetEnabled = this._isWidgetEnabled(type, {
69
+ ...widgetConfig,
70
+ ...explicitOptions,
71
+ });
68
72
  const widgetOptions = {
69
73
  id: widgetId,
70
74
  sdk: this,
@@ -72,6 +76,7 @@ export class FeedbackSDK {
72
76
  ...this.config,
73
77
  ...widgetConfig,
74
78
  ...explicitOptions,
79
+ enabled: widgetEnabled,
75
80
  };
76
81
 
77
82
  try {
@@ -162,6 +167,7 @@ export class FeedbackSDK {
162
167
  surveyConfig.showDescription ?? surveyConfig.show_description,
163
168
  customQuestions: surveyConfig.customQuestions || surveyConfig.questions,
164
169
  pages: surveyConfig.pages,
170
+ enabled: surveyConfig.enabled,
165
171
  ...displayOptions,
166
172
  });
167
173
  }
@@ -184,6 +190,17 @@ export class FeedbackSDK {
184
190
 
185
191
  const normalizedOptions = this._normalizeSurveyConfig(options);
186
192
  const surveyConfigDefaults = this._getWidgetTypeConfig('survey');
193
+ const surveyEnabled = this._isWidgetEnabled('survey', normalizedOptions);
194
+
195
+ if (!surveyEnabled) {
196
+ this.eventBus.emit('survey:suppressed', {
197
+ surveyId:
198
+ normalizedOptions.surveyId || normalizedOptions.id || options.id || null,
199
+ reason: 'disabled',
200
+ survey: normalizedOptions,
201
+ });
202
+ return null;
203
+ }
187
204
 
188
205
  const surveyWidget = this.createWidget('survey', {
189
206
  surveyId: normalizedOptions.surveyId,
@@ -215,6 +232,7 @@ export class FeedbackSDK {
215
232
  email: normalizedOptions.email,
216
233
  onSubmit: normalizedOptions.onSubmit,
217
234
  onDismiss: normalizedOptions.onDismiss,
235
+ enabled: surveyEnabled,
218
236
  });
219
237
 
220
238
  surveyWidget.mount();
@@ -308,13 +326,19 @@ export class FeedbackSDK {
308
326
  : {};
309
327
 
310
328
  const inferredType =
311
- survey.type || this._inferSurveyTypeFromPage(firstPage) || 'nps';
329
+ survey.surveyType ||
330
+ survey.survey_type ||
331
+ survey.type ||
332
+ this._inferSurveyTypeFromPage(firstPage) ||
333
+ 'nps';
312
334
 
313
335
  return {
314
336
  ...survey,
315
- surveyId: survey.surveyId || survey.id || null,
316
- surveyType: survey.surveyType || inferredType,
317
- type: survey.type || inferredType,
337
+ surveyId: survey.surveyId || survey.survey_id || survey.id || null,
338
+ surveyType: survey.surveyType || survey.survey_type || inferredType,
339
+ type: survey.type || survey.survey_type || inferredType,
340
+ enabled:
341
+ typeof survey.enabled === 'boolean' ? survey.enabled : undefined,
318
342
  should_show:
319
343
  survey.should_show ??
320
344
  (survey.eligibility ? survey.eligibility.should_show : undefined),
@@ -343,7 +367,11 @@ export class FeedbackSDK {
343
367
  showTitle: survey.showTitle ?? survey.show_title ?? null,
344
368
  showDescription:
345
369
  survey.showDescription ?? survey.show_description ?? null,
346
- customQuestions: survey.customQuestions || survey.questions || [],
370
+ customQuestions:
371
+ survey.customQuestions ||
372
+ survey.custom_questions ||
373
+ survey.questions ||
374
+ [],
347
375
  pages: this._normalizeSurveyPages(survey.pages || []),
348
376
  };
349
377
  }
@@ -418,6 +446,23 @@ export class FeedbackSDK {
418
446
  return this._toCamelCaseObject(mergedTypeConfig);
419
447
  }
420
448
 
449
+ _isWidgetEnabled(type, options = {}) {
450
+ const typeConfig = this._getWidgetTypeConfig(type);
451
+ if (typeConfig.enabled === false) {
452
+ return false;
453
+ }
454
+
455
+ if (typeof options.enabled === 'boolean') {
456
+ return options.enabled;
457
+ }
458
+
459
+ if (typeof typeConfig.enabled === 'boolean') {
460
+ return typeConfig.enabled;
461
+ }
462
+
463
+ return true;
464
+ }
465
+
421
466
  _isPlainObject(value) {
422
467
  return Object.prototype.toString.call(value) === '[object Object]';
423
468
  }
@@ -471,11 +516,21 @@ export class FeedbackSDK {
471
516
 
472
517
  const configDefaults = this._getWidgetTypeConfig('changelog');
473
518
  const explicitOptions = this._omitUndefined(options);
519
+ const changelogEnabled = this._isWidgetEnabled('changelog', explicitOptions);
520
+
521
+ if (!changelogEnabled) {
522
+ this.eventBus.emit('widget:suppressed', {
523
+ type: 'changelog',
524
+ reason: 'disabled',
525
+ });
526
+ return null;
527
+ }
474
528
 
475
529
  const changelogWidget = this.createWidget('changelog', {
476
530
  ...defaults,
477
531
  ...configDefaults,
478
532
  ...explicitOptions,
533
+ enabled: changelogEnabled,
479
534
  });
480
535
 
481
536
  changelogWidget.mount();
@@ -48,6 +48,15 @@ export class BaseWidget {
48
48
  mount(container) {
49
49
  if (this.mounted || this.destroyed) return this;
50
50
 
51
+ if (this.options.enabled === false) {
52
+ this.sdk.eventBus.emit('widget:suppressed', {
53
+ widget: this,
54
+ type: this.type,
55
+ reason: 'disabled',
56
+ });
57
+ return this;
58
+ }
59
+
51
60
  if (this.options.suppressAfterSubmission && this._hasRecentlySubmitted()) {
52
61
  this.sdk.eventBus.emit('widget:suppressed', {
53
62
  widget: this,
@@ -18,6 +18,11 @@ export class MessengerWidget extends BaseWidget {
18
18
  constructor(options) {
19
19
  super({ ...options, type: 'messenger' });
20
20
 
21
+ const resolvedEnableChangelog =
22
+ typeof options.enableChangelog === 'boolean'
23
+ ? options.enableChangelog
24
+ : options.enableNews !== false;
25
+
21
26
  this.messengerOptions = {
22
27
  position: options.position || 'bottom-right',
23
28
  theme: options.theme || 'light',
@@ -30,7 +35,10 @@ export class MessengerWidget extends BaseWidget {
30
35
  greetingMessage: options.greetingMessage || 'Hi there 👋',
31
36
  welcomeMessage: options.welcomeMessage || 'How can we help?',
32
37
  enableHelp: options.enableHelp !== false,
33
- enableChangelog: options.enableChangelog !== false,
38
+ enableChangelog: resolvedEnableChangelog,
39
+ autoLoadData: options.autoLoadData !== false,
40
+ initialView: options.initialView || 'home',
41
+ previewData: options.previewData || null,
34
42
  featuredContent: options.featuredContent || null,
35
43
  feedbackUrl: options.feedbackUrl || null,
36
44
  changelogUrl: options.changelogUrl || null,
@@ -498,6 +506,51 @@ export class MessengerWidget extends BaseWidget {
498
506
  };
499
507
  }
500
508
 
509
+ _applyPreviewData() {
510
+ const data = this.messengerOptions.previewData;
511
+ if (!data || typeof data !== 'object') {
512
+ return;
513
+ }
514
+
515
+ if (Array.isArray(data.conversations)) {
516
+ this.messengerState.setConversations(data.conversations);
517
+ }
518
+
519
+ if (Array.isArray(data.helpArticles)) {
520
+ this.messengerState.setHelpArticles(data.helpArticles);
521
+ }
522
+
523
+ if (Array.isArray(data.homeChangelogItems)) {
524
+ this.messengerState.setHomeChangelogItems(data.homeChangelogItems);
525
+ }
526
+
527
+ if (Array.isArray(data.changelogItems)) {
528
+ this.messengerState.setChangelogItems(data.changelogItems);
529
+ }
530
+
531
+ if (typeof data.unreadCount === 'number') {
532
+ this.setUnreadCount(data.unreadCount);
533
+ }
534
+
535
+ if (data.availability && typeof data.availability === 'object') {
536
+ const availability = data.availability;
537
+ this.messengerState.agentsOnline = Boolean(
538
+ availability.agentsOnline ?? availability.agents_online
539
+ );
540
+ this.messengerState.onlineCount =
541
+ availability.onlineCount ?? availability.online_count ?? 0;
542
+ this.messengerState.responseTime =
543
+ availability.responseTime ??
544
+ availability.response_time ??
545
+ this.messengerState.responseTime;
546
+ this.messengerState._notify('availabilityUpdate', availability);
547
+ }
548
+
549
+ if (typeof data.currentView === 'string') {
550
+ this.messengerState.setView(data.currentView);
551
+ }
552
+ }
553
+
501
554
  async loadInitialData() {
502
555
  try {
503
556
  const conversations = await this._fetchConversations();
@@ -824,17 +877,28 @@ export class MessengerWidget extends BaseWidget {
824
877
  }
825
878
 
826
879
  async onMount() {
827
- this.loadInitialData();
880
+ this._applyPreviewData();
828
881
 
829
- if (this.apiService?.sessionToken) {
830
- this._initWebSocket();
831
- }
882
+ if (this.messengerOptions.autoLoadData) {
883
+ this.loadInitialData();
832
884
 
833
- this.checkAgentAvailability();
885
+ if (this.apiService?.sessionToken) {
886
+ this._initWebSocket();
887
+ }
834
888
 
835
- this._availabilityInterval = setInterval(() => {
836
889
  this.checkAgentAvailability();
837
- }, 60000);
890
+
891
+ this._availabilityInterval = setInterval(() => {
892
+ this.checkAgentAvailability();
893
+ }, 60000);
894
+ }
895
+
896
+ if (
897
+ this.messengerOptions.initialView &&
898
+ this.messengerOptions.initialView !== this.messengerState.currentView
899
+ ) {
900
+ this.messengerState.setView(this.messengerOptions.initialView);
901
+ }
838
902
  }
839
903
 
840
904
  onDestroy() {
@@ -8,6 +8,8 @@ export class SurveyWidget extends BaseWidget {
8
8
  surveyId: options.surveyId || null,
9
9
  surveyType: options.surveyType || 'nps',
10
10
  position: options.position || 'bottom-right',
11
+ enabled:
12
+ typeof options.enabled === 'boolean' ? options.enabled : undefined,
11
13
  title: options.title || null,
12
14
  description: options.description || null,
13
15
  lowLabel: options.lowLabel || null,
@@ -61,6 +63,15 @@ export class SurveyWidget extends BaseWidget {
61
63
  }
62
64
 
63
65
  show() {
66
+ if (this.options.enabled === false || this.surveyOptions.enabled === false) {
67
+ this.sdk.eventBus.emit('survey:suppressed', {
68
+ widget: this,
69
+ surveyId: this.surveyOptions.surveyId,
70
+ reason: 'disabled',
71
+ });
72
+ return this;
73
+ }
74
+
64
75
  this._renderSurvey();
65
76
  this.surveyState.isVisible = true;
66
77
  this.sdk.eventBus.emit('survey:shown', {
package/types/index.d.ts CHANGED
@@ -4,10 +4,14 @@ declare module '@product7/feedback-sdk' {
4
4
  userContext?: UserContext;
5
5
  debug?: boolean;
6
6
  boardId?: string;
7
+ siteId?: string;
8
+ sessionToken?: string;
7
9
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
8
10
  theme?: 'light' | 'dark';
9
11
  apiUrl?: string;
10
12
  autoShow?: boolean;
13
+ mock?: boolean;
14
+ env?: string;
11
15
  widgets?: WidgetConfigMap;
12
16
  }
13
17
 
@@ -24,6 +28,7 @@ declare module '@product7/feedback-sdk' {
24
28
  }
25
29
 
26
30
  export interface ButtonWidgetOptions {
31
+ enabled?: boolean;
27
32
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
28
33
  theme?: 'light' | 'dark';
29
34
  boardId?: string;
@@ -74,6 +79,9 @@ declare module '@product7/feedback-sdk' {
74
79
  config?: any;
75
80
  sessionToken?: string;
76
81
  expiresIn?: number;
82
+ status?: boolean;
83
+ message?: string | null;
84
+ configVersion?: number | null;
77
85
  }>;
78
86
  createWidget(type: 'button', options?: ButtonWidgetOptions): ButtonWidget;
79
87
  createWidget(type: 'survey', options?: SurveyWidgetOptions): SurveyWidget;
@@ -148,6 +156,7 @@ declare module '@product7/feedback-sdk' {
148
156
  }
149
157
 
150
158
  export interface SurveyWidgetOptions {
159
+ enabled?: boolean;
151
160
  surveyId?: string | null;
152
161
  surveyType?: SurveyType;
153
162
  position?: 'bottom-right' | 'bottom-left' | 'center' | 'bottom';
@@ -221,6 +230,7 @@ declare module '@product7/feedback-sdk' {
221
230
  }
222
231
 
223
232
  export interface ChangelogWidgetOptions {
233
+ enabled?: boolean;
224
234
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
225
235
  theme?: 'light' | 'dark';
226
236
  triggerText?: string;
@@ -250,6 +260,7 @@ declare module '@product7/feedback-sdk' {
250
260
  }
251
261
 
252
262
  export interface MessengerWidgetOptions {
263
+ enabled?: boolean;
253
264
  position?: 'bottom-right' | 'bottom-left';
254
265
  theme?: 'light' | 'dark';
255
266
  teamName?: string;
@@ -258,6 +269,25 @@ declare module '@product7/feedback-sdk' {
258
269
  welcomeMessage?: string;
259
270
  enableHelp?: boolean;
260
271
  enableChangelog?: boolean;
272
+ enableNews?: boolean;
273
+ autoLoadData?: boolean;
274
+ initialView?: 'home' | 'messages' | 'chat' | 'prechat' | 'help' | 'changelog';
275
+ previewData?: {
276
+ conversations?: any[];
277
+ helpArticles?: any[];
278
+ homeChangelogItems?: any[];
279
+ changelogItems?: any[];
280
+ unreadCount?: number;
281
+ currentView?: string;
282
+ availability?: {
283
+ agentsOnline?: boolean;
284
+ agents_online?: boolean;
285
+ onlineCount?: number;
286
+ online_count?: number;
287
+ responseTime?: string;
288
+ response_time?: string;
289
+ };
290
+ };
261
291
  logoUrl?: string;
262
292
  primaryColor?: string;
263
293
  featuredContent?: {