@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@product7/feedback-sdk",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
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",
@@ -639,10 +639,16 @@ const survey = sdk.createWidget('survey', {
639
639
  surveyType: 'nps',
640
640
  position: 'center',
641
641
  theme: 'light',
642
- title: 'How likely are you to recommend us?',
643
- description: 'Your feedback helps us improve.',
644
- lowLabel: 'Not likely',
645
- highLabel: 'Very likely',
642
+ description:
643
+ 'To what extent do you agree or disagree that our tools support the work you do?',
644
+ ratingScale: 5,
645
+ showTitle: false,
646
+ showDescription: true,
647
+ showFeedbackInput: false,
648
+ showSubmitButton: false,
649
+ autoSubmitOnSelect: true,
650
+ lowLabel: 'Strongly Disagree',
651
+ highLabel: 'Strongly Agree',
646
652
  onSubmit: (response) => {
647
653
  console.log('Survey submitted:', response);
648
654
  // Optional: send to analytics
@@ -4,17 +4,6 @@ export class HelpView {
4
4
  this.options = options;
5
5
  this.element = null;
6
6
  this._unsubscribe = null;
7
-
8
- this._avatarColors = [
9
- { bg: '#EF4444', text: '#FFFFFF' },
10
- { bg: '#F97316', text: '#FFFFFF' },
11
- { bg: '#F59E0B', text: '#FFFFFF' },
12
- { bg: '#10B981', text: '#FFFFFF' },
13
- { bg: '#06B6D4', text: '#FFFFFF' },
14
- { bg: '#3B82F6', text: '#FFFFFF' },
15
- { bg: '#8B5CF6', text: '#FFFFFF' },
16
- { bg: '#EC4899', text: '#FFFFFF' },
17
- ];
18
7
  }
19
8
 
20
9
  render() {
@@ -40,10 +29,8 @@ export class HelpView {
40
29
  <div class="messenger-help-header-top">
41
30
  <h2>Help</h2>
42
31
  <button class="sdk-close-btn" aria-label="Close">
43
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="18" height="18">
44
- <rect width="256" height="256" fill="none"/>
45
- <line x1="200" y1="56" x2="56" y2="200" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
46
- <line x1="200" y1="200" x2="56" y2="56" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
32
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256">
33
+ <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>
47
34
  </svg>
48
35
  </button>
49
36
  </div>
@@ -71,7 +58,7 @@ export class HelpView {
71
58
  const collections = this.state.helpArticles || [];
72
59
  const searchQuery = (this.state.helpSearchQuery || '').toLowerCase();
73
60
 
74
- const filtered = searchQuery
61
+ const filteredCollections = searchQuery
75
62
  ? collections.filter(
76
63
  (c) =>
77
64
  c.title.toLowerCase().includes(searchQuery) ||
@@ -79,119 +66,41 @@ export class HelpView {
79
66
  )
80
67
  : collections;
81
68
 
82
- if (filtered.length === 0) {
69
+ const headerEl = this.element.querySelector(
70
+ '.messenger-help-collections-header'
71
+ );
72
+ if (headerEl) {
73
+ headerEl.textContent = `${filteredCollections.length} collections`;
74
+ }
75
+
76
+ if (filteredCollections.length === 0) {
83
77
  collectionsContainer.innerHTML = this._renderEmptyState();
84
78
  return;
85
79
  }
86
80
 
87
- collectionsContainer.innerHTML = filtered
88
- .map((c) => this._renderCollectionItem(c))
81
+ collectionsContainer.innerHTML = filteredCollections
82
+ .map((collection) => this._renderCollectionItem(collection))
89
83
  .join('');
90
84
 
91
- // Resolve Phosphor icons async after render
92
- filtered.forEach((c) => {
93
- if (c.icon && !c.icon.startsWith('<svg')) {
94
- const item = collectionsContainer.querySelector(
95
- `[data-collection-id="${c.id}"] .messenger-help-collection-icon`
96
- );
97
- if (item) this._resolvePhosphorIcon(item, c.icon);
98
- }
99
- });
100
-
101
85
  this._attachCollectionEvents();
102
86
  }
103
87
 
104
88
  _renderCollectionItem(collection) {
105
- const count = collection.article_count || collection.articleCount || 0;
106
- const icon = this._renderIcon(collection.icon);
107
- const avatar = this._renderAuthorAvatar(collection);
108
-
89
+ const articleCount = collection.articleCount || 0;
109
90
  return `
110
91
  <div class="messenger-help-collection" data-collection-id="${collection.id}">
111
- <div class="messenger-help-collection-header">
112
- <div class="messenger-help-collection-icon">${icon}</div>
92
+ <div class="messenger-help-collection-content">
113
93
  <h3 class="messenger-help-collection-title">${collection.title}</h3>
94
+ <p class="messenger-help-collection-desc">${collection.description || ''}</p>
95
+ <span class="messenger-help-collection-count">${articleCount} articles</span>
114
96
  </div>
115
- ${
116
- collection.description
117
- ? `<p class="messenger-help-collection-desc">${collection.description}</p>`
118
- : ''
119
- }
120
- <div class="messenger-help-collection-footer">
121
- ${avatar}
122
- <span>${count} ${count === 1 ? 'article' : 'articles'}</span>
123
- </div>
124
- </div>
125
- `;
126
- }
127
-
128
- _renderIcon(icon) {
129
- if (!icon) return this._getFolderIcon();
130
- if (icon.startsWith('<svg')) return icon;
131
- // Iconify string — render placeholder, then fetch async
132
- return this._getFolderIcon();
133
- }
134
-
135
- async _resolvePhosphorIcon(el, iconStr) {
136
- // iconStr e.g. "ph:house-line-duotone"
137
- const [set, name] = iconStr.split(':');
138
- if (!set || !name) return;
139
- try {
140
- const res = await fetch(`https://api.iconify.design/${set}/${name}.svg`);
141
- if (!res.ok) return;
142
- const svg = await res.text();
143
- if (svg && svg.startsWith('<svg')) {
144
- el.innerHTML = svg;
145
- const s = el.querySelector('svg');
146
- if (s) {
147
- s.setAttribute('width', '16');
148
- s.setAttribute('height', '16');
149
- }
150
- }
151
- } catch (e) {
152
- // keep fallback folder icon
153
- }
154
- }
155
-
156
- _getFolderIcon() {
157
- return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="20" height="20">
158
- <rect width="256" height="256" fill="none"/>
159
- <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"/>
160
- </svg>`;
161
- }
162
-
163
- _renderAuthorAvatar(collection) {
164
- const author = collection.author;
165
- if (!author) return '';
166
-
167
- if (author.picture) {
168
- return `<img class="messenger-help-author-avatar" src="${author.picture}" alt="${author.name}" />`;
169
- }
170
-
171
- const color = this._getAvatarColor(collection.id);
172
- const initials = this._getInitials(author.name);
173
- return `
174
- <div class="messenger-help-author-avatar messenger-help-author-initials"
175
- style="background:${color.bg};color:${color.text}">
176
- ${initials}
97
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256" class="messenger-help-collection-arrow">
98
+ <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>
99
+ </svg>
177
100
  </div>
178
101
  `;
179
102
  }
180
103
 
181
- _getAvatarColor(id) {
182
- const hash = id.split('').reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
183
- return this._avatarColors[hash % this._avatarColors.length];
184
- }
185
-
186
- _getInitials(name) {
187
- return name
188
- .split(' ')
189
- .map((n) => n[0])
190
- .join('')
191
- .toUpperCase()
192
- .slice(0, 2);
193
- }
194
-
195
104
  _renderEmptyState() {
196
105
  const isSearching = this.state.helpSearchQuery;
197
106
 
@@ -262,7 +171,9 @@ export class HelpView {
262
171
  }
263
172
 
264
173
  destroy() {
265
- if (this._unsubscribe) this._unsubscribe();
174
+ if (this._unsubscribe) {
175
+ this._unsubscribe();
176
+ }
266
177
  if (this.element && this.element.parentNode) {
267
178
  this.element.parentNode.removeChild(this.element);
268
179
  }
package/types/index.d.ts CHANGED
@@ -114,6 +114,12 @@ declare module '@product7/feedback-sdk' {
114
114
  description?: string | null;
115
115
  lowLabel?: string | null;
116
116
  highLabel?: string | null;
117
+ ratingScale?: number | null;
118
+ showFeedbackInput?: boolean | null;
119
+ showSubmitButton?: boolean | null;
120
+ autoSubmitOnSelect?: boolean | null;
121
+ showTitle?: boolean | null;
122
+ showDescription?: boolean | null;
117
123
  customQuestions?: SurveyQuestion[];
118
124
  pages?: SurveyPage[];
119
125
  respondentId?: string | null;
@@ -132,6 +138,9 @@ declare module '@product7/feedback-sdk' {
132
138
  score: number | null;
133
139
  feedback: string;
134
140
  customAnswers: Record<string, any>;
141
+ pageAnswers?: Record<string, any>;
142
+ currentPageIndex?: number;
143
+ isSubmitting?: boolean;
135
144
  isVisible: boolean;
136
145
  };
137
146
  }