@product7/feedback-sdk 1.6.4 → 1.6.6

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.4",
3
+ "version": "1.6.6",
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",
@@ -63,12 +63,15 @@ export class FeedbackSDK {
63
63
  }
64
64
 
65
65
  const widgetId = generateId('widget');
66
+ const widgetConfig = this._getWidgetTypeConfig(type);
67
+ const explicitOptions = this._omitUndefined(options);
66
68
  const widgetOptions = {
67
69
  id: widgetId,
68
70
  sdk: this,
69
71
  apiService: this.apiService,
70
72
  ...this.config,
71
- ...options,
73
+ ...widgetConfig,
74
+ ...explicitOptions,
72
75
  };
73
76
 
74
77
  try {
@@ -180,13 +183,22 @@ export class FeedbackSDK {
180
183
  }
181
184
 
182
185
  const normalizedOptions = this._normalizeSurveyConfig(options);
186
+ const surveyConfigDefaults = this._getWidgetTypeConfig('survey');
183
187
 
184
188
  const surveyWidget = this.createWidget('survey', {
185
189
  surveyId: normalizedOptions.surveyId,
186
190
  surveyType:
187
191
  normalizedOptions.surveyType || normalizedOptions.type || 'nps',
188
- position: normalizedOptions.position || 'bottom-right',
189
- theme: normalizedOptions.theme || this.config.theme || 'light',
192
+ position:
193
+ normalizedOptions.position ??
194
+ surveyConfigDefaults.position ??
195
+ this.config.position ??
196
+ 'bottom-right',
197
+ theme:
198
+ normalizedOptions.theme ??
199
+ surveyConfigDefaults.theme ??
200
+ this.config.theme ??
201
+ 'light',
190
202
  title: normalizedOptions.title,
191
203
  description: normalizedOptions.description,
192
204
  lowLabel: normalizedOptions.lowLabel,
@@ -389,6 +401,58 @@ export class FeedbackSDK {
389
401
  return null;
390
402
  }
391
403
 
404
+ _getWidgetTypeConfig(type) {
405
+ const widgetsConfig = this._isPlainObject(this.config?.widgets)
406
+ ? this.config.widgets
407
+ : {};
408
+
409
+ const legacyTypeConfig = this._isPlainObject(this.config?.[type])
410
+ ? this.config[type]
411
+ : {};
412
+
413
+ const namespacedTypeConfig = this._isPlainObject(widgetsConfig?.[type])
414
+ ? widgetsConfig[type]
415
+ : {};
416
+
417
+ const mergedTypeConfig = deepMerge(legacyTypeConfig, namespacedTypeConfig);
418
+ return this._toCamelCaseObject(mergedTypeConfig);
419
+ }
420
+
421
+ _isPlainObject(value) {
422
+ return Object.prototype.toString.call(value) === '[object Object]';
423
+ }
424
+
425
+ _toCamelCaseKey(key) {
426
+ return key.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
427
+ }
428
+
429
+ _toCamelCaseObject(value) {
430
+ if (Array.isArray(value)) {
431
+ return value.map((item) => this._toCamelCaseObject(item));
432
+ }
433
+
434
+ if (!this._isPlainObject(value)) {
435
+ return value;
436
+ }
437
+
438
+ const normalized = {};
439
+ for (const [key, nestedValue] of Object.entries(value)) {
440
+ normalized[this._toCamelCaseKey(key)] =
441
+ this._toCamelCaseObject(nestedValue);
442
+ }
443
+ return normalized;
444
+ }
445
+
446
+ _omitUndefined(value) {
447
+ if (!this._isPlainObject(value)) {
448
+ return value;
449
+ }
450
+
451
+ return Object.fromEntries(
452
+ Object.entries(value).filter(([, nestedValue]) => nestedValue !== undefined)
453
+ );
454
+ }
455
+
392
456
  showChangelog(options = {}) {
393
457
  if (!this.initialized) {
394
458
  throw new SDKError(
@@ -396,16 +460,22 @@ export class FeedbackSDK {
396
460
  );
397
461
  }
398
462
 
463
+ const defaults = {
464
+ position: this.config.position || 'bottom-right',
465
+ theme: this.config.theme || 'light',
466
+ title: "What's New",
467
+ triggerText: "What's New",
468
+ showBadge: true,
469
+ viewButtonText: 'View Update',
470
+ };
471
+
472
+ const configDefaults = this._getWidgetTypeConfig('changelog');
473
+ const explicitOptions = this._omitUndefined(options);
474
+
399
475
  const changelogWidget = this.createWidget('changelog', {
400
- position: options.position || 'bottom-right',
401
- theme: options.theme || this.config.theme || 'light',
402
- title: options.title || "What's New",
403
- triggerText: options.triggerText || "What's New",
404
- showBadge: options.showBadge !== false,
405
- viewButtonText: options.viewButtonText || 'View Update',
406
- changelogBaseUrl: options.changelogBaseUrl,
407
- openInNewTab: options.openInNewTab,
408
- onViewUpdate: options.onViewUpdate,
476
+ ...defaults,
477
+ ...configDefaults,
478
+ ...explicitOptions,
409
479
  });
410
480
 
411
481
  changelogWidget.mount();
@@ -8,6 +8,13 @@ export class ButtonWidget extends BaseWidget {
8
8
  }
9
9
 
10
10
  _render() {
11
+ const buttonText =
12
+ this.options.buttonText ||
13
+ this.options.triggerText ||
14
+ this.options.label ||
15
+ this.options.text ||
16
+ 'Feedback';
17
+
11
18
  const button = document.createElement('div');
12
19
  button.className = `feedback-widget-button position-${this.options.position}`;
13
20
  button.innerHTML = `
@@ -15,7 +22,7 @@ export class ButtonWidget extends BaseWidget {
15
22
  <svg class="feedback-icon" width="20" height="20" viewBox="0 0 256 256" fill="currentColor">
16
23
  <path d="M216,80H184V48a16,16,0,0,0-16-16H40A16,16,0,0,0,24,48V176a8,8,0,0,0,13,6.22L72,154V184a16,16,0,0,0,16,16h93.59L219,230.22a8,8,0,0,0,5,1.78,8,8,0,0,0,8-8V96A16,16,0,0,0,216,80ZM66.55,137.78,40,159.25V48H168v88H71.58A8,8,0,0,0,66.55,137.78ZM216,207.25l-26.55-21.47a8,8,0,0,0-5-1.78H88V152h80a16,16,0,0,0,16-16V96h32Z"/>
17
24
  </svg>
18
- <span class="feedback-text">Feedback</span>
25
+ <span class="feedback-text">${buttonText}</span>
19
26
 
20
27
  <div class="feedback-minimize-icon">
21
28
  <svg viewBox="0 0 256 256">
@@ -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() {
package/types/index.d.ts CHANGED
@@ -4,10 +4,15 @@ 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;
15
+ widgets?: WidgetConfigMap;
11
16
  }
12
17
 
13
18
  export interface UserContext {
@@ -22,6 +27,33 @@ declare module '@product7/feedback-sdk' {
22
27
  };
23
28
  }
24
29
 
30
+ export interface ButtonWidgetOptions {
31
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
32
+ theme?: 'light' | 'dark';
33
+ boardId?: string;
34
+ displayMode?: 'panel' | 'modal';
35
+ size?: 'small' | 'medium' | 'large';
36
+ primaryColor?: string;
37
+ backgroundColor?: string;
38
+ textColor?: string;
39
+ autoShow?: boolean;
40
+ suppressAfterSubmission?: boolean;
41
+ suppressionDays?: number;
42
+ buttonText?: string;
43
+ triggerText?: string;
44
+ label?: string;
45
+ text?: string;
46
+ customStyles?: Record<string, string>;
47
+ }
48
+
49
+ export interface WidgetConfigMap {
50
+ button?: Partial<ButtonWidgetOptions> | Record<string, any>;
51
+ survey?: Partial<SurveyWidgetOptions> | Record<string, any>;
52
+ messenger?: Partial<MessengerWidgetOptions> | Record<string, any>;
53
+ changelog?: Partial<ChangelogWidgetOptions> | Record<string, any>;
54
+ [key: string]: Record<string, any> | undefined;
55
+ }
56
+
25
57
  export interface ButtonWidget {
26
58
  id: string;
27
59
  type: 'button';
@@ -29,8 +61,14 @@ declare module '@product7/feedback-sdk' {
29
61
  destroy(): void;
30
62
  show(): this;
31
63
  hide(): this;
64
+ openPanel(): void;
65
+ closePanel(): void;
32
66
  openModal(): void;
33
67
  closeModal(): void;
68
+ updateText(text: string): void;
69
+ updatePosition(
70
+ position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
71
+ ): void;
34
72
  }
35
73
 
36
74
  export class FeedbackSDK {
@@ -41,10 +79,17 @@ declare module '@product7/feedback-sdk' {
41
79
  sessionToken?: string;
42
80
  expiresIn?: number;
43
81
  }>;
82
+ createWidget(type: 'button', options?: ButtonWidgetOptions): ButtonWidget;
83
+ createWidget(type: 'survey', options?: SurveyWidgetOptions): SurveyWidget;
84
+ createWidget(
85
+ type: 'messenger',
86
+ options?: MessengerWidgetOptions
87
+ ): MessengerWidget;
44
88
  createWidget(
45
- type: 'button',
46
- options?: Partial<FeedbackConfig>
47
- ): ButtonWidget;
89
+ type: 'changelog',
90
+ options?: ChangelogWidgetOptions
91
+ ): ChangelogWidget;
92
+ createWidget(type: string, options?: Record<string, any>): any;
48
93
  setUserContext(userContext: UserContext): void;
49
94
  getUserContext(): UserContext | null;
50
95
  destroy(): void;
@@ -217,6 +262,25 @@ declare module '@product7/feedback-sdk' {
217
262
  welcomeMessage?: string;
218
263
  enableHelp?: boolean;
219
264
  enableChangelog?: boolean;
265
+ enableNews?: boolean;
266
+ autoLoadData?: boolean;
267
+ initialView?: 'home' | 'messages' | 'chat' | 'prechat' | 'help' | 'changelog';
268
+ previewData?: {
269
+ conversations?: any[];
270
+ helpArticles?: any[];
271
+ homeChangelogItems?: any[];
272
+ changelogItems?: any[];
273
+ unreadCount?: number;
274
+ currentView?: string;
275
+ availability?: {
276
+ agentsOnline?: boolean;
277
+ agents_online?: boolean;
278
+ onlineCount?: number;
279
+ online_count?: number;
280
+ responseTime?: string;
281
+ response_time?: string;
282
+ };
283
+ };
220
284
  logoUrl?: string;
221
285
  primaryColor?: string;
222
286
  featuredContent?: {