@product7/feedback-sdk 1.4.3 → 1.4.5

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
@@ -86,13 +86,10 @@ widget.mount();
86
86
 
87
87
  ## Documentation
88
88
 
89
- - [Installation Guide](docs/installation.md)
90
- - [Widget Types](docs/widgets.md)
91
- - [Configuration](docs/configuration.md)
92
- - [API Reference](docs/api.md)
93
- - [Theming Guide](docs/theming.md)
94
- - [Examples](docs/examples.md)
95
- - [Migration Guide](docs/migration.md)
89
+ - [Installation Guide](src/docs/installation.md)
90
+ - [Framework Integrations](src/docs/framework-integrations.md)
91
+ - [API Reference](src/docs/api.md)
92
+ - [Examples](src/docs/example.md)
96
93
 
97
94
  ---
98
95
 
package/dist/README.md CHANGED
@@ -86,13 +86,10 @@ widget.mount();
86
86
 
87
87
  ## Documentation
88
88
 
89
- - [Installation Guide](docs/installation.md)
90
- - [Widget Types](docs/widgets.md)
91
- - [Configuration](docs/configuration.md)
92
- - [API Reference](docs/api.md)
93
- - [Theming Guide](docs/theming.md)
94
- - [Examples](docs/examples.md)
95
- - [Migration Guide](docs/migration.md)
89
+ - [Installation Guide](src/docs/installation.md)
90
+ - [Framework Integrations](src/docs/framework-integrations.md)
91
+ - [API Reference](src/docs/api.md)
92
+ - [Examples](src/docs/example.md)
96
93
 
97
94
  ---
98
95
 
@@ -2370,18 +2370,14 @@
2370
2370
 
2371
2371
  this.modalElement
2372
2372
  .querySelector('.changelog-modal-container')
2373
- .addEventListener('click', (e) => {
2374
- e.stopPropagation();
2375
- });
2373
+ .addEventListener('click', (e) => e.stopPropagation());
2376
2374
 
2377
2375
  this.modalElement
2378
2376
  .querySelector('.changelog-modal-close')
2379
2377
  .addEventListener('click', () => this.closeModal());
2380
2378
 
2381
2379
  this._escapeHandler = (e) => {
2382
- if (e.key === 'Escape') {
2383
- this.closeModal();
2384
- }
2380
+ if (e.key === 'Escape') this.closeModal();
2385
2381
  };
2386
2382
  document.addEventListener('keydown', this._escapeHandler);
2387
2383
  }
@@ -2459,9 +2455,7 @@
2459
2455
  }
2460
2456
 
2461
2457
  setTimeout(() => {
2462
- if (container.parentNode) {
2463
- container.parentNode.removeChild(container);
2464
- }
2458
+ if (container.parentNode) container.parentNode.removeChild(container);
2465
2459
  }, 2500);
2466
2460
  }
2467
2461
 
@@ -2524,18 +2518,14 @@
2524
2518
 
2525
2519
  this.listModalElement
2526
2520
  .querySelector('.changelog-list-modal-container')
2527
- .addEventListener('click', (e) => {
2528
- e.stopPropagation();
2529
- });
2521
+ .addEventListener('click', (e) => e.stopPropagation());
2530
2522
 
2531
2523
  this.listModalElement
2532
2524
  .querySelector('.changelog-list-modal-close')
2533
2525
  .addEventListener('click', () => this.closeSidebar());
2534
2526
 
2535
2527
  this._listModalEscapeHandler = (e) => {
2536
- if (e.key === 'Escape') {
2537
- this.closeSidebar();
2538
- }
2528
+ if (e.key === 'Escape') this.closeSidebar();
2539
2529
  };
2540
2530
  document.addEventListener('keydown', this._listModalEscapeHandler);
2541
2531
  }
@@ -2545,9 +2535,7 @@
2545
2535
  '.changelog-list-modal-body'
2546
2536
  );
2547
2537
 
2548
- if (this.isLoading) {
2549
- return;
2550
- }
2538
+ if (this.isLoading) return;
2551
2539
 
