@product7/feedback-sdk 1.5.2 → 1.5.4
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/dist/feedback-sdk.js +644 -33
- 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 +139 -18
- package/src/styles/survey.js +61 -1
- package/src/widgets/SurveyWidget.js +444 -14
- package/types/index.d.ts +38 -0
package/dist/feedback-sdk.js
CHANGED
|
@@ -6729,6 +6729,7 @@
|
|
|
6729
6729
|
lowLabel: options.lowLabel || null,
|
|
6730
6730
|
highLabel: options.highLabel || null,
|
|
6731
6731
|
customQuestions: options.customQuestions || [],
|
|
6732
|
+
pages: Array.isArray(options.pages) ? options.pages : [],
|
|
6732
6733
|
respondentId: options.respondentId || null,
|
|
6733
6734
|
email: options.email || null,
|
|
6734
6735
|
onSubmit: options.onSubmit || null,
|
|
@@ -6739,6 +6740,8 @@
|
|
|
6739
6740
|
score: null,
|
|
6740
6741
|
feedback: '',
|
|
6741
6742
|
customAnswers: {},
|
|
6743
|
+
pageAnswers: {},
|
|
6744
|
+
currentPageIndex: 0,
|
|
6742
6745
|
isVisible: false,
|
|
6743
6746
|
};
|
|
6744
6747
|
}
|
|
@@ -6769,9 +6772,19 @@
|
|
|
6769
6772
|
}
|
|
6770
6773
|
|
|
6771
6774
|
_renderSurvey() {
|
|
6772
|
-
this._closeSurvey();
|
|
6775
|
+
this._closeSurvey(false);
|
|
6773
6776
|
|
|
6774
6777
|
const config = this._getSurveyConfig();
|
|
6778
|
+
const isMultiPage = this._isMultiPageSurvey();
|
|
6779
|
+
const isLastPage = this._isLastPage();
|
|
6780
|
+
const pageProgress = isMultiPage
|
|
6781
|
+
? `Page ${this.surveyState.currentPageIndex + 1} of ${this.surveyOptions.pages.length}`
|
|
6782
|
+
: '';
|
|
6783
|
+
const submitLabel = isMultiPage && !isLastPage ? 'Next' : 'Submit';
|
|
6784
|
+
const backButton =
|
|
6785
|
+
isMultiPage && this.surveyState.currentPageIndex > 0
|
|
6786
|
+
? '<button class="feedback-survey-back">Back</button>'
|
|
6787
|
+
: '';
|
|
6775
6788
|
|
|
6776
6789
|
if (this.surveyOptions.position === 'center') {
|
|
6777
6790
|
this.backdropElement = document.createElement('div');
|
|
@@ -6789,11 +6802,15 @@
|
|
|
6789
6802
|
<button class="feedback-survey-close">×</button>
|
|
6790
6803
|
<h3 class="feedback-survey-title">${config.title}</h3>
|
|
6791
6804
|
<p class="feedback-survey-description">${config.description}</p>
|
|
6805
|
+
${isMultiPage ? `<div class="feedback-survey-progress">${pageProgress}</div>` : ''}
|
|
6792
6806
|
<div class="feedback-survey-content">${config.html}</div>
|
|
6793
6807
|
<div class="feedback-survey-feedback">
|
|
6794
|
-
<textarea class="feedback-survey-textarea" placeholder="Any additional feedback? (optional)"
|
|
6808
|
+
<textarea class="feedback-survey-textarea" placeholder="Any additional feedback? (optional)">${this.surveyState.feedback || ''}</textarea>
|
|
6809
|
+
</div>
|
|
6810
|
+
<div class="feedback-survey-actions">
|
|
6811
|
+
${backButton}
|
|
6812
|
+
<button class="feedback-survey-submit">${submitLabel}</button>
|
|
6795
6813
|
</div>
|
|
6796
|
-
<button class="feedback-survey-submit">Submit</button>
|
|
6797
6814
|
`;
|
|
6798
6815
|
|
|
6799
6816
|
document.body.appendChild(this.surveyElement);
|
|
@@ -6809,6 +6826,10 @@
|
|
|
6809
6826
|
}
|
|
6810
6827
|
|
|
6811
6828
|
_getSurveyConfig() {
|
|
6829
|
+
if (this._isMultiPageSurvey()) {
|
|
6830
|
+
return this._getCurrentPageConfig();
|
|
6831
|
+
}
|
|
6832
|
+
|
|
6812
6833
|
const configs = {
|
|
6813
6834
|
nps: {
|
|
6814
6835
|
title:
|
|
@@ -6882,6 +6903,166 @@
|
|
|
6882
6903
|
return configs[this.surveyOptions.surveyType] || configs.nps;
|
|
6883
6904
|
}
|
|
6884
6905
|
|
|
6906
|
+
_isMultiPageSurvey() {
|
|
6907
|
+
return (
|
|
6908
|
+
Array.isArray(this.surveyOptions.pages) &&
|
|
6909
|
+
this.surveyOptions.pages.length > 0
|
|
6910
|
+
);
|
|
6911
|
+
}
|
|
6912
|
+
|
|
6913
|
+
_getCurrentPage() {
|
|
6914
|
+
if (!this._isMultiPageSurvey()) return null;
|
|
6915
|
+
return this.surveyOptions.pages[this.surveyState.currentPageIndex] || null;
|
|
6916
|
+
}
|
|
6917
|
+
|
|
6918
|
+
_isLastPage() {
|
|
6919
|
+
if (!this._isMultiPageSurvey()) return true;
|
|
6920
|
+
return this.surveyState.currentPageIndex >= this.surveyOptions.pages.length - 1;
|
|
6921
|
+
}
|
|
6922
|
+
|
|
6923
|
+
_getCurrentPageConfig() {
|
|
6924
|
+
const page = this._getCurrentPage();
|
|
6925
|
+
if (!page) {
|
|
6926
|
+
return this._getFallbackSurveyConfig();
|
|
6927
|
+
}
|
|
6928
|
+
|
|
6929
|
+
return {
|
|
6930
|
+
title: page.title || this.surveyOptions.title || 'Quick Feedback',
|
|
6931
|
+
description:
|
|
6932
|
+
page.description ||
|
|
6933
|
+
this.surveyOptions.description ||
|
|
6934
|
+
'Help us improve by answering this question.',
|
|
6935
|
+
html: this._renderSurveyPage(page),
|
|
6936
|
+
};
|
|
6937
|
+
}
|
|
6938
|
+
|
|
6939
|
+
_getFallbackSurveyConfig() {
|
|
6940
|
+
return {
|
|
6941
|
+
title: this.surveyOptions.title || 'Quick Feedback',
|
|
6942
|
+
description:
|
|
6943
|
+
this.surveyOptions.description ||
|
|
6944
|
+
'Help us improve by answering a few questions.',
|
|
6945
|
+
html: this._renderCustomQuestions(),
|
|
6946
|
+
};
|
|
6947
|
+
}
|
|
6948
|
+
|
|
6949
|
+
_renderSurveyPage(page) {
|
|
6950
|
+
switch (page.type) {
|
|
6951
|
+
case 'rating':
|
|
6952
|
+
return this._renderRatingPage(page);
|
|
6953
|
+
case 'multiple_choice':
|
|
6954
|
+
return this._renderMultipleChoicePage(page);
|
|
6955
|
+
case 'text':
|
|
6956
|
+
return this._renderTextPage(page);
|
|
6957
|
+
default:
|
|
6958
|
+
return this._renderTextPage(page);
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6961
|
+
|
|
6962
|
+
_renderRatingPage(page) {
|
|
6963
|
+
const pageId = page.id || `page_${this.surveyState.currentPageIndex}`;
|
|
6964
|
+
const config = page.ratingConfig || page.rating_config || {};
|
|
6965
|
+
const scale = Number(config.scale) || 5;
|
|
6966
|
+
const ratingType = config.survey_type || this.surveyOptions.surveyType || 'csat';
|
|
6967
|
+
const pageAnswer = this.surveyState.pageAnswers[pageId] || {};
|
|
6968
|
+
const currentRating = pageAnswer.rating;
|
|
6969
|
+
|
|
6970
|
+
const labels = `
|
|
6971
|
+
<div class="feedback-survey-labels">
|
|
6972
|
+
<span>${config.low_label || this.surveyOptions.lowLabel || ''}</span>
|
|
6973
|
+
<span>${config.high_label || this.surveyOptions.highLabel || ''}</span>
|
|
6974
|
+
</div>
|
|
6975
|
+
`;
|
|
6976
|
+
|
|
6977
|
+
if (scale === 11 || ratingType === 'nps') {
|
|
6978
|
+
return `
|
|
6979
|
+
<div class="feedback-survey-nps" data-page-id="${pageId}">
|
|
6980
|
+
${[...Array(11).keys()]
|
|
6981
|
+
.map((n) => {
|
|
6982
|
+
const selected = currentRating === n ? ' selected' : '';
|
|
6983
|
+
return `<button class="feedback-survey-page-rating-btn feedback-survey-nps-btn${selected}" data-page-id="${pageId}" data-score="${n}">${n}</button>`;
|
|
6984
|
+
})
|
|
6985
|
+
.join('')}
|
|
6986
|
+
</div>
|
|
6987
|
+
${labels}
|
|
6988
|
+
`;
|
|
6989
|
+
}
|
|
6990
|
+
|
|
6991
|
+
if (ratingType === 'emoji' && scale === 5) {
|
|
6992
|
+
const emojis = [
|
|
6993
|
+
'\uD83D\uDE1E',
|
|
6994
|
+
'\uD83D\uDE15',
|
|
6995
|
+
'\uD83D\uDE10',
|
|
6996
|
+
'\uD83D\uDE42',
|
|
6997
|
+
'\uD83D\uDE04',
|
|
6998
|
+
];
|
|
6999
|
+
return `
|
|
7000
|
+
<div class="feedback-survey-csat" data-page-id="${pageId}">
|
|
7001
|
+
${emojis
|
|
7002
|
+
.map((emoji, i) => {
|
|
7003
|
+
const score = i + 1;
|
|
7004
|
+
const selected = currentRating === score ? ' selected' : '';
|
|
7005
|
+
return `<button class="feedback-survey-page-rating-btn feedback-survey-csat-btn${selected}" data-page-id="${pageId}" data-score="${score}">${emoji}</button>`;
|
|
7006
|
+
})
|
|
7007
|
+
.join('')}
|
|
7008
|
+
</div>
|
|
7009
|
+
${labels}
|
|
7010
|
+
`;
|
|
7011
|
+
}
|
|
7012
|
+
|
|
7013
|
+
return `
|
|
7014
|
+
<div class="feedback-survey-ces" data-page-id="${pageId}">
|
|
7015
|
+
${[...Array(scale).keys()]
|
|
7016
|
+
.map((i) => {
|
|
7017
|
+
const score = i + 1;
|
|
7018
|
+
const selected = currentRating === score ? ' selected' : '';
|
|
7019
|
+
return `<button class="feedback-survey-page-rating-btn feedback-survey-ces-btn${selected}" data-page-id="${pageId}" data-score="${score}">${score}</button>`;
|
|
7020
|
+
})
|
|
7021
|
+
.join('')}
|
|
7022
|
+
</div>
|
|
7023
|
+
${labels}
|
|
7024
|
+
`;
|
|
7025
|
+
}
|
|
7026
|
+
|
|
7027
|
+
_renderMultipleChoicePage(page) {
|
|
7028
|
+
const pageId = page.id || `page_${this.surveyState.currentPageIndex}`;
|
|
7029
|
+
const config = page.multipleChoiceConfig || page.multiple_choice_config || {};
|
|
7030
|
+
const options = Array.isArray(config.options) ? config.options : [];
|
|
7031
|
+
const allowMultiple = config.allow_multiple === true || config.multiple === true;
|
|
7032
|
+
const pageAnswer = this.surveyState.pageAnswers[pageId] || {};
|
|
7033
|
+
const selectedValues = Array.isArray(pageAnswer.values)
|
|
7034
|
+
? pageAnswer.values
|
|
7035
|
+
: pageAnswer.value
|
|
7036
|
+
? [pageAnswer.value]
|
|
7037
|
+
: [];
|
|
7038
|
+
|
|
7039
|
+
return `
|
|
7040
|
+
<div class="feedback-survey-multiple-choice" data-page-id="${pageId}" data-multiple="${allowMultiple}">
|
|
7041
|
+
${options
|
|
7042
|
+
.map((option, index) => {
|
|
7043
|
+
const value =
|
|
7044
|
+
option.value || option.id || option.key || `option_${index}`;
|
|
7045
|
+
const label = option.label || option.text || String(value);
|
|
7046
|
+
const selected = selectedValues.includes(value) ? ' selected' : '';
|
|
7047
|
+
return `<button class="feedback-survey-page-choice-btn${selected}" data-page-id="${pageId}" data-value="${value}">${label}</button>`;
|
|
7048
|
+
})
|
|
7049
|
+
.join('')}
|
|
7050
|
+
</div>
|
|
7051
|
+
`;
|
|
7052
|
+
}
|
|
7053
|
+
|
|
7054
|
+
_renderTextPage(page) {
|
|
7055
|
+
const pageId = page.id || `page_${this.surveyState.currentPageIndex}`;
|
|
7056
|
+
const pageAnswer = this.surveyState.pageAnswers[pageId] || {};
|
|
7057
|
+
const value = pageAnswer.text || '';
|
|
7058
|
+
|
|
7059
|
+
return `
|
|
7060
|
+
<div class="feedback-survey-text-page" data-page-id="${pageId}">
|
|
7061
|
+
<textarea class="feedback-survey-page-textarea" data-page-id="${pageId}" placeholder="Type your answer...">${value}</textarea>
|
|
7062
|
+
</div>
|
|
7063
|
+
`;
|
|
7064
|
+
}
|
|
7065
|
+
|
|
6885
7066
|
_renderCustomQuestions() {
|
|
6886
7067
|
if (
|
|
6887
7068
|
!this.surveyOptions.customQuestions ||
|
|
@@ -6954,6 +7135,11 @@
|
|
|
6954
7135
|
);
|
|
6955
7136
|
submitBtn.addEventListener('click', () => this._handleSubmit());
|
|
6956
7137
|
|
|
7138
|
+
const backBtn = this.surveyElement.querySelector('.feedback-survey-back');
|
|
7139
|
+
if (backBtn) {
|
|
7140
|
+
backBtn.addEventListener('click', () => this._handleBack());
|
|
7141
|
+
}
|
|
7142
|
+
|
|
6957
7143
|
const textarea = this.surveyElement.querySelector(
|
|
6958
7144
|
'.feedback-survey-textarea'
|
|
6959
7145
|
);
|
|
@@ -6972,6 +7158,11 @@
|
|
|
6972
7158
|
}
|
|
6973
7159
|
|
|
6974
7160
|
_attachTypeSpecificEvents() {
|
|
7161
|
+
if (this._isMultiPageSurvey()) {
|
|
7162
|
+
this._attachCurrentPageEvents();
|
|
7163
|
+
return;
|
|
7164
|
+
}
|
|
7165
|
+
|
|
6975
7166
|
const type = this.surveyOptions.surveyType;
|
|
6976
7167
|
|
|
6977
7168
|
if (type === 'nps') {
|
|
@@ -7033,6 +7224,87 @@
|
|
|
7033
7224
|
}
|
|
7034
7225
|
}
|
|
7035
7226
|
|
|
7227
|
+
_attachCurrentPageEvents() {
|
|
7228
|
+
const page = this._getCurrentPage();
|
|
7229
|
+
if (!page || !this.surveyElement) return;
|
|
7230
|
+
const pageId = page.id || `page_${this.surveyState.currentPageIndex}`;
|
|
7231
|
+
|
|
7232
|
+
if (page.type === 'rating') {
|
|
7233
|
+
this.surveyElement
|
|
7234
|
+
.querySelectorAll('.feedback-survey-page-rating-btn')
|
|
7235
|
+
.forEach((btn) => {
|
|
7236
|
+
btn.addEventListener('click', () => {
|
|
7237
|
+
const score = parseInt(btn.dataset.score);
|
|
7238
|
+
if (Number.isNaN(score)) return;
|
|
7239
|
+
this._setPageAnswer(pageId, { rating: score });
|
|
7240
|
+
|
|
7241
|
+
this.surveyElement
|
|
7242
|
+
.querySelectorAll('.feedback-survey-page-rating-btn')
|
|
7243
|
+
.forEach((item) => item.classList.remove('selected'));
|
|
7244
|
+
btn.classList.add('selected');
|
|
7245
|
+
});
|
|
7246
|
+
});
|
|
7247
|
+
}
|
|
7248
|
+
|
|
7249
|
+
if (page.type === 'multiple_choice') {
|
|
7250
|
+
const container = this.surveyElement.querySelector(
|
|
7251
|
+
'.feedback-survey-multiple-choice'
|
|
7252
|
+
);
|
|
7253
|
+
const allowMultiple = container
|
|
7254
|
+
? container.dataset.multiple === 'true'
|
|
7255
|
+
: false;
|
|
7256
|
+
|
|
7257
|
+
this.surveyElement
|
|
7258
|
+
.querySelectorAll('.feedback-survey-page-choice-btn')
|
|
7259
|
+
.forEach((btn) => {
|
|
7260
|
+
btn.addEventListener('click', () => {
|
|
7261
|
+
const value = btn.dataset.value;
|
|
7262
|
+
if (!value) return;
|
|
7263
|
+
|
|
7264
|
+
const existing = this.surveyState.pageAnswers[pageId] || {};
|
|
7265
|
+
const existingValues = Array.isArray(existing.values)
|
|
7266
|
+
? existing.values
|
|
7267
|
+
: existing.value
|
|
7268
|
+
? [existing.value]
|
|
7269
|
+
: [];
|
|
7270
|
+
|
|
7271
|
+
let nextValues = [];
|
|
7272
|
+
if (allowMultiple) {
|
|
7273
|
+
const hasValue = existingValues.includes(value);
|
|
7274
|
+
nextValues = hasValue
|
|
7275
|
+
? existingValues.filter((v) => v !== value)
|
|
7276
|
+
: [...existingValues, value];
|
|
7277
|
+
} else {
|
|
7278
|
+
nextValues = [value];
|
|
7279
|
+
}
|
|
7280
|
+
|
|
7281
|
+
this._setPageAnswer(pageId, {
|
|
7282
|
+
value: nextValues[0] || null,
|
|
7283
|
+
values: nextValues,
|
|
7284
|
+
});
|
|
7285
|
+
|
|
7286
|
+
if (!allowMultiple) {
|
|
7287
|
+
this.surveyElement
|
|
7288
|
+
.querySelectorAll('.feedback-survey-page-choice-btn')
|
|
7289
|
+
.forEach((item) => item.classList.remove('selected'));
|
|
7290
|
+
}
|
|
7291
|
+
btn.classList.toggle('selected', nextValues.includes(value));
|
|
7292
|
+
});
|
|
7293
|
+
});
|
|
7294
|
+
}
|
|
7295
|
+
|
|
7296
|
+
if (page.type === 'text') {
|
|
7297
|
+
const textarea = this.surveyElement.querySelector(
|
|
7298
|
+
'.feedback-survey-page-textarea'
|
|
7299
|
+
);
|
|
7300
|
+
if (textarea) {
|
|
7301
|
+
textarea.addEventListener('input', (e) => {
|
|
7302
|
+
this._setPageAnswer(pageId, { text: e.target.value });
|
|
7303
|
+
});
|
|
7304
|
+
}
|
|
7305
|
+
}
|
|
7306
|
+
}
|
|
7307
|
+
|
|
7036
7308
|
_selectNPS(score) {
|
|
7037
7309
|
this.surveyState.score = score;
|
|
7038
7310
|
this.surveyElement
|
|
@@ -7091,7 +7363,21 @@
|
|
|
7091
7363
|
async _handleSubmit() {
|
|
7092
7364
|
const type = this.surveyOptions.surveyType;
|
|
7093
7365
|
|
|
7366
|
+
if (this._isMultiPageSurvey()) {
|
|
7367
|
+
if (!this._validateCurrentPage()) {
|
|
7368
|
+
return;
|
|
7369
|
+
}
|
|
7370
|
+
|
|
7371
|
+
const nextPageIndex = this._getNextPageIndex();
|
|
7372
|
+
if (nextPageIndex !== -1 && nextPageIndex !== this.surveyState.currentPageIndex) {
|
|
7373
|
+
this.surveyState.currentPageIndex = nextPageIndex;
|
|
7374
|
+
this._renderSurvey();
|
|
7375
|
+
return;
|
|
7376
|
+
}
|
|
7377
|
+
}
|
|
7378
|
+
|
|
7094
7379
|
if (
|
|
7380
|
+
!this._isMultiPageSurvey() &&
|
|
7095
7381
|
(type === 'nps' || type === 'csat' || type === 'ces') &&
|
|
7096
7382
|
this.surveyState.score === null
|
|
7097
7383
|
) {
|
|
@@ -7100,20 +7386,28 @@
|
|
|
7100
7386
|
}
|
|
7101
7387
|
|
|
7102
7388
|
const respondent = this._getRespondentContext();
|
|
7389
|
+
const normalizedPageAnswers = this._normalizePageAnswersForSubmit();
|
|
7390
|
+
const mergedAnswers = {
|
|
7391
|
+
...this.surveyState.customAnswers,
|
|
7392
|
+
...(Object.keys(normalizedPageAnswers).length > 0 && {
|
|
7393
|
+
page_answers: normalizedPageAnswers,
|
|
7394
|
+
}),
|
|
7395
|
+
};
|
|
7103
7396
|
|
|
7104
7397
|
const responseData = {
|
|
7105
|
-
rating: this.
|
|
7398
|
+
rating: this._getSubmissionRating(),
|
|
7106
7399
|
feedback: this.surveyState.feedback,
|
|
7107
|
-
answers:
|
|
7400
|
+
answers: mergedAnswers,
|
|
7108
7401
|
...(respondent.respondentId && { respondentId: respondent.respondentId }),
|
|
7109
7402
|
...(respondent.email && { email: respondent.email }),
|
|
7110
7403
|
};
|
|
7111
7404
|
|
|
7112
7405
|
const response = {
|
|
7113
7406
|
type: type,
|
|
7114
|
-
score: this.
|
|
7407
|
+
score: this._getSubmissionRating(),
|
|
7115
7408
|
feedback: this.surveyState.feedback,
|
|
7116
|
-
customAnswers:
|
|
7409
|
+
customAnswers: mergedAnswers,
|
|
7410
|
+
pageAnswers: normalizedPageAnswers,
|
|
7117
7411
|
timestamp: new Date().toISOString(),
|
|
7118
7412
|
};
|
|
7119
7413
|
|
|
@@ -7135,6 +7429,138 @@
|
|
|
7135
7429
|
this._showSuccessNotification();
|
|
7136
7430
|
}
|
|
7137
7431
|
|
|
7432
|
+
_handleBack() {
|
|
7433
|
+
if (!this._isMultiPageSurvey()) return;
|
|
7434
|
+
if (this.surveyState.currentPageIndex <= 0) return;
|
|
7435
|
+
this.surveyState.currentPageIndex -= 1;
|
|
7436
|
+
this._renderSurvey();
|
|
7437
|
+
}
|
|
7438
|
+
|
|
7439
|
+
_setPageAnswer(pageId, data) {
|
|
7440
|
+
if (!pageId) return;
|
|
7441
|
+
this.surveyState.pageAnswers[pageId] = {
|
|
7442
|
+
...(this.surveyState.pageAnswers[pageId] || {}),
|
|
7443
|
+
...data,
|
|
7444
|
+
};
|
|
7445
|
+
}
|
|
7446
|
+
|
|
7447
|
+
_validateCurrentPage() {
|
|
7448
|
+
const page = this._getCurrentPage();
|
|
7449
|
+
if (!page || page.required === false) return true;
|
|
7450
|
+
const pageId = page.id || `page_${this.surveyState.currentPageIndex}`;
|
|
7451
|
+
|
|
7452
|
+
const answer = this.surveyState.pageAnswers[pageId] || {};
|
|
7453
|
+
|
|
7454
|
+
if (page.type === 'rating') {
|
|
7455
|
+
if (typeof answer.rating !== 'number') {
|
|
7456
|
+
this._showError('Please select a rating');
|
|
7457
|
+
return false;
|
|
7458
|
+
}
|
|
7459
|
+
}
|
|
7460
|
+
|
|
7461
|
+
if (page.type === 'multiple_choice') {
|
|
7462
|
+
const hasSingle = Boolean(answer.value);
|
|
7463
|
+
const hasMany = Array.isArray(answer.values) && answer.values.length > 0;
|
|
7464
|
+
if (!hasSingle && !hasMany) {
|
|
7465
|
+
this._showError('Please select an option');
|
|
7466
|
+
return false;
|
|
7467
|
+
}
|
|
7468
|
+
}
|
|
7469
|
+
|
|
7470
|
+
if (page.type === 'text') {
|
|
7471
|
+
if (!answer.text || !String(answer.text).trim()) {
|
|
7472
|
+
this._showError('Please enter an answer');
|
|
7473
|
+
return false;
|
|
7474
|
+
}
|
|
7475
|
+
}
|
|
7476
|
+
|
|
7477
|
+
return true;
|
|
7478
|
+
}
|
|
7479
|
+
|
|
7480
|
+
_getNextPageIndex() {
|
|
7481
|
+
if (!this._isMultiPageSurvey()) {
|
|
7482
|
+
return -1;
|
|
7483
|
+
}
|
|
7484
|
+
|
|
7485
|
+
const page = this._getCurrentPage();
|
|
7486
|
+
const total = this.surveyOptions.pages.length;
|
|
7487
|
+
const currentIndex = this.surveyState.currentPageIndex;
|
|
7488
|
+
const fallbackNext = currentIndex + 1 < total ? currentIndex + 1 : -1;
|
|
7489
|
+
const navigation = page ? page.afterThisPage || page.after_this_page : null;
|
|
7490
|
+
if (!navigation) {
|
|
7491
|
+
return fallbackNext;
|
|
7492
|
+
}
|
|
7493
|
+
|
|
7494
|
+
const nextValue = navigation.default;
|
|
7495
|
+
if (!nextValue) {
|
|
7496
|
+
return fallbackNext;
|
|
7497
|
+
}
|
|
7498
|
+
|
|
7499
|
+
if (nextValue === 'end_survey') {
|
|
7500
|
+
return -1;
|
|
7501
|
+
}
|
|
7502
|
+
if (nextValue === 'next_page' || nextValue === 'next') {
|
|
7503
|
+
return fallbackNext;
|
|
7504
|
+
}
|
|
7505
|
+
|
|
7506
|
+
if (typeof nextValue === 'number') {
|
|
7507
|
+
return nextValue >= 0 && nextValue < total ? nextValue : fallbackNext;
|
|
7508
|
+
}
|
|
7509
|
+
|
|
7510
|
+
if (typeof nextValue === 'string') {
|
|
7511
|
+
const normalizedId = nextValue.replace(/^page:/, '');
|
|
7512
|
+
const pageIndex = this.surveyOptions.pages.findIndex(
|
|
7513
|
+
(item) => item.id === normalizedId
|
|
7514
|
+
);
|
|
7515
|
+
return pageIndex >= 0 ? pageIndex : fallbackNext;
|
|
7516
|
+
}
|
|
7517
|
+
|
|
7518
|
+
return fallbackNext;
|
|
7519
|
+
}
|
|
7520
|
+
|
|
7521
|
+
_getSubmissionRating() {
|
|
7522
|
+
if (typeof this.surveyState.score === 'number') {
|
|
7523
|
+
return this.surveyState.score;
|
|
7524
|
+
}
|
|
7525
|
+
|
|
7526
|
+
if (!this._isMultiPageSurvey()) {
|
|
7527
|
+
return null;
|
|
7528
|
+
}
|
|
7529
|
+
|
|
7530
|
+
for (const page of this.surveyOptions.pages) {
|
|
7531
|
+
const pageId = page.id || `page_${this.surveyOptions.pages.indexOf(page)}`;
|
|
7532
|
+
const answer = this.surveyState.pageAnswers[pageId];
|
|
7533
|
+
if (answer && typeof answer.rating === 'number') {
|
|
7534
|
+
return answer.rating;
|
|
7535
|
+
}
|
|
7536
|
+
}
|
|
7537
|
+
|
|
7538
|
+
return null;
|
|
7539
|
+
}
|
|
7540
|
+
|
|
7541
|
+
_normalizePageAnswersForSubmit() {
|
|
7542
|
+
const output = {};
|
|
7543
|
+
for (const [pageId, answer] of Object.entries(this.surveyState.pageAnswers)) {
|
|
7544
|
+
if (answer == null) continue;
|
|
7545
|
+
if (Array.isArray(answer.values) && answer.values.length > 0) {
|
|
7546
|
+
output[pageId] = answer.values;
|
|
7547
|
+
continue;
|
|
7548
|
+
}
|
|
7549
|
+
if (answer.value != null && answer.value !== '') {
|
|
7550
|
+
output[pageId] = answer.value;
|
|
7551
|
+
continue;
|
|
7552
|
+
}
|
|
7553
|
+
if (typeof answer.rating === 'number') {
|
|
7554
|
+
output[pageId] = answer.rating;
|
|
7555
|
+
continue;
|
|
7556
|
+
}
|
|
7557
|
+
if (typeof answer.text === 'string' && answer.text.trim()) {
|
|
7558
|
+
output[pageId] = answer.text.trim();
|
|
7559
|
+
}
|
|
7560
|
+
}
|
|
7561
|
+
return output;
|
|
7562
|
+
}
|
|
7563
|
+
|
|
7138
7564
|
_getRespondentContext() {
|
|
7139
7565
|
const sdkUserContext =
|
|
7140
7566
|
typeof this.sdk.getUserContext === 'function'
|
|
@@ -7213,7 +7639,7 @@
|
|
|
7213
7639
|
}, 3000);
|
|
7214
7640
|
}
|
|
7215
7641
|
|
|
7216
|
-
_closeSurvey() {
|
|
7642
|
+
_closeSurvey(resetState = true) {
|
|
7217
7643
|
if (this._escapeHandler) {
|
|
7218
7644
|
document.removeEventListener('keydown', this._escapeHandler);
|
|
7219
7645
|
this._escapeHandler = null;
|
|
@@ -7246,12 +7672,16 @@
|
|
|
7246
7672
|
this.backdropElement = null;
|
|
7247
7673
|
}
|
|
7248
7674
|
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7675
|
+
if (resetState) {
|
|
7676
|
+
this.surveyState = {
|
|
7677
|
+
score: null,
|
|
7678
|
+
feedback: '',
|
|
7679
|
+
customAnswers: {},
|
|
7680
|
+
pageAnswers: {},
|
|
7681
|
+
currentPageIndex: 0,
|
|
7682
|
+
isVisible: false,
|
|
7683
|
+
};
|
|
7684
|
+
}
|
|
7255
7685
|
}
|
|
7256
7686
|
|
|
7257
7687
|
destroy() {
|
|
@@ -7457,7 +7887,9 @@
|
|
|
7457
7887
|
|
|
7458
7888
|
try {
|
|
7459
7889
|
const result = await this.apiService.getActiveSurveys(context);
|
|
7460
|
-
const surveys = result.data || []
|
|
7890
|
+
const surveys = (result.data || []).map((survey) =>
|
|
7891
|
+
this._normalizeSurveyConfig(survey)
|
|
7892
|
+
);
|
|
7461
7893
|
if (context.includeIneligible) {
|
|
7462
7894
|
return surveys;
|
|
7463
7895
|
}
|
|
@@ -7503,12 +7935,13 @@
|
|
|
7503
7935
|
|
|
7504
7936
|
return this.showSurvey({
|
|
7505
7937
|
surveyId: surveyConfig.id,
|
|
7506
|
-
surveyType: surveyConfig.type,
|
|
7938
|
+
surveyType: surveyConfig.surveyType || surveyConfig.type,
|
|
7507
7939
|
title: surveyConfig.title,
|
|
7508
7940
|
description: surveyConfig.description,
|
|
7509
|
-
lowLabel: surveyConfig.low_label,
|
|
7510
|
-
highLabel: surveyConfig.high_label,
|
|
7511
|
-
customQuestions: surveyConfig.questions,
|
|
7941
|
+
lowLabel: surveyConfig.lowLabel || surveyConfig.low_label,
|
|
7942
|
+
highLabel: surveyConfig.highLabel || surveyConfig.high_label,
|
|
7943
|
+
customQuestions: surveyConfig.customQuestions || surveyConfig.questions,
|
|
7944
|
+
pages: surveyConfig.pages,
|
|
7512
7945
|
...displayOptions,
|
|
7513
7946
|
});
|
|
7514
7947
|
}
|
|
@@ -7529,20 +7962,23 @@
|
|
|
7529
7962
|
return null;
|
|
7530
7963
|
}
|
|
7531
7964
|
|
|
7965
|
+
const normalizedOptions = this._normalizeSurveyConfig(options);
|
|
7966
|
+
|
|
7532
7967
|
const surveyWidget = this.createWidget('survey', {
|
|
7533
|
-
surveyId:
|
|
7534
|
-
surveyType:
|
|
7535
|
-
position:
|
|
7536
|
-
theme:
|
|
7537
|
-
title:
|
|
7538
|
-
description:
|
|
7539
|
-
lowLabel:
|
|
7540
|
-
highLabel:
|
|
7541
|
-
customQuestions:
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7968
|
+
surveyId: normalizedOptions.surveyId,
|
|
7969
|
+
surveyType: normalizedOptions.surveyType || normalizedOptions.type || 'nps',
|
|
7970
|
+
position: normalizedOptions.position || 'bottom-right',
|
|
7971
|
+
theme: normalizedOptions.theme || this.config.theme || 'light',
|
|
7972
|
+
title: normalizedOptions.title,
|
|
7973
|
+
description: normalizedOptions.description,
|
|
7974
|
+
lowLabel: normalizedOptions.lowLabel,
|
|
7975
|
+
highLabel: normalizedOptions.highLabel,
|
|
7976
|
+
customQuestions: normalizedOptions.customQuestions,
|
|
7977
|
+
pages: normalizedOptions.pages,
|
|
7978
|
+
respondentId: normalizedOptions.respondentId,
|
|
7979
|
+
email: normalizedOptions.email,
|
|
7980
|
+
onSubmit: normalizedOptions.onSubmit,
|
|
7981
|
+
onDismiss: normalizedOptions.onDismiss,
|
|
7546
7982
|
});
|
|
7547
7983
|
|
|
7548
7984
|
surveyWidget.mount();
|
|
@@ -7557,6 +7993,14 @@
|
|
|
7557
7993
|
return shouldShow;
|
|
7558
7994
|
}
|
|
7559
7995
|
|
|
7996
|
+
const eligibilityShouldShow = this._getSurveyField(
|
|
7997
|
+
survey.eligibility || {},
|
|
7998
|
+
['shouldShow', 'should_show']
|
|
7999
|
+
);
|
|
8000
|
+
if (typeof eligibilityShouldShow === 'boolean') {
|
|
8001
|
+
return eligibilityShouldShow;
|
|
8002
|
+
}
|
|
8003
|
+
|
|
7560
8004
|
const eligible = this._getSurveyField(survey, [
|
|
7561
8005
|
'eligible',
|
|
7562
8006
|
'isEligible',
|
|
@@ -7571,6 +8015,14 @@
|
|
|
7571
8015
|
return !isAnswered;
|
|
7572
8016
|
}
|
|
7573
8017
|
|
|
8018
|
+
const eligibilityAnswered = this._getSurveyField(survey.eligibility || {}, [
|
|
8019
|
+
'isAnswered',
|
|
8020
|
+
'is_answered',
|
|
8021
|
+
]);
|
|
8022
|
+
if (typeof eligibilityAnswered === 'boolean') {
|
|
8023
|
+
return !eligibilityAnswered;
|
|
8024
|
+
}
|
|
8025
|
+
|
|
7574
8026
|
return true;
|
|
7575
8027
|
}
|
|
7576
8028
|
|
|
@@ -7584,6 +8036,15 @@
|
|
|
7584
8036
|
return explicitReason;
|
|
7585
8037
|
}
|
|
7586
8038
|
|
|
8039
|
+
const eligibilityReason = this._getSurveyField(survey.eligibility || {}, [
|
|
8040
|
+
'reason',
|
|
8041
|
+
'suppressionReason',
|
|
8042
|
+
'suppression_reason',
|
|
8043
|
+
]);
|
|
8044
|
+
if (eligibilityReason) {
|
|
8045
|
+
return eligibilityReason;
|
|
8046
|
+
}
|
|
8047
|
+
|
|
7587
8048
|
const isAnswered = this._getSurveyField(survey, ['isAnswered', 'is_answered']);
|
|
7588
8049
|
if (isAnswered === true) {
|
|
7589
8050
|
return 'already_answered';
|
|
@@ -7592,6 +8053,96 @@
|
|
|
7592
8053
|
return 'ineligible';
|
|
7593
8054
|
}
|
|
7594
8055
|
|
|
8056
|
+
_normalizeSurveyConfig(survey = {}) {
|
|
8057
|
+
const firstPage = Array.isArray(survey.pages) && survey.pages.length > 0
|
|
8058
|
+
? survey.pages[0]
|
|
8059
|
+
: null;
|
|
8060
|
+
const ratingConfig = firstPage
|
|
8061
|
+
? firstPage.rating_config || firstPage.ratingConfig || {}
|
|
8062
|
+
: {};
|
|
8063
|
+
|
|
8064
|
+
const inferredType =
|
|
8065
|
+
survey.type ||
|
|
8066
|
+
this._inferSurveyTypeFromPage(firstPage) ||
|
|
8067
|
+
'nps';
|
|
8068
|
+
|
|
8069
|
+
return {
|
|
8070
|
+
...survey,
|
|
8071
|
+
surveyId: survey.surveyId || survey.id || null,
|
|
8072
|
+
surveyType: survey.surveyType || inferredType,
|
|
8073
|
+
type: survey.type || inferredType,
|
|
8074
|
+
should_show:
|
|
8075
|
+
survey.should_show ??
|
|
8076
|
+
(survey.eligibility ? survey.eligibility.should_show : undefined),
|
|
8077
|
+
reason:
|
|
8078
|
+
survey.reason ||
|
|
8079
|
+
(survey.eligibility ? survey.eligibility.reason : undefined),
|
|
8080
|
+
title:
|
|
8081
|
+
survey.title ||
|
|
8082
|
+
survey.name ||
|
|
8083
|
+
(firstPage ? firstPage.title : null),
|
|
8084
|
+
description:
|
|
8085
|
+
survey.description ||
|
|
8086
|
+
(firstPage ? firstPage.description : null),
|
|
8087
|
+
lowLabel:
|
|
8088
|
+
survey.lowLabel ||
|
|
8089
|
+
survey.low_label ||
|
|
8090
|
+
ratingConfig.low_label ||
|
|
8091
|
+
null,
|
|
8092
|
+
highLabel:
|
|
8093
|
+
survey.highLabel ||
|
|
8094
|
+
survey.high_label ||
|
|
8095
|
+
ratingConfig.high_label ||
|
|
8096
|
+
null,
|
|
8097
|
+
customQuestions: survey.customQuestions || survey.questions || [],
|
|
8098
|
+
pages: this._normalizeSurveyPages(survey.pages || []),
|
|
8099
|
+
};
|
|
8100
|
+
}
|
|
8101
|
+
|
|
8102
|
+
_normalizeSurveyPages(pages = []) {
|
|
8103
|
+
if (!Array.isArray(pages)) {
|
|
8104
|
+
return [];
|
|
8105
|
+
}
|
|
8106
|
+
|
|
8107
|
+
return pages
|
|
8108
|
+
.map((page, index) => ({
|
|
8109
|
+
id: page.id || `page_${index}`,
|
|
8110
|
+
type: page.type || 'rating',
|
|
8111
|
+
title: page.title || '',
|
|
8112
|
+
description: page.description || '',
|
|
8113
|
+
required: page.required !== false,
|
|
8114
|
+
position: page.position ?? index,
|
|
8115
|
+
ratingConfig: page.ratingConfig || page.rating_config || null,
|
|
8116
|
+
multipleChoiceConfig:
|
|
8117
|
+
page.multipleChoiceConfig || page.multiple_choice_config || null,
|
|
8118
|
+
linkConfig: page.linkConfig || page.link_config || null,
|
|
8119
|
+
afterThisPage: page.afterThisPage || page.after_this_page || null,
|
|
8120
|
+
}))
|
|
8121
|
+
.sort((a, b) => a.position - b.position);
|
|
8122
|
+
}
|
|
8123
|
+
|
|
8124
|
+
_inferSurveyTypeFromPage(page) {
|
|
8125
|
+
if (!page) return null;
|
|
8126
|
+
const ratingConfig = page.rating_config || page.ratingConfig || {};
|
|
8127
|
+
const scale = ratingConfig.scale;
|
|
8128
|
+
const surveyType = ratingConfig.survey_type;
|
|
8129
|
+
const title = (page.title || '').toLowerCase();
|
|
8130
|
+
|
|
8131
|
+
if (scale === 11 || surveyType === 'nps') {
|
|
8132
|
+
return 'nps';
|
|
8133
|
+
}
|
|
8134
|
+
|
|
8135
|
+
if (
|
|
8136
|
+
surveyType === 'emoji' ||
|
|
8137
|
+
title.includes('effort') ||
|
|
8138
|
+
title.includes('easy')
|
|
8139
|
+
) {
|
|
8140
|
+
return 'ces';
|
|
8141
|
+
}
|
|
8142
|
+
|
|
8143
|
+
return 'csat';
|
|
8144
|
+
}
|
|
8145
|
+
|
|
7595
8146
|
_getSurveyField(survey, fields) {
|
|
7596
8147
|
for (const field of fields) {
|
|
7597
8148
|
if (survey[field] !== undefined && survey[field] !== null) {
|
|
@@ -11211,13 +11762,73 @@
|
|
|
11211
11762
|
box-shadow: 0 0 0 3px var(--color-primary-light);
|
|
11212
11763
|
}
|
|
11213
11764
|
|
|
11765
|
+
.feedback-survey-progress {
|
|
11766
|
+
font-size: var(--font-size-xs);
|
|
11767
|
+
color: var(--color-text-tertiary);
|
|
11768
|
+
margin-bottom: var(--spacing-3);
|
|
11769
|
+
}
|
|
11770
|
+
|
|
11771
|
+
.feedback-survey-actions {
|
|
11772
|
+
display: flex;
|
|
11773
|
+
gap: var(--spacing-2);
|
|
11774
|
+
margin-top: var(--spacing-3);
|
|
11775
|
+
}
|
|
11776
|
+
|
|
11777
|
+
.feedback-survey-back {
|
|
11778
|
+
padding: var(--spacing-3) var(--spacing-4);
|
|
11779
|
+
border: 1px solid var(--color-border);
|
|
11780
|
+
border-radius: var(--radius-md);
|
|
11781
|
+
background: var(--color-surface);
|
|
11782
|
+
color: var(--color-text-primary);
|
|
11783
|
+
font-size: var(--font-size-base);
|
|
11784
|
+
font-weight: var(--font-weight-medium);
|
|
11785
|
+
cursor: pointer;
|
|
11786
|
+
font-family: inherit;
|
|
11787
|
+
}
|
|
11788
|
+
|
|
11789
|
+
.feedback-survey-page-choice-btn {
|
|
11790
|
+
width: 100%;
|
|
11791
|
+
padding: var(--spacing-3);
|
|
11792
|
+
border: 1px solid var(--color-border);
|
|
11793
|
+
border-radius: var(--radius-md);
|
|
11794
|
+
background: var(--color-surface);
|
|
11795
|
+
color: var(--color-text-primary);
|
|
11796
|
+
text-align: left;
|
|
11797
|
+
font-size: var(--font-size-base);
|
|
11798
|
+
cursor: pointer;
|
|
11799
|
+
margin-bottom: var(--spacing-2);
|
|
11800
|
+
font-family: inherit;
|
|
11801
|
+
}
|
|
11802
|
+
|
|
11803
|
+
.feedback-survey-page-choice-btn.selected {
|
|
11804
|
+
background: var(--color-primary);
|
|
11805
|
+
border-color: var(--color-primary);
|
|
11806
|
+
color: var(--color-white);
|
|
11807
|
+
}
|
|
11808
|
+
|
|
11809
|
+
.feedback-survey-page-textarea {
|
|
11810
|
+
width: 100%;
|
|
11811
|
+
min-height: 96px;
|
|
11812
|
+
padding: var(--spacing-3);
|
|
11813
|
+
border: 1px solid var(--color-border);
|
|
11814
|
+
border-radius: var(--radius-md);
|
|
11815
|
+
font-size: var(--font-size-base);
|
|
11816
|
+
font-family: inherit;
|
|
11817
|
+
box-sizing: border-box;
|
|
11818
|
+
outline: none;
|
|
11819
|
+
}
|
|
11820
|
+
|
|
11821
|
+
.feedback-survey-page-textarea:focus {
|
|
11822
|
+
border-color: var(--color-primary);
|
|
11823
|
+
box-shadow: 0 0 0 3px var(--color-primary-light);
|
|
11824
|
+
}
|
|
11825
|
+
|
|
11214
11826
|
/* ========================================
|
|
11215
11827
|
SUBMIT & FEEDBACK
|
|
11216
11828
|
======================================== */
|
|
11217
11829
|
|
|
11218
11830
|
.feedback-survey-submit {
|
|
11219
11831
|
width: 100%;
|
|
11220
|
-
margin-top: var(--spacing-3);
|
|
11221
11832
|
padding: var(--spacing-3);
|
|
11222
11833
|
background: var(--color-primary);
|
|
11223
11834
|
color: var(--color-white);
|