@product7/feedback-sdk 1.1.8 → 1.2.0
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 +456 -0
- package/dist/README.md +456 -0
- package/dist/feedback-sdk.js +5255 -941
- 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/APIService.js +272 -0
- package/src/core/FeedbackSDK.js +70 -1
- package/src/index.js +5 -1
- package/src/styles/messengerStyles.js +1657 -0
- package/src/styles/styles.js +96 -1
- package/src/widgets/BaseWidget.js +1 -1
- package/src/widgets/ButtonWidget.js +84 -49
- package/src/widgets/MessengerWidget.js +441 -0
- package/src/widgets/SurveyWidget.js +24 -8
- package/src/widgets/WidgetFactory.js +2 -0
- package/src/widgets/messenger/MessengerState.js +222 -0
- package/src/widgets/messenger/components/MessengerLauncher.js +119 -0
- package/src/widgets/messenger/components/MessengerPanel.js +130 -0
- package/src/widgets/messenger/components/NavigationTabs.js +134 -0
- package/src/widgets/messenger/views/ChangelogView.js +198 -0
- package/src/widgets/messenger/views/ChatView.js +284 -0
- package/src/widgets/messenger/views/ConversationsView.js +223 -0
- package/src/widgets/messenger/views/HelpView.js +191 -0
- package/src/widgets/messenger/views/HomeView.js +224 -0
- package/types/index.d.ts +129 -67
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelpView - Help collections browse with Intercom-style design
|
|
3
|
+
*/
|
|
4
|
+
export class HelpView {
|
|
5
|
+
constructor(state, options = {}) {
|
|
6
|
+
this.state = state;
|
|
7
|
+
this.options = options;
|
|
8
|
+
this.element = null;
|
|
9
|
+
this._unsubscribe = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
render() {
|
|
13
|
+
this.element = document.createElement('div');
|
|
14
|
+
this.element.className = 'messenger-view messenger-help-view';
|
|
15
|
+
|
|
16
|
+
this._updateContent();
|
|
17
|
+
|
|
18
|
+
// Subscribe to state changes
|
|
19
|
+
this._unsubscribe = this.state.subscribe((type) => {
|
|
20
|
+
if (type === 'helpArticlesUpdate' || type === 'helpSearchChange') {
|
|
21
|
+
this._updateCollectionsList();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return this.element;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_updateContent() {
|
|
29
|
+
const searchQuery = this.state.helpSearchQuery || '';
|
|
30
|
+
const collections = this.state.helpArticles || [];
|
|
31
|
+
const collectionCount = collections.length;
|
|
32
|
+
|
|
33
|
+
this.element.innerHTML = `
|
|
34
|
+
<div class="messenger-help-header">
|
|
35
|
+
<h2>Help</h2>
|
|
36
|
+
<button class="messenger-close-btn" aria-label="Close">
|
|
37
|
+
<i class="ph ph-x" style="font-size: 20px;"></i>
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="messenger-help-search">
|
|
42
|
+
<div class="messenger-help-search-wrapper">
|
|
43
|
+
<input
|
|
44
|
+
type="text"
|
|
45
|
+
class="messenger-help-search-input"
|
|
46
|
+
placeholder="Search for help"
|
|
47
|
+
value="${searchQuery}"
|
|
48
|
+
/>
|
|
49
|
+
<i class="ph ph-magnifying-glass messenger-help-search-icon" style="font-size: 18px;"></i>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="messenger-help-body">
|
|
54
|
+
<div class="messenger-help-collections-header">
|
|
55
|
+
${collectionCount} collections
|
|
56
|
+
</div>
|
|
57
|
+
<div class="messenger-help-collections"></div>
|
|
58
|
+
</div>
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
this._updateCollectionsList();
|
|
62
|
+
this._attachEvents();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_updateCollectionsList() {
|
|
66
|
+
const collectionsContainer = this.element.querySelector(
|
|
67
|
+
'.messenger-help-collections'
|
|
68
|
+
);
|
|
69
|
+
const collections = this.state.helpArticles || [];
|
|
70
|
+
const searchQuery = (this.state.helpSearchQuery || '').toLowerCase();
|
|
71
|
+
|
|
72
|
+
// Filter collections by search
|
|
73
|
+
const filteredCollections = searchQuery
|
|
74
|
+
? collections.filter(
|
|
75
|
+
(c) =>
|
|
76
|
+
c.title.toLowerCase().includes(searchQuery) ||
|
|
77
|
+
(c.description && c.description.toLowerCase().includes(searchQuery))
|
|
78
|
+
)
|
|
79
|
+
: collections;
|
|
80
|
+
|
|
81
|
+
// Update collection count
|
|
82
|
+
const headerEl = this.element.querySelector(
|
|
83
|
+
'.messenger-help-collections-header'
|
|
84
|
+
);
|
|
85
|
+
if (headerEl) {
|
|
86
|
+
headerEl.textContent = `${filteredCollections.length} collections`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (filteredCollections.length === 0) {
|
|
90
|
+
collectionsContainer.innerHTML = this._renderEmptyState();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
collectionsContainer.innerHTML = filteredCollections
|
|
95
|
+
.map((collection) => this._renderCollectionItem(collection))
|
|
96
|
+
.join('');
|
|
97
|
+
|
|
98
|
+
// Attach click events
|
|
99
|
+
this._attachCollectionEvents();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
_renderCollectionItem(collection) {
|
|
103
|
+
const articleCount = collection.articleCount || 0;
|
|
104
|
+
return `
|
|
105
|
+
<div class="messenger-help-collection" data-collection-id="${collection.id}">
|
|
106
|
+
<div class="messenger-help-collection-content">
|
|
107
|
+
<h3 class="messenger-help-collection-title">${collection.title}</h3>
|
|
108
|
+
<p class="messenger-help-collection-desc">${collection.description || ''}</p>
|
|
109
|
+
<span class="messenger-help-collection-count">${articleCount} articles</span>
|
|
110
|
+
</div>
|
|
111
|
+
<i class="ph ph-caret-right messenger-help-collection-arrow" style="font-size: 20px;"></i>
|
|
112
|
+
</div>
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_renderEmptyState() {
|
|
117
|
+
const isSearching = this.state.helpSearchQuery;
|
|
118
|
+
|
|
119
|
+
if (isSearching) {
|
|
120
|
+
return `
|
|
121
|
+
<div class="messenger-help-empty">
|
|
122
|
+
<div class="messenger-help-empty-icon">
|
|
123
|
+
<i class="ph ph-magnifying-glass" style="font-size: 48px;"></i>
|
|
124
|
+
</div>
|
|
125
|
+
<h3>No results found</h3>
|
|
126
|
+
<p>Try a different search term</p>
|
|
127
|
+
</div>
|
|
128
|
+
`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return `
|
|
132
|
+
<div class="messenger-help-empty">
|
|
133
|
+
<div class="messenger-help-empty-icon">
|
|
134
|
+
<i class="ph ph-question" style="font-size: 48px;"></i>
|
|
135
|
+
</div>
|
|
136
|
+
<h3>Help collections</h3>
|
|
137
|
+
<p>No collections available yet</p>
|
|
138
|
+
</div>
|
|
139
|
+
`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_attachEvents() {
|
|
143
|
+
// Close button
|
|
144
|
+
this.element
|
|
145
|
+
.querySelector('.messenger-close-btn')
|
|
146
|
+
.addEventListener('click', () => {
|
|
147
|
+
this.state.setOpen(false);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Search input
|
|
151
|
+
const searchInput = this.element.querySelector(
|
|
152
|
+
'.messenger-help-search-input'
|
|
153
|
+
);
|
|
154
|
+
let searchTimeout;
|
|
155
|
+
searchInput.addEventListener('input', (e) => {
|
|
156
|
+
clearTimeout(searchTimeout);
|
|
157
|
+
searchTimeout = setTimeout(() => {
|
|
158
|
+
this.state.setHelpSearchQuery(e.target.value);
|
|
159
|
+
}, 300);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
this._attachCollectionEvents();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
_attachCollectionEvents() {
|
|
166
|
+
this.element
|
|
167
|
+
.querySelectorAll('.messenger-help-collection')
|
|
168
|
+
.forEach((item) => {
|
|
169
|
+
item.addEventListener('click', () => {
|
|
170
|
+
const collectionId = item.dataset.collectionId;
|
|
171
|
+
const collection = this.state.helpArticles.find(
|
|
172
|
+
(c) => c.id === collectionId
|
|
173
|
+
);
|
|
174
|
+
if (collection && collection.url) {
|
|
175
|
+
window.open(collection.url, '_blank');
|
|
176
|
+
} else if (this.options.onArticleClick) {
|
|
177
|
+
this.options.onArticleClick(collection);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
destroy() {
|
|
184
|
+
if (this._unsubscribe) {
|
|
185
|
+
this._unsubscribe();
|
|
186
|
+
}
|
|
187
|
+
if (this.element && this.element.parentNode) {
|
|
188
|
+
this.element.parentNode.removeChild(this.element);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HomeView - Welcome screen with team info and quick actions
|
|
3
|
+
*/
|
|
4
|
+
export class HomeView {
|
|
5
|
+
constructor(state, options = {}) {
|
|
6
|
+
this.state = state;
|
|
7
|
+
this.options = options;
|
|
8
|
+
this.element = null;
|
|
9
|
+
this._unsubscribe = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
render() {
|
|
13
|
+
this.element = document.createElement('div');
|
|
14
|
+
this.element.className = 'messenger-view messenger-home-view';
|
|
15
|
+
|
|
16
|
+
this._updateContent();
|
|
17
|
+
|
|
18
|
+
// Subscribe to state changes to re-render when data loads
|
|
19
|
+
this._unsubscribe = this.state.subscribe((type) => {
|
|
20
|
+
if (type === 'homeChangelogUpdate' || type === 'conversationsUpdate') {
|
|
21
|
+
this._updateContent();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return this.element;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_updateContent() {
|
|
29
|
+
const avatarsHtml = this._renderAvatarStack();
|
|
30
|
+
const recentChangelogHtml = this._renderRecentChangelog();
|
|
31
|
+
|
|
32
|
+
this.element.innerHTML = `
|
|
33
|
+
<div class="messenger-home-header">
|
|
34
|
+
<div class="messenger-home-header-top">
|
|
35
|
+
<div class="messenger-home-logo">
|
|
36
|
+
${this.options.logoUrl ? `<img src="${this.options.logoUrl}" alt="${this.state.teamName}" />` : ''}
|
|
37
|
+
</div>
|
|
38
|
+
<div class="messenger-home-avatars">${avatarsHtml}</div>
|
|
39
|
+
<button class="messenger-close-btn" aria-label="Close">
|
|
40
|
+
<i class="ph ph-x" style="font-size: 20px;"></i>
|
|
41
|
+
</button>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="messenger-home-welcome">
|
|
44
|
+
<span class="messenger-home-greeting">Hello there.</span>
|
|
45
|
+
<span class="messenger-home-question">${this.state.welcomeMessage}</span>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="messenger-home-body">
|
|
50
|
+
<button class="messenger-home-message-btn">
|
|
51
|
+
<span>Send us a message</span>
|
|
52
|
+
<i class="ph ph-arrow-right" style="font-size: 16px;"></i>
|
|
53
|
+
</button>
|
|
54
|
+
|
|
55
|
+
${this._renderFeaturedCard()}
|
|
56
|
+
|
|
57
|
+
${recentChangelogHtml}
|
|
58
|
+
</div>
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
this._attachEvents();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_renderAvatarStack() {
|
|
65
|
+
const avatars = this.state.teamAvatars;
|
|
66
|
+
if (!avatars || avatars.length === 0) {
|
|
67
|
+
// Default avatars with initials
|
|
68
|
+
return `
|
|
69
|
+
<div class="messenger-avatar-stack">
|
|
70
|
+
<div class="messenger-avatar" style="background: #5856d6;">S</div>
|
|
71
|
+
<div class="messenger-avatar" style="background: #007aff;">T</div>
|
|
72
|
+
</div>
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const avatarItems = avatars
|
|
77
|
+
.slice(0, 3)
|
|
78
|
+
.map((avatar, i) => {
|
|
79
|
+
if (typeof avatar === 'string' && avatar.startsWith('http')) {
|
|
80
|
+
return `<img class="messenger-avatar" src="${avatar}" alt="Team member" style="z-index: ${3 - i};" />`;
|
|
81
|
+
}
|
|
82
|
+
return `<div class="messenger-avatar" style="background: ${this._getAvatarColor(i)}; z-index: ${3 - i};">${avatar.charAt(0).toUpperCase()}</div>`;
|
|
83
|
+
})
|
|
84
|
+
.join('');
|
|
85
|
+
|
|
86
|
+
return `<div class="messenger-avatar-stack">${avatarItems}</div>`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_getAvatarColor(index) {
|
|
90
|
+
const colors = ['#5856d6', '#007aff', '#34c759', '#ff9500', '#ff3b30'];
|
|
91
|
+
return colors[index % colors.length];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_renderFeaturedCard() {
|
|
95
|
+
// Only show if there's featured content configured
|
|
96
|
+
if (!this.options.featuredContent) {
|
|
97
|
+
return '';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const { title, description, imageUrl, action } =
|
|
101
|
+
this.options.featuredContent;
|
|
102
|
+
|
|
103
|
+
return `
|
|
104
|
+
<div class="messenger-home-featured">
|
|
105
|
+
${imageUrl ? `<img src="${imageUrl}" alt="${title}" class="messenger-home-featured-image" onerror="this.style.display='none';" />` : ''}
|
|
106
|
+
<div class="messenger-home-featured-content">
|
|
107
|
+
<h3>${title}</h3>
|
|
108
|
+
<p>${description}</p>
|
|
109
|
+
</div>
|
|
110
|
+
${action ? `<button class="messenger-home-featured-btn" data-action="${action.type}" data-value="${action.value}">${action.label}</button>` : ''}
|
|
111
|
+
</div>
|
|
112
|
+
`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_renderRecentChangelog() {
|
|
116
|
+
// Show recent changelog preview as cards with images
|
|
117
|
+
const changelogItems = this.state.homeChangelogItems;
|
|
118
|
+
if (changelogItems.length === 0) {
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const changelogHtml = changelogItems
|
|
123
|
+
.map(
|
|
124
|
+
(item) => `
|
|
125
|
+
<div class="messenger-home-changelog-card" data-changelog-id="${item.id}">
|
|
126
|
+
${
|
|
127
|
+
item.coverImage
|
|
128
|
+
? `
|
|
129
|
+
<div class="messenger-home-changelog-cover">
|
|
130
|
+
<img src="${item.coverImage}" alt="${item.title}" onerror="this.style.display='none';" />
|
|
131
|
+
${item.coverText ? `<span class="messenger-home-changelog-cover-text">${item.coverText}</span>` : ''}
|
|
132
|
+
</div>
|
|
133
|
+
`
|
|
134
|
+
: ''
|
|
135
|
+
}
|
|
136
|
+
<div class="messenger-home-changelog-card-content">
|
|
137
|
+
<h4 class="messenger-home-changelog-card-title">${item.title}</h4>
|
|
138
|
+
<p class="messenger-home-changelog-card-desc">${item.description || ''}</p>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
`
|
|
142
|
+
)
|
|
143
|
+
.join('');
|
|
144
|
+
|
|
145
|
+
return `
|
|
146
|
+
<div class="messenger-home-changelog-section">
|
|
147
|
+
${changelogHtml}
|
|
148
|
+
</div>
|
|
149
|
+
`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
_formatDate(dateString) {
|
|
153
|
+
if (!dateString) return '';
|
|
154
|
+
const date = new Date(dateString);
|
|
155
|
+
const now = new Date();
|
|
156
|
+
const diffDays = Math.floor((now - date) / (1000 * 60 * 60 * 24));
|
|
157
|
+
|
|
158
|
+
if (diffDays === 0) return 'Today';
|
|
159
|
+
if (diffDays === 1) return 'Yesterday';
|
|
160
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
161
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
_attachEvents() {
|
|
165
|
+
// Close button
|
|
166
|
+
this.element
|
|
167
|
+
.querySelector('.messenger-close-btn')
|
|
168
|
+
.addEventListener('click', () => {
|
|
169
|
+
this.state.setOpen(false);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Send message button
|
|
173
|
+
this.element
|
|
174
|
+
.querySelector('.messenger-home-message-btn')
|
|
175
|
+
.addEventListener('click', () => {
|
|
176
|
+
this.state.setView('messages');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Changelog items
|
|
180
|
+
this.element
|
|
181
|
+
.querySelectorAll('.messenger-home-changelog-item')
|
|
182
|
+
.forEach((item) => {
|
|
183
|
+
item.addEventListener('click', () => {
|
|
184
|
+
// Navigate to changelog view with specific item selected
|
|
185
|
+
this.state.setView('changelog');
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// See all changelog
|
|
190
|
+
const seeAllBtn = this.element.querySelector(
|
|
191
|
+
'.messenger-home-changelog-all'
|
|
192
|
+
);
|
|
193
|
+
if (seeAllBtn) {
|
|
194
|
+
seeAllBtn.addEventListener('click', () => {
|
|
195
|
+
this.state.setView('changelog');
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Featured card action
|
|
200
|
+
const featuredBtn = this.element.querySelector(
|
|
201
|
+
'.messenger-home-featured-btn'
|
|
202
|
+
);
|
|
203
|
+
if (featuredBtn) {
|
|
204
|
+
featuredBtn.addEventListener('click', () => {
|
|
205
|
+
const action = featuredBtn.dataset.action;
|
|
206
|
+
const value = featuredBtn.dataset.value;
|
|
207
|
+
if (action === 'url') {
|
|
208
|
+
window.open(value, '_blank');
|
|
209
|
+
} else if (action === 'view') {
|
|
210
|
+
this.state.setView(value);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
destroy() {
|
|
217
|
+
if (this._unsubscribe) {
|
|
218
|
+
this._unsubscribe();
|
|
219
|
+
}
|
|
220
|
+
if (this.element && this.element.parentNode) {
|
|
221
|
+
this.element.parentNode.removeChild(this.element);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,73 +1,135 @@
|
|
|
1
1
|
declare module '@product7/feedback-sdk' {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
export interface FeedbackConfig {
|
|
3
|
+
workspace: string;
|
|
4
|
+
userContext?: UserContext;
|
|
5
|
+
debug?: boolean;
|
|
6
|
+
boardId?: string;
|
|
7
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
8
|
+
theme?: 'light' | 'dark';
|
|
9
|
+
apiUrl?: string;
|
|
10
|
+
autoShow?: boolean;
|
|
11
|
+
}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
export interface UserContext {
|
|
14
|
+
user_id?: string;
|
|
15
|
+
email?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
custom_fields?: Record<string, any>;
|
|
18
|
+
company?: {
|
|
19
|
+
id?: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
monthly_spend?: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
export interface ButtonWidget {
|
|
26
|
+
id: string;
|
|
27
|
+
type: 'button';
|
|
28
|
+
mount(container?: string | HTMLElement): this;
|
|
29
|
+
destroy(): void;
|
|
30
|
+
show(): this;
|
|
31
|
+
hide(): this;
|
|
32
|
+
openModal(): void;
|
|
33
|
+
closeModal(): void;
|
|
34
|
+
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
export class FeedbackSDK {
|
|
37
|
+
constructor(config: FeedbackConfig);
|
|
38
|
+
init(): Promise<{
|
|
39
|
+
initialized: boolean;
|
|
40
|
+
config?: any;
|
|
41
|
+
sessionToken?: string;
|
|
42
|
+
expiresIn?: number;
|
|
43
|
+
}>;
|
|
44
|
+
createWidget(
|
|
45
|
+
type: 'button',
|
|
46
|
+
options?: Partial<FeedbackConfig>
|
|
47
|
+
): ButtonWidget;
|
|
48
|
+
setUserContext(userContext: UserContext): void;
|
|
49
|
+
getUserContext(): UserContext | null;
|
|
50
|
+
destroy(): void;
|
|
51
|
+
readonly initialized: boolean;
|
|
52
|
+
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
isReady: () => boolean;
|
|
64
|
-
setUserContext: (userContext: UserContext) => void;
|
|
65
|
-
onReady: (callback: (sdk: FeedbackSDK) => void) => void;
|
|
66
|
-
onError: (callback: (error: Error) => void) => void;
|
|
67
|
-
version: string;
|
|
68
|
-
instance: FeedbackSDK | null;
|
|
69
|
-
}
|
|
54
|
+
export type SurveyType = 'nps' | 'csat' | 'ces' | 'custom';
|
|
55
|
+
|
|
56
|
+
export interface SurveyQuestion {
|
|
57
|
+
id?: string;
|
|
58
|
+
label: string;
|
|
59
|
+
type: 'select' | 'text';
|
|
60
|
+
placeholder?: string;
|
|
61
|
+
options?: Array<{ value: string; label: string }>;
|
|
62
|
+
}
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
64
|
+
export interface SurveyWidgetResponse {
|
|
65
|
+
type: SurveyType;
|
|
66
|
+
score: number | null;
|
|
67
|
+
feedback: string;
|
|
68
|
+
customAnswers: Record<string, any>;
|
|
69
|
+
timestamp: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface SurveyWidgetOptions {
|
|
73
|
+
surveyId?: string | null;
|
|
74
|
+
surveyType?: SurveyType;
|
|
75
|
+
position?: 'bottom-right' | 'bottom-left' | 'center' | 'bottom';
|
|
76
|
+
title?: string | null;
|
|
77
|
+
description?: string | null;
|
|
78
|
+
lowLabel?: string | null;
|
|
79
|
+
highLabel?: string | null;
|
|
80
|
+
customQuestions?: SurveyQuestion[];
|
|
81
|
+
theme?: 'light' | 'dark';
|
|
82
|
+
onSubmit?: (response: SurveyWidgetResponse) => void;
|
|
83
|
+
onDismiss?: () => void;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface SurveyWidget {
|
|
87
|
+
show(): this;
|
|
88
|
+
hide(): this;
|
|
89
|
+
destroy(): void;
|
|
90
|
+
surveyOptions: SurveyWidgetOptions;
|
|
91
|
+
surveyState: {
|
|
92
|
+
score: number | null;
|
|
93
|
+
feedback: string;
|
|
94
|
+
customAnswers: Record<string, any>;
|
|
95
|
+
isVisible: boolean;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface SurveyConfig {
|
|
100
|
+
workspace: string;
|
|
101
|
+
userContext?: UserContext;
|
|
102
|
+
debug?: boolean;
|
|
103
|
+
apiUrl?: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export class SurveySDK {
|
|
107
|
+
constructor(config: SurveyConfig);
|
|
108
|
+
init(): Promise<{ initialized: boolean }>;
|
|
109
|
+
createWidget(type: 'survey', options: SurveyWidgetOptions): SurveyWidget;
|
|
110
|
+
setUserContext(userContext: UserContext): void;
|
|
111
|
+
getUserContext(): UserContext | null;
|
|
112
|
+
destroy(): void;
|
|
113
|
+
readonly initialized: boolean;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
interface FeedbackSDKExport {
|
|
117
|
+
FeedbackSDK: typeof FeedbackSDK;
|
|
118
|
+
ButtonWidget: any;
|
|
119
|
+
create: (config: FeedbackConfig) => FeedbackSDK;
|
|
120
|
+
initWithUser: (
|
|
121
|
+
config: Omit<FeedbackConfig, 'userContext'>,
|
|
122
|
+
userContext: UserContext
|
|
123
|
+
) => Promise<FeedbackSDK>;
|
|
124
|
+
getInstance: () => FeedbackSDK | null;
|
|
125
|
+
isReady: () => boolean;
|
|
126
|
+
setUserContext: (userContext: UserContext) => void;
|
|
127
|
+
onReady: (callback: (sdk: FeedbackSDK) => void) => void;
|
|
128
|
+
onError: (callback: (error: Error) => void) => void;
|
|
129
|
+
version: string;
|
|
130
|
+
instance: FeedbackSDK | null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const FeedbackSDKDefault: FeedbackSDKExport;
|
|
134
|
+
export default FeedbackSDKDefault;
|
|
135
|
+
}
|