2552
2540
  if (this.changelogs.length === 0) {
2553
2541
  body.innerHTML = `
@@ -2570,8 +2558,7 @@
2570
2558
 
2571
2559
  body.querySelectorAll('.changelog-list-item').forEach((item, index) => {
2572
2560
  item.addEventListener('click', () => {
2573
- const changelog = this.changelogs[index];
2574
- this._handleViewUpdate(changelog);
2561
+ this._handleViewUpdate(this.changelogs[index]);
2575
2562
  });
2576
2563
  });
2577
2564
  }
@@ -2582,6 +2569,10 @@
2582
2569
  const date = changelog.published_at
2583
2570
  ? this._formatDate(changelog.published_at)
2584
2571
  : '';
2572
+ const description = this._truncateDescription(
2573
+ changelog.excerpt || changelog.description,
2574
+ 120
2575
+ );
2585
2576
 
2586
2577
  return `
2587
2578
  <div class="changelog-list-item" data-index="${index}">
@@ -2613,13 +2604,7 @@
2613
2604
  : ''
2614
2605
  }
2615
2606
  <h3 class="changelog-list-item-title">${changelog.title}</h3>
2616
- ${
2617
- changelog.excerpt || changelog.description
2618
- ? `
2619
- <p class="changelog-list-item-description">${changelog.excerpt || changelog.description}</p>
2620
- `
2621
- : ''
2622
- }
2607
+ ${description ? `<p class="changelog-list-item-description">${description}</p>` : ''}
2623
2608
  </div>
2624
2609
  </div>
2625
2610
  </div>
