@product7/feedback-sdk 1.5.7 → 1.5.9

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 CHANGED
@@ -542,7 +542,7 @@ The SDK includes a powerful survey widget for collecting structured user feedbac
542
542
 
543
543
  | Type | Description | Scale |
544
544
  | ---------- | --------------------- | ------------------------ |
545
- | **NPS** | Net Promoter Score | 0-10 numeric scale |
545
+ | **NPS** | Net Promoter Score | 1-5 numeric scale (default; configurable to 0-10) |
546
546
  | **CSAT** | Customer Satisfaction | 5-point emoji scale |
547
547
  | **CES** | Customer Effort Score | 5-level difficulty scale |
548
548
  | **Custom** | Multi-question forms | Flexible input types |
@@ -560,7 +560,14 @@ await feedback.init();
560
560
  // Show NPS survey
561
561
  feedback.showSurvey({
562
562
  surveyType: 'nps',
563
- title: 'How likely are you to recommend us?',
563
+ description:
564
+ 'To what extent do you agree or disagree that our tools support the work you do?',
565
+ ratingScale: 5,
566
+ showTitle: false,
567
+ showDescription: true,
568
+ showFeedbackInput: false,
569
+ showSubmitButton: false,
570
+ autoSubmitOnSelect: true,
564
571
  onSubmit: (response) => {
565
572
  console.log('Survey submitted:', response);
566
573
  },
@@ -577,6 +584,12 @@ feedback.showSurvey({
577
584
  theme: 'light', // 'light' | 'dark'
578
585
  title: 'Your survey title',
579
586
  description: 'Optional description',
587
+ ratingScale: 5, // NPS scale (default 5, set 11 for 0-10)
588
+ showTitle: false, // default false for single-step rating surveys
589
+ showDescription: true, // default true for single-step rating surveys
590
+ showFeedbackInput: false, // default false for single-step rating surveys
591
+ showSubmitButton: false, // default false for single-step rating surveys
592
+ autoSubmitOnSelect: true, // default true for single-step rating surveys
580
593
  lowLabel: 'Not likely', // Low end label (NPS/CES)
581
594
  highLabel: 'Very likely', // High end label (NPS/CES)
582
595
  customQuestions: [], // For custom surveys
@@ -639,12 +652,19 @@ const surveys = await feedback.getActiveSurveys({
639
652
  ```javascript
640
653
  feedback.showSurvey({
641
654
  surveyType: 'nps',
642
- title: 'How likely are you to recommend us to a friend?',
643
- lowLabel: 'Not at all likely',
644
- highLabel: 'Extremely likely',
655
+ description:
656
+ 'To what extent do you agree or disagree that our tools support the work you do?',
657
+ ratingScale: 5,
658
+ showTitle: false,
659
+ showDescription: true,
660
+ showFeedbackInput: false,
661
+ showSubmitButton: false,
662
+ autoSubmitOnSelect: true,
663
+ lowLabel: 'Strongly Disagree',
664
+ highLabel: 'Strongly Agree',
645
665
  position: 'bottom-right',
646
666
  onSubmit: (response) => {
647
- console.log('Score:', response.score); // 0-10
667
+ console.log('Score:', response.score); // 1-5 by default
648
668
  console.log('Feedback:', response.feedback);
649
669
  },
650
670
  });
package/dist/README.md CHANGED
@@ -542,7 +542,7 @@ The SDK includes a powerful survey widget for collecting structured user feedbac
542
542
 
543
543
  | Type | Description | Scale |
544
544
  | ---------- | --------------------- | ------------------------ |
545
- | **NPS** | Net Promoter Score | 0-10 numeric scale |
545
+ | **NPS** | Net Promoter Score | 1-5 numeric scale (default; configurable to 0-10) |
546
546
  | **CSAT** | Customer Satisfaction | 5-point emoji scale |
547
547
  | **CES** | Customer Effort Score | 5-level difficulty scale |
548
548
  | **Custom** | Multi-question forms | Flexible input types |
@@ -560,7 +560,14 @@ await feedback.init();
560
560
  // Show NPS survey
561
561
  feedback.showSurvey({
562
562
  surveyType: 'nps',
563
- title: 'How likely are you to recommend us?',
563
+ description:
564
+ 'To what extent do you agree or disagree that our tools support the work you do?',
565
+ ratingScale: 5,
566
+ showTitle: false,
567
+ showDescription: true,
568
+ showFeedbackInput: false,
569
+ showSubmitButton: false,
570
+ autoSubmitOnSelect: true,
564
571
  onSubmit: (response) => {
565
572
  console.log('Survey submitted:', response);
566
573
  },
@@ -577,6 +584,12 @@ feedback.showSurvey({
577
584
  theme: 'light', // 'light' | 'dark'
578
585
  title: 'Your survey title',
579
586
  description: 'Optional description',
587
+ ratingScale: 5, // NPS scale (default 5, set 11 for 0-10)
588
+ showTitle: false, // default false for single-step rating surveys
589
+ showDescription: true, // default true for single-step rating surveys
590
+ showFeedbackInput: false, // default false for single-step rating surveys
591
+ showSubmitButton: false, // default false for single-step rating surveys
592
+ autoSubmitOnSelect: true, // default true for single-step rating surveys
580
593
  lowLabel: 'Not likely', // Low end label (NPS/CES)
581
594
  highLabel: 'Very likely', // High end label (NPS/CES)
582
595
  customQuestions: [], // For custom surveys
@@ -639,12 +652,19 @@ const surveys = await feedback.getActiveSurveys({
639
652
  ```javascript
640
653
  feedback.showSurvey({
641
654
  surveyType: 'nps',
642
- title: 'How likely are you to recommend us to a friend?',
643
- lowLabel: 'Not at all likely',
644
- highLabel: 'Extremely likely',
655
+ description:
656
+ 'To what extent do you agree or disagree that our tools support the work you do?',
657
+ ratingScale: 5,
658
+ showTitle: false,
659
+ showDescription: true,
660
+ showFeedbackInput: false,
661
+ showSubmitButton: false,
662
+ autoSubmitOnSelect: true,
663
+ lowLabel: 'Strongly Disagree',
664
+ highLabel: 'Strongly Agree',
645
665
  position: 'bottom-right',
646
666
  onSubmit: (response) => {
647
- console.log('Score:', response.score); // 0-10
667
+ console.log('Score:', response.score); // 1-5 by default
648
668
  console.log('Feedback:', response.feedback);
649
669
  },
650
670
  });
@@ -5160,17 +5160,6 @@
5160
5160
  this.options = options;
5161
5161
  this.element = null;
5162
5162
  this._unsubscribe = null;
5163
-
5164
- this._avatarColors = [
5165
- { bg: '#EF4444', text: '#FFFFFF' },
5166
- { bg: '#F97316', text: '#FFFFFF' },
5167
- { bg: '#F59E0B', text: '#FFFFFF' },
5168
- { bg: '#10B981', text: '#FFFFFF' },
5169
- { bg: '#06B6D4', text: '#FFFFFF' },
5170
- { bg: '#3B82F6', text: '#FFFFFF' },
5171
- { bg: '#8B5CF6', text: '#FFFFFF' },
5172
- { bg: '#EC4899', text: '#FFFFFF' },
5173
- ];
5174
5163
  }
5175
5164
 
5176
5165
  render() {
@@ -5196,10 +5185,8 @@
5196
5185
  <div class="messenger-help-header-top">
5197
5186
  <h2>Help</h2>
5198
5187
  <button class="sdk-close-btn" aria-label="Close">
5199
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="18" height="18">
5200
- <rect width="256" height="256" fill="none"/>
5201
- <line x1="200" y1="56" x2="56" y2="200" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
5202
- <line x1="200" y1="200" x2="56" y2="56" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
5188
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256">
5189
+ <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
5203
5190
  </svg>
5204
5191
  </button>
5205
5192
  </div>
@@ -5227,7 +5214,7 @@
5227
5214
  const collections = this.state.helpArticles || [];
5228
5215
  const searchQuery = (this.state.helpSearchQuery || '').toLowerCase();
5229
5216
 
5230
- const filtered = searchQuery
5217
+ const filteredCollections = searchQuery
5231
5218
  ? collections.filter(
5232
5219
  (c) =>
5233
5220
  c.title.toLowerCase().includes(searchQuery) ||
@@ -5235,119 +5222,41 @@
5235
5222
  )
5236
5223
  : collections;
5237
5224
 
5238
- if (filtered.length === 0) {
5225
+ const headerEl = this.element.querySelector(
5226
+ '.messenger-help-collections-header'
5227
+ );
5228
+ if (headerEl) {
5229
+ headerEl.textContent = `${filteredCollections.length} collections`;
5230
+ }
5231
+
5232
+ if (filteredCollections.length === 0) {
5239
5233
  collectionsContainer.innerHTML = this._renderEmptyState();
5240
5234
  return;
5241
5235
  }
5242
5236
 
5243
- collectionsContainer.innerHTML = filtered
5244
- .map((c) => this._renderCollectionItem(c))
5237
+ collectionsContainer.innerHTML = filteredCollections
5238
+ .map((collection) => this._renderCollectionItem(collection))
5245
5239
  .join('');
5246
5240
 
5247
- // Resolve Phosphor icons async after render
5248
- filtered.forEach((c) => {
5249
- if (c.icon && !c.icon.startsWith('<svg')) {
5250
- const item = collectionsContainer.querySelector(
5251
- `[data-collection-id="${c.id}"] .messenger-help-collection-icon`
5252
- );
5253
- if (item) this._resolvePhosphorIcon(item, c.icon);
5254
- }
5255
- });
5256
-
5257
5241
  this._attachCollectionEvents();
5258
5242
  }
5259
5243
 
5260
5244
  _renderCollectionItem(collection) {
5261
- const count = collection.article_count || collection.articleCount || 0;
5262
- const icon = this._renderIcon(collection.icon);
5263
- const avatar = this._renderAuthorAvatar(collection);
5264
-
5245
+ const articleCount = collection.articleCount || 0;
5265
5246
  return `
5266
5247
  <div class="messenger-help-collection" data-collection-id="${collection.id}">
5267
- <div class="messenger-help-collection-header">
5268
- <div class="messenger-help-collection-icon">${icon}</div>
5248
+ <div class="messenger-help-collection-content">
5269
5249
  <h3 class="messenger-help-collection-title">${collection.title}</h3>
5250
+ <p class="messenger-help-collection-desc">${collection.description || ''}</p>
5251
+ <span class="messenger-help-collection-count">${articleCount} articles</span>
5270
5252
  </div>
5271
- ${
5272
- collection.description
5273
- ? `<p class="messenger-help-collection-desc">${collection.description}</p>`
5274
- : ''
5275
- }
5276
- <div class="messenger-help-collection-footer">
5277
- ${avatar}
5278
- <span>${count} ${count === 1 ? 'article' : 'articles'}</span>
5279
- </div>
5280
- </div>
5281
- `;
5282
- }
5283
-
5284
- _renderIcon(icon) {
5285
- if (!icon) return this._getFolderIcon();
5286
- if (icon.startsWith('<svg')) return icon;
5287
- // Iconify string — render placeholder, then fetch async
5288
- return this._getFolderIcon();
5289
- }
5290
-
5291
- async _resolvePhosphorIcon(el, iconStr) {
5292
- // iconStr e.g. "ph:house-line-duotone"
5293
- const [set, name] = iconStr.split(':');
5294
- if (!set || !name) return;
5295
- try {
5296
- const res = await fetch(`https://api.iconify.design/${set}/${name}.svg`);
5297
- if (!res.ok) return;
5298
- const svg = await res.text();
5299
- if (svg && svg.startsWith('<svg')) {
5300
- el.innerHTML = svg;
5301
- const s = el.querySelector('svg');
5302
- if (s) {
5303
- s.setAttribute('width', '16');
5304
- s.setAttribute('height', '16');
5305
- }
5306
- }
5307
- } catch (e) {
5308
- // keep fallback folder icon
5309
- }
5310
- }
5311
-
5312
- _getFolderIcon() {
5313
- return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="20" height="20">
5314
- <rect width="256" height="256" fill="none"/>
5315
- <path d="M216,208H40a8,8,0,0,1-8-8V64a8,8,0,0,1,8-8H93.33a8,8,0,0,1,4.8,1.6l27.74,20.8a8,8,0,0,0,4.8,1.6H216a8,8,0,0,1,8,8V200A8,8,0,0,1,216,208Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
5316
- </svg>`;
5317
- }
5318
-
5319
- _renderAuthorAvatar(collection) {
5320
- const author = collection.author;
5321
- if (!author) return '';
5322
-
5323
- if (author.picture) {
5324
- return `<img class="messenger-help-author-avatar" src="${author.picture}" alt="${author.name}" />`;
5325
- }
5326
-
5327
- const color = this._getAvatarColor(collection.id);
5328
- const initials = this._getInitials(author.name);
5329
- return `
5330
- <div class="messenger-help-author-avatar messenger-help-author-initials"
5331
- style="background:${color.bg};color:${color.text}">
5332
- ${initials}
5253
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256" class="messenger-help-collection-arrow">
5254
+ <path d="M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"></path>
5255
+ </svg>
5333
5256
  </div>
5334
5257
  `;
5335
5258
  }
5336
5259
 
5337
- _getAvatarColor(id) {
5338
- const hash = id.split('').reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
5339
- return this._avatarColors[hash % this._avatarColors.length];
5340
- }
5341
-
5342
- _getInitials(name) {
5343
- return name
5344
- .split(' ')
5345
- .map((n) => n[0])
5346
- .join('')
5347
- .toUpperCase()
5348
- .slice(0, 2);
5349
- }
5350
-
5351
5260
  _renderEmptyState() {
5352
5261
  const isSearching = this.state.helpSearchQuery;
5353
5262
 
@@ -5418,7 +5327,9 @@
5418
5327
  }
5419
5328
 
5420
5329
  destroy() {
5421
- if (this._unsubscribe) this._unsubscribe();
5330
+ if (this._unsubscribe) {
5331
+ this._unsubscribe();
5332
+ }
5422
5333
  if (this.element && this.element.parentNode) {
5423
5334
  this.element.parentNode.removeChild(this.element);
5424
5335
  }