@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/README.md +4 -0
- package/dist/README.md +4 -0
- package/dist/feedback-sdk.js +162 -21
- package/dist/feedback-sdk.js.map +1 -1
- package/dist/feedback-sdk.min.js +1 -1
- package/dist/feedback-sdk.min.js.map +1 -1
- package/package.json +1 -1
- package/src/core/FeedbackSDK.js +82 -12
- package/src/widgets/ButtonWidget.js +8 -1
- package/src/widgets/MessengerWidget.js +72 -8
- package/types/index.d.ts +67 -3
package/package.json
CHANGED
package/src/core/FeedbackSDK.js
CHANGED
|
@@ -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
|
-
...
|
|
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:
|
|
189
|
-
|
|
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
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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"
|
|
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:
|
|
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.
|
|
880
|
+
this._applyPreviewData();
|
|
828
881
|
|
|
829
|
-
if (this.
|
|
830
|
-
this.
|
|
831
|
-
}
|
|
882
|
+
if (this.messengerOptions.autoLoadData) {
|
|
883
|
+
this.loadInitialData();
|
|
832
884
|
|
|
833
|
-
|
|
885
|
+
if (this.apiService?.sessionToken) {
|
|
886
|
+
this._initWebSocket();
|
|
887
|
+
}
|
|
834
888
|
|
|
835
|
-
this._availabilityInterval = setInterval(() => {
|
|
836
889
|
this.checkAgentAvailability();
|
|
837
|
-
|
|
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: '
|
|
46
|
-
options?:
|
|
47
|
-
):
|
|
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?: {
|