@@ -2646,9 +2631,7 @@
2646
2631
  _renderCurrentChangelog() {
2647
2632
  const content = this.modalElement.querySelector('.changelog-modal-content');
2648
2633
 
2649
- if (this.isLoading) {
2650
- return;
2651
- }
2634
+ if (this.isLoading) return;
2652
2635
 
2653
2636
  if (this.changelogs.length === 0) {
2654
2637
  content.innerHTML = `
@@ -2667,6 +2650,10 @@
2667
2650
  const hasImage = changelog.cover_image || changelog.image;
2668
2651
  const imageUrl = changelog.cover_image || changelog.image;
2669
2652
  const hasMultiple = this.changelogs.length > 1;
2653
+ const description = this._truncateDescription(
2654
+ changelog.excerpt || changelog.description,
2655
+ 160
2656
+ );
2670
2657
 
2671
2658
  content.innerHTML = `
2672
2659
  <div class="changelog-popup-item">
@@ -2681,13 +2668,7 @@
2681
2668
  }
2682
2669
  <div class="changelog-popup-body">
2683
2670
  <h2 class="changelog-popup-title">${changelog.title}</h2>
2684
- ${
2685
- changelog.excerpt || changelog.description
2686
- ? `
2687
- <p class="changelog-popup-description">${changelog.excerpt || changelog.description}</p>
2688
- `
2689
- : ''
2690
- }
2671
+ ${description ? `<p class="changelog-popup-description">${description}</p>` : ''}
2691
2672
  <button class="changelog-popup-btn" type="button">
2692
2673
  ${this.options.viewButtonText || 'View Update'}
2693
2674
  </button>
@@ -2734,8 +2715,7 @@
2734
2715
  if (hasMultiple) {
2735
2716
  content.querySelectorAll('.changelog-dot').forEach((dot) => {
2736
2717
  dot.addEventListener('click', (e) => {
2737
- const index = parseInt(e.target.dataset.index, 10);
2738
- this.currentIndex = index;
2718
+ this.currentIndex = parseInt(e.target.dataset.index, 10);
2739
2719
  this._renderCurrentChangelog();
2740
2720
  });
2741
2721
  });
@@ -2745,10 +2725,19 @@
2745
2725
  _handleViewUpdate(changelog) {
2746
2726
  this.sdk.eventBus.emit('changelog:view', { changelog });
2747
2727
 
2748
- if (changelog.url || changelog.slug) {
2749
- const url =
2750
- changelog.url ||
2751
- `${this.options.changelogBaseUrl || ''}/${changelog.slug}`;
2728
+ const changelogBase = (this.options.changelogBaseUrl || '').replace(
2729
+ /\/$/,
2730
+ ''
2731
+ );
2732
+ const url =
2733
+ changelog.url ||
2734
+ (changelog.slug && changelogBase
2735
+ ? `${changelogBase}/${changelog.slug}`
2736
+ : null) ||
2737
+ changelogBase ||
2738
+ null;
2739
+
2740
+ if (url) {
2752
2741
  if (this.options.openInNewTab !== false) {
2753
2742
  window.open(url, '_blank', 'noopener,noreferrer');
2754
2743
  } else {
@@ -2761,10 +2750,26 @@
2761
2750
  }
2762
2751
  }
2763
2752
 
2753
+ _stripHtml(html) {
2754
+ const tmp = document.createElement('div');
2755
+ tmp.innerHTML = html;
2756
+ return (tmp.textContent || tmp.innerText || '').trim();
2757
+ }
2758
+
2759
+ _truncateDescription(html, maxLength = 120) {
2760
+ if (!html) return '';
2761
+ const plain = this._stripHtml(html);
2762
+ if (plain.length <= maxLength) return plain;
2763
+ return plain.substring(0, maxLength).trimEnd() + '...';
2764
+ }
2765
+
2764
2766
  _formatDate(dateString) {
2765
2767
  const date = new Date(dateString);
2766
- const options = { year: 'numeric', month: 'short', day: 'numeric' };
2767
- return date.toLocaleDateString('en-US', options);
2768
+ return date.toLocaleDateString('en-US', {
2769
+ year: 'numeric',
2770
+ month: 'short',
2771
+ day: 'numeric',
2772
+ });
2768
2773
  }
2769
2774
 
2770
2775
  _getContrastColor(hexColor) {
@@ -2778,16 +2783,12 @@
2778
2783
 
2779
2784
  hideBadge() {
2780
2785
  const badge = this.element?.querySelector('.changelog-badge');
2781
- if (badge) {
2782
- badge.style.display = 'none';
2783
- }
2786
+ if (badge) badge.style.display = 'none';
2784
2787
  }
2785
2788
 
2786
2789
  showBadge() {
2787
2790
  const badge = this.element?.querySelector('.changelog-badge');
2788
- if (badge) {
2789
- badge.style.display = 'block';
2790
- }
2791
+ if (badge) badge.style.display = 'block';
2791
2792
  }
2792
2793
 
2793
2794
  nextChangelog() {
@@ -3398,6 +3399,13 @@
3398
3399
  this.isLoading = false;
3399
3400
  this.isLoadingMessages = false;
3400
3401
 
3402
+ this.urls = options.urls || {
3403
+ feedback: null,
3404
+ changelog: null,
3405
+ help: null,
3406
+ roadmap: null,
3407
+ };
3408
+
3401
3409
  this._listeners = new Set();
3402
3410
  }
3403
3411
 
@@ -3981,14 +3989,14 @@
3981
3989
 
3982
3990
  _updateContent() {
3983
3991
  this.element.innerHTML = `
3984
- <div class="messenger-changelog-header">
3985
- <h2>Latest Updates</h2>
3986
- </div>
3992
+ <div class="messenger-changelog-header">
3993
+ <h2>Latest Updates</h2>
3994
+ </div>
3987
3995
 
3988
- <div class="messenger-changelog-body">
3989
- <div class="messenger-changelog-list"></div>
3990
- </div>
3991
- `;
3996
+ <div class="messenger-changelog-body">
3997
+ <div class="messenger-changelog-list"></div>
3998
+ </div>
3999
+ `;
3992
4000
 
3993
4001
  this._updateChangelogList();
3994
4002
  this._attachEvents();
@@ -4984,30 +4992,29 @@
4984
4992
 
4985
4993
  _updateContent() {
4986
4994
  const searchQuery = this.state.helpSearchQuery || '';
4987
- this.state.helpArticles || [];
4988
4995
 
4989
4996
  this.element.innerHTML = `
4990
- <div class="messenger-help-header">
4991
- <div class="messenger-help-header-top">
4992
- <h2>Help</h2>
4993
- <button class="sdk-close-btn" aria-label="Close">
4994
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256">
4995
- <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>
4996
- </svg>
4997
- </button>
4998
- </div>
4999
- <input
5000
- type="text"
5001
- class="messenger-help-search-input"
5002
- placeholder="Search for help..."
5003
- value="${searchQuery}"
5004
- />
5005
- </div>
4997
+ <div class="messenger-help-header">
4998
+ <div class="messenger-help-header-top">
4999
+ <h2>Help</h2>
5000
+ <button class="sdk-close-btn" aria-label="Close">
5001
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256">
5002
+ <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>
5003
+ </svg>
5004
+ </button>
5005
+ </div>
5006
+ <input
5007
+ type="text"
5008
+ class="messenger-help-search-input"
5009
+ placeholder="Search for help..."
5010
+ value="${searchQuery}"
5011
+ />
5012
+ </div>
5006
5013
 
5007
- <div class="messenger-help-body">
5008
- <div class="messenger-help-collections"></div>
5009
- </div>
5010
- `;
5014
+ <div class="messenger-help-body">
5015
+ <div class="messenger-help-collections"></div>
5016
+ </div>
5017
+ `;
5011
5018
 
5012
5019
  this._updateCollectionsList();
5013
5020
  this._attachEvents();
@@ -5273,11 +5280,6 @@
5273
5280
  `;
5274
5281
 
5275
5282
  if (openConversation) {
5276
- openConversation.lastMessage
5277
- ? openConversation.lastMessage.length > 40
5278
- ? openConversation.lastMessage.substring(0, 40) + '...'
5279
- : openConversation.lastMessage
5280
- : 'Continue your conversation';
5281
5283
  return `
5282
5284
  <button class="messenger-home-message-btn messenger-home-continue-btn" data-conversation-id="${openConversation.id}">
5283
5285
  <div class="messenger-home-continue-info">
@@ -5285,18 +5287,19 @@
5285
5287
  </div>
5286
5288
  ${sendIcon}
5287
5289
  </button>
5288
- <button class="messenger-home-message-btn" data-action="feedback">
5290
+ <button class="messenger-home-message-btn messenger-feedback-btn" data-action="feedback">
5289
5291
  <span class="messenger-home-continue-label">Leave us feedback</span>
5290
5292
  ${caretIcon}
5291
5293
  </button>
5292
5294
  `;
5293
5295
  }
5296
+
5294
5297
  return `
5295
5298
  <button class="messenger-home-message-btn">
5296
5299
  <span>Start a conversation</span>
5297
5300
  ${sendIcon}
5298
5301
  </button>
5299
- <button class="messenger-home-message-btn" data-action="feedback">
5302
+ <button class="messenger-home-message-btn messenger-feedback-btn" data-action="feedback">
5300
5303
  <span>Leave us feedback</span>
5301
5304
  ${caretIcon}
5302
5305
  </button>
@@ -5378,7 +5381,9 @@
5378
5381
  this.state.setOpen(false);
5379
5382
  });
5380
5383
 
5381
- const msgBtn = this.element.querySelector('.messenger-home-message-btn');
5384
+ const msgBtn = this.element.querySelector(
5385
+ '.messenger-home-message-btn:not(.messenger-feedback-btn)'
5386
+ );
5382
5387
  if (msgBtn) {
5383
5388
  msgBtn.addEventListener('click', () => {
5384
5389
  const convId = msgBtn.dataset.conversationId;
@@ -5395,11 +5400,35 @@
5395
5400
  });
5396
5401
  }
5397
5402
 
5403
+ const feedbackBtn = this.element.querySelector('.messenger-feedback-btn');
5404
+ if (feedbackBtn) {
5405
+ feedbackBtn.addEventListener('click', () => {
5406
+ const url = this.state.urls?.feedback;
5407
+
5408
+ if (this.options.onFeedbackClick) {
5409
+ this.options.onFeedbackClick();
5410
+ } else if (url) {
5411
+ window.open(url, '_blank');
5412
+ } else {
5413
+ console.warn(
5414
+ '[Messenger] No feedback destination configured. Set `feedbackUrl` in MessengerWidget options.'
5415
+ );
5416
+ }
5417
+ });
5418
+ }
5419
+
5398
5420
  this.element
5399
- .querySelectorAll('.messenger-home-changelog-item')
5400
- .forEach((item) => {
5401
- item.addEventListener('click', () => {
5402
- this.state.setView('changelog');
5421
+ .querySelectorAll('.messenger-home-changelog-card')
5422
+ .forEach((card) => {
5423
+ card.addEventListener('click', () => {
5424
+ const item = this.state.homeChangelogItems.find(
5425
+ (i) => i.id === card.dataset.changelogId
5426
+ );
5427
+ if (item?.url) {
5428
+ window.open(item.url, '_blank');
5429
+ } else {
5430
+ this.state.setView('changelog');
5431
+ }
5403
5432
  });
5404
5433
  });
5405
5434
 
@@ -5681,7 +5710,12 @@
5681
5710
  enableHelp: options.enableHelp !== false,
5682
5711
  enableChangelog: options.enableChangelog !== false,
5683
5712
  featuredContent: options.featuredContent || null,
5713
+ feedbackUrl: options.feedbackUrl || null,
5714
+ changelogUrl: options.changelogUrl || null,
5715
+ helpUrl: options.helpUrl || null,
5716
+ roadmapUrl: options.roadmapUrl || null,
5684
5717
  onSendMessage: options.onSendMessage || null,
5718
+ onFeedbackClick: options.onFeedbackClick || null,
5685
5719
  onArticleClick: options.onArticleClick || null,
5686
5720
  onChangelogClick: options.onChangelogClick || null,
5687
5721
  };
@@ -5693,6 +5727,12 @@
5693
5727
  enableHelp: this.messengerOptions.enableHelp,
5694
5728
  enableChangelog: this.messengerOptions.enableChangelog,
5695
5729
  userContext: this.sdk?.apiService?.getUserContext() || null,
5730
+ urls: {
5731
+ feedback: this.messengerOptions.feedbackUrl,
5732
+ changelog: this.messengerOptions.changelogUrl,
5733
+ help: this.messengerOptions.helpUrl,
5734
+ roadmap: this.messengerOptions.roadmapUrl,
5735
+ },
5696
5736
  });
5697
5737
 
5698
5738
  this.launcher = null;
@@ -5739,6 +5779,7 @@
5739
5779
  onSelectConversation: this._handleSelectConversation.bind(this),
5740
5780
  onStartNewConversation: this._handleNewConversationClick.bind(this),
5741
5781
  onIdentifyContact: this._handleIdentifyContact.bind(this),
5782
+ onFeedbackClick: this.messengerOptions.onFeedbackClick,
5742
5783
  onArticleClick: this.messengerOptions.onArticleClick,
5743
5784
  onChangelogClick: this.messengerOptions.onChangelogClick,
5744
5785
  });
@@ -6194,12 +6235,20 @@
6194
6235
  const response = await this.apiService.getHelpCollections();
6195
6236
  if (response.success && response.data) {
6196
6237
  const collections = response.data.collections || response.data;
6238
+ const helpBase = (this.messengerOptions.helpUrl || '').replace(
6239
+ /\/$/,
6240
+ ''
6241
+ );
6242
+
6197
6243
  return collections.map((collection) => ({
6198
6244
  id: collection.id,
6199
6245
  title: collection.title,
6200
6246
  description: collection.description || '',
6201
6247
  articleCount: collection.article_count || 0,
6202
- url: collection.url_slug ? `/help-docs/collections/${collection.url_slug}` : null,
6248
+ url:
6249
+ collection.url_slug && helpBase
6250
+ ? `${helpBase}/collections/${collection.url_slug}`
6251
+ : helpBase || null,
6203
6252
  }));
6204
6253
  }
6205
6254
  return [];
@@ -6304,7 +6353,7 @@
6304
6353
  try {
6305
6354
  await this.apiService.sendTypingIndicator(conversationId, isTyping);
6306
6355
  } catch (error) {
6307
- // Silent fail
6356
+ // silent fail
6308
6357
  }
6309
6358
  }
6310
6359
 
@@ -6412,6 +6461,9 @@
6412
6461
 
6413
6462
  if (response.success && response.data) {
6414
6463
  const changelogs = Array.isArray(response.data) ? response.data : [];
6464
+ const changelogBase = (
6465
+ this.messengerOptions.changelogUrl || ''
6466
+ ).replace(/\/$/, '');
6415
6467
 
6416
6468
  const mappedItems = changelogs.map((item) => ({
6417
6469
  id: item.id,
@@ -6420,7 +6472,10 @@
6420
6472
  tags: item.labels ? item.labels.map((label) => label.name) : [],
6421
6473
  coverImage: item.cover_image || null,
6422
6474
  publishedAt: item.published_at,
6423
- url: item.slug ? `/changelog/${item.slug}` : null,
6475
+ url:
6476
+ item.slug && changelogBase
6477
+ ? `${changelogBase}/${item.slug}`
6478
+ : changelogBase || null,
6424
6479
  }));
6425
6480
 
6426
6481
  return {