@product7/product7-js 0.1.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 +1025 -0
- package/dist/README.md +1025 -0
- package/dist/product7-js.js +14658 -0
- package/dist/product7-js.js.map +1 -0
- package/dist/product7-js.min.js +2 -0
- package/dist/product7-js.min.js.map +1 -0
- package/package.json +114 -0
- package/src/api/mock-data/index.js +360 -0
- package/src/api/services/ChangelogService.js +28 -0
- package/src/api/services/FeedbackService.js +44 -0
- package/src/api/services/HelpService.js +50 -0
- package/src/api/services/MessengerService.js +279 -0
- package/src/api/services/SurveyService.js +127 -0
- package/src/api/utils/helpers.js +30 -0
- package/src/core/APIService.js +303 -0
- package/src/core/BaseAPIService.js +298 -0
- package/src/core/EventBus.js +54 -0
- package/src/core/Product7.js +812 -0
- package/src/core/WebSocketService.js +275 -0
- package/src/docs/api.md +226 -0
- package/src/docs/example.md +461 -0
- package/src/docs/framework-integrations.md +714 -0
- package/src/docs/installation.md +281 -0
- package/src/index.js +894 -0
- package/src/styles/base.js +50 -0
- package/src/styles/changelog.js +665 -0
- package/src/styles/components.js +553 -0
- package/src/styles/design-tokens.js +124 -0
- package/src/styles/feedback.js +325 -0
- package/src/styles/messenger-components.js +632 -0
- package/src/styles/messenger-core.js +233 -0
- package/src/styles/messenger-features.js +169 -0
- package/src/styles/messenger-views.js +877 -0
- package/src/styles/messenger.js +17 -0
- package/src/styles/messengerCustomStyles.js +114 -0
- package/src/styles/styles.js +26 -0
- package/src/styles/survey.js +894 -0
- package/src/utils/errors.js +142 -0
- package/src/utils/helpers.js +219 -0
- package/src/widgets/BaseWidget.js +548 -0
- package/src/widgets/ButtonWidget.js +104 -0
- package/src/widgets/ChangelogWidget.js +615 -0
- package/src/widgets/InlineWidget.js +148 -0
- package/src/widgets/MessengerWidget.js +979 -0
- package/src/widgets/SurveyWidget.js +1325 -0
- package/src/widgets/TabWidget.js +45 -0
- package/src/widgets/WidgetFactory.js +70 -0
- package/src/widgets/messenger/MessengerState.js +323 -0
- package/src/widgets/messenger/components/MessengerLauncher.js +124 -0
- package/src/widgets/messenger/components/MessengerPanel.js +111 -0
- package/src/widgets/messenger/components/NavigationTabs.js +130 -0
- package/src/widgets/messenger/views/ChangelogView.js +167 -0
- package/src/widgets/messenger/views/ChatView.js +592 -0
- package/src/widgets/messenger/views/ConversationsView.js +244 -0
- package/src/widgets/messenger/views/HelpView.js +239 -0
- package/src/widgets/messenger/views/HomeView.js +300 -0
- package/src/widgets/messenger/views/PreChatFormView.js +109 -0
- package/types/index.d.ts +341 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
export class ConversationsView {
|
|
2
|
+
constructor(state, options = {}) {
|
|
3
|
+
this.state = state;
|
|
4
|
+
this.options = options;
|
|
5
|
+
this.element = null;
|
|
6
|
+
this._unsubscribe = null;
|
|
7
|
+
this.avatarColors = [
|
|
8
|
+
'#155EEF',
|
|
9
|
+
'#8b5cf6',
|
|
10
|
+
'#10b981',
|
|
11
|
+
'#f59e0b',
|
|
12
|
+
'#ef4444',
|
|
13
|
+
'#ec4899',
|
|
14
|
+
'#06b6d4',
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
render() {
|
|
19
|
+
this.element = document.createElement('div');
|
|
20
|
+
this.element.className = 'messenger-view messenger-conversations-view';
|
|
21
|
+
|
|
22
|
+
this._updateContent();
|
|
23
|
+
this._attachEvents();
|
|
24
|
+
|
|
25
|
+
this._unsubscribe = this.state.subscribe((type) => {
|
|
26
|
+
if (
|
|
27
|
+
type === 'conversationsUpdate' ||
|
|
28
|
+
type === 'conversationAdded' ||
|
|
29
|
+
type === 'conversationRead' ||
|
|
30
|
+
type === 'conversationUpdated'
|
|
31
|
+
) {
|
|
32
|
+
this._updateContent();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return this.element;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_getAvatarColor(name) {
|
|
40
|
+
// Generate consistent color based on name
|
|
41
|
+
const charCode = (name || 'S').charCodeAt(0);
|
|
42
|
+
return this.avatarColors[charCode % this.avatarColors.length];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_updateContent() {
|
|
46
|
+
const conversations = this.state.conversations;
|
|
47
|
+
|
|
48
|
+
let conversationsHtml;
|
|
49
|
+
if (conversations.length === 0) {
|
|
50
|
+
conversationsHtml = `
|
|
51
|
+
<div class="messenger-empty-state">
|
|
52
|
+
<div class="messenger-empty-state-icon">
|
|
53
|
+
<iconify-icon icon="ph:chat-circle-duotone" width="48" height="48"></iconify-icon>
|
|
54
|
+
</div>
|
|
55
|
+
<h3>No conversations yet</h3>
|
|
56
|
+
<p>Start a new conversation with our team</p>
|
|
57
|
+
</div>
|
|
58
|
+
`;
|
|
59
|
+
} else {
|
|
60
|
+
conversationsHtml = `
|
|
61
|
+
<div class="messenger-conversations-list">
|
|
62
|
+
${conversations.map((conv) => this._renderConversationItem(conv)).join('')}
|
|
63
|
+
</div>
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.element.innerHTML = `
|
|
68
|
+
<div class="messenger-conversations-header">
|
|
69
|
+
<h2>Messages</h2>
|
|
70
|
+
<button class="sdk-close-btn" aria-label="Close">
|
|
71
|
+
<iconify-icon icon="ph:x-duotone" width="18" height="18"></iconify-icon>
|
|
72
|
+
</button>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div class="messenger-conversations-body">
|
|
76
|
+
${conversationsHtml}
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="messenger-conversations-footer">
|
|
80
|
+
<button class="messenger-new-message-btn">
|
|
81
|
+
<span>Send us a message</span>
|
|
82
|
+
<iconify-icon icon="ph:paper-plane-right" width="20" height="20" style="flex-shrink: 0;"></iconify-icon>
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
this._attachEvents();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
_renderConversationItem(conversation) {
|
|
91
|
+
const unreadClass = conversation.unread > 0 ? 'unread' : '';
|
|
92
|
+
const timeAgo = this._formatTimeAgo(conversation.lastMessageTime);
|
|
93
|
+
const avatarsHtml = this._renderConversationAvatars(
|
|
94
|
+
conversation.participants
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return `
|
|
98
|
+
<div class="messenger-conversation-item ${unreadClass}" data-conversation-id="${conversation.id}">
|
|
99
|
+
<div class="messenger-conversation-avatars">
|
|
100
|
+
${avatarsHtml}
|
|
101
|
+
</div>
|
|
102
|
+
<div class="messenger-conversation-content">
|
|
103
|
+
<div class="messenger-conversation-header">
|
|
104
|
+
<span class="messenger-conversation-title">${conversation.title || 'Chat with team'}</span>
|
|
105
|
+
<span class="messenger-conversation-time">${timeAgo}</span>
|
|
106
|
+
</div>
|
|
107
|
+
<div class="messenger-conversation-preview">
|
|
108
|
+
${conversation.unread > 0 ? '<span class="messenger-unread-dot"></span>' : ''}
|
|
109
|
+
<span class="messenger-conversation-message">${this._truncateMessage(conversation.lastMessage)}</span>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_renderConversationAvatars(participants) {
|
|
117
|
+
if (!participants || participants.length === 0) {
|
|
118
|
+
const color = this._getAvatarColor('S');
|
|
119
|
+
return `<div class="sdk-avatar sdk-avatar-md" style="background-color: ${color};">S</div>`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const p = participants[0];
|
|
123
|
+
if (p.avatarUrl) {
|
|
124
|
+
return `<div class="sdk-avatar sdk-avatar-md"><img src="${p.avatarUrl}" alt="${p.name}" /></div>`;
|
|
125
|
+
}
|
|
126
|
+
const initial = (p.name || 'S').charAt(0).toUpperCase();
|
|
127
|
+
const color = this._getAvatarColor(p.name);
|
|
128
|
+
return `<div class="sdk-avatar sdk-avatar-md" style="background-color: ${color};">${initial}</div>`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
_renderAvatarStack() {
|
|
132
|
+
const avatars = this.state.teamAvatars;
|
|
133
|
+
if (!avatars || avatars.length === 0) {
|
|
134
|
+
const color1 = this._getAvatarColor('S');
|
|
135
|
+
const color2 = this._getAvatarColor('T');
|
|
136
|
+
return `
|
|
137
|
+
<div class="messenger-avatar-stack">
|
|
138
|
+
<div class="sdk-avatar sdk-avatar-sm" style="background-color: ${color1};">S</div>
|
|
139
|
+
<div class="sdk-avatar sdk-avatar-sm" style="background-color: ${color2};">T</div>
|
|
140
|
+
</div>
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const avatarItems = avatars
|
|
145
|
+
.slice(0, 2)
|
|
146
|
+
.map((avatar, index) => {
|
|
147
|
+
if (typeof avatar === 'string' && avatar.startsWith('http')) {
|
|
148
|
+
return `<div class="sdk-avatar sdk-avatar-sm"><img src="${avatar}" alt="Team member" /></div>`;
|
|
149
|
+
}
|
|
150
|
+
const initial = avatar.charAt(0).toUpperCase();
|
|
151
|
+
const color = this._getAvatarColor(avatar);
|
|
152
|
+
return `<div class="sdk-avatar sdk-avatar-sm" style="background-color: ${color};">${initial}</div>`;
|
|
153
|
+
})
|
|
154
|
+
.join('');
|
|
155
|
+
|
|
156
|
+
return `<div class="messenger-avatar-stack">${avatarItems}</div>`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
_formatTimeAgo(timestamp) {
|
|
160
|
+
if (!timestamp) return '';
|
|
161
|
+
const date = new Date(timestamp);
|
|
162
|
+
const now = new Date();
|
|
163
|
+
const diffMs = now - date;
|
|
164
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
165
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
166
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
167
|
+
|
|
168
|
+
if (diffMins < 1) return 'now';
|
|
169
|
+
if (diffMins < 60) return `${diffMins}m`;
|
|
170
|
+
if (diffHours < 24) return `${diffHours}h`;
|
|
171
|
+
if (diffDays < 7) return `${diffDays}d`;
|
|
172
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
_truncateMessage(message) {
|
|
176
|
+
if (!message) return 'No messages yet';
|
|
177
|
+
const maxLength = 50;
|
|
178
|
+
if (message.length <= maxLength) return message;
|
|
179
|
+
return message.substring(0, maxLength) + '...';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
_attachEvents() {
|
|
183
|
+
const closeBtn = this.element.querySelector('.sdk-close-btn');
|
|
184
|
+
if (closeBtn) {
|
|
185
|
+
closeBtn.addEventListener('click', () => {
|
|
186
|
+
this.state.setOpen(false);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
this.element
|
|
191
|
+
.querySelectorAll('.messenger-conversation-item')
|
|
192
|
+
.forEach((item) => {
|
|
193
|
+
item.addEventListener('click', () => {
|
|
194
|
+
const convId = item.dataset.conversationId;
|
|
195
|
+
this.state.setActiveConversation(convId);
|
|
196
|
+
this.state.markAsRead(convId);
|
|
197
|
+
this.state.setView('chat');
|
|
198
|
+
|
|
199
|
+
if (this.options.onSelectConversation) {
|
|
200
|
+
this.options.onSelectConversation(convId);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const newMsgBtn = this.element.querySelector('.messenger-new-message-btn');
|
|
206
|
+
if (newMsgBtn) {
|
|
207
|
+
newMsgBtn.addEventListener('click', () => {
|
|
208
|
+
this._startNewConversation();
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
_startNewConversation() {
|
|
214
|
+
// If there's an open conversation, route to it instead of creating new
|
|
215
|
+
const openConversation = this.state.conversations.find(
|
|
216
|
+
(c) => c.status === 'open'
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
if (openConversation) {
|
|
220
|
+
this.state.setActiveConversation(openConversation.id);
|
|
221
|
+
this.state.markAsRead(openConversation.id);
|
|
222
|
+
this.state.setView('chat');
|
|
223
|
+
if (this.options.onSelectConversation) {
|
|
224
|
+
this.options.onSelectConversation(openConversation.id);
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
this.state.setActiveConversation(null);
|
|
228
|
+
if (this.options.onStartNewConversation) {
|
|
229
|
+
this.options.onStartNewConversation();
|
|
230
|
+
} else {
|
|
231
|
+
this.state.setView('chat');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
destroy() {
|
|
237
|
+
if (this._unsubscribe) {
|
|
238
|
+
this._unsubscribe();
|
|
239
|
+
}
|
|
240
|
+
if (this.element && this.element.parentNode) {
|
|
241
|
+
this.element.parentNode.removeChild(this.element);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
export class HelpView {
|
|
2
|
+
constructor(state, options = {}) {
|
|
3
|
+
this.state = state;
|
|
4
|
+
this.options = options;
|
|
5
|
+
this.element = null;
|
|
6
|
+
this._unsubscribe = null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
render() {
|
|
10
|
+
this.element = document.createElement('div');
|
|
11
|
+
this.element.className = 'messenger-view messenger-help-view';
|
|
12
|
+
|
|
13
|
+
this._updateContent();
|
|
14
|
+
|
|
15
|
+
this._unsubscribe = this.state.subscribe((type) => {
|
|
16
|
+
if (type === 'helpArticlesUpdate' || type === 'helpSearchChange') {
|
|
17
|
+
this._updateCollectionsList();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return this.element;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_updateContent() {
|
|
25
|
+
const searchQuery = this.state.helpSearchQuery || '';
|
|
26
|
+
|
|
27
|
+
this.element.innerHTML = `
|
|
28
|
+
<div class="messenger-help-header">
|
|
29
|
+
<div class="messenger-help-header-top">
|
|
30
|
+
<h2>Help</h2>
|
|
31
|
+
<button class="sdk-close-btn messenger-help-close-btn" aria-label="Close">
|
|
32
|
+
<iconify-icon icon="ph:x-duotone" width="18" height="18"></iconify-icon>
|
|
33
|
+
</button>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="messenger-help-search-wrap">
|
|
36
|
+
<span class="messenger-help-search-icon">
|
|
37
|
+
<iconify-icon icon="ph:magnifying-glass-duotone" width="16" height="16"></iconify-icon>
|
|
38
|
+
</span>
|
|
39
|
+
<input
|
|
40
|
+
type="text"
|
|
41
|
+
class="messenger-help-search-input"
|
|
42
|
+
placeholder="Search for help..."
|
|
43
|
+
value="${searchQuery}"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="messenger-help-body">
|
|
48
|
+
<div class="messenger-help-collections"></div>
|
|
49
|
+
</div>
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
this._updateCollectionsList();
|
|
53
|
+
this._attachEvents();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_updateCollectionsList() {
|
|
57
|
+
const container = this.element.querySelector('.messenger-help-collections');
|
|
58
|
+
const collections = this.state.helpArticles || [];
|
|
59
|
+
const searchQuery = (this.state.helpSearchQuery || '').toLowerCase();
|
|
60
|
+
|
|
61
|
+
const filtered = searchQuery
|
|
62
|
+
? collections.filter(
|
|
63
|
+
(c) =>
|
|
64
|
+
c.title.toLowerCase().includes(searchQuery) ||
|
|
65
|
+
(c.description && c.description.toLowerCase().includes(searchQuery))
|
|
66
|
+
)
|
|
67
|
+
: collections;
|
|
68
|
+
|
|
69
|
+
if (filtered.length === 0) {
|
|
70
|
+
container.innerHTML = this._renderEmptyState();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
container.innerHTML = filtered
|
|
75
|
+
.map((c) => this._renderCollectionItem(c))
|
|
76
|
+
.join('');
|
|
77
|
+
this._attachCollectionEvents();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_avatarColors = [
|
|
81
|
+
{ bg: '#EF4444', text: '#FFFFFF' },
|
|
82
|
+
{ bg: '#F97316', text: '#FFFFFF' },
|
|
83
|
+
{ bg: '#F59E0B', text: '#FFFFFF' },
|
|
84
|
+
{ bg: '#10B981', text: '#FFFFFF' },
|
|
85
|
+
{ bg: '#06B6D4', text: '#FFFFFF' },
|
|
86
|
+
{ bg: '#3B82F6', text: '#FFFFFF' },
|
|
87
|
+
{ bg: '#8B5CF6', text: '#FFFFFF' },
|
|
88
|
+
{ bg: '#EC4899', text: '#FFFFFF' },
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
_getAvatarColor(id) {
|
|
92
|
+
const hash = id
|
|
93
|
+
.split('')
|
|
94
|
+
.reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
95
|
+
return this._avatarColors[hash % this._avatarColors.length];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_getInitials(name) {
|
|
99
|
+
if (!name) return 'A';
|
|
100
|
+
return name
|
|
101
|
+
.split(' ')
|
|
102
|
+
.map((n) => n[0])
|
|
103
|
+
.join('')
|
|
104
|
+
.toUpperCase()
|
|
105
|
+
.slice(0, 2);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
_renderAuthorAvatar(collection) {
|
|
109
|
+
if (collection.author?.picture) {
|
|
110
|
+
return `<img
|
|
111
|
+
src="${collection.author.picture}"
|
|
112
|
+
alt="${collection.author.name || ''}"
|
|
113
|
+
class="messenger-help-collection-avatar"
|
|
114
|
+
title="${collection.author.name || ''}"
|
|
115
|
+
/>`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const { bg, text } = this._getAvatarColor(collection.id);
|
|
119
|
+
const initials = collection.author?.name
|
|
120
|
+
? this._getInitials(collection.author.name)
|
|
121
|
+
: 'A';
|
|
122
|
+
|
|
123
|
+
return `<span
|
|
124
|
+
class="messenger-help-collection-avatar messenger-help-collection-avatar--initials"
|
|
125
|
+
style="background-color: ${bg}; color: ${text};"
|
|
126
|
+
title="${collection.author?.name || 'Author'}"
|
|
127
|
+
>${initials}</span>`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
_resolveCollectionIcon(icon) {
|
|
131
|
+
if (!icon) return this._defaultCollectionIcon();
|
|
132
|
+
|
|
133
|
+
if (icon.trimStart().startsWith('<')) {
|
|
134
|
+
return `<span class="messenger-help-collection-icon">${icon}</span>`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (icon.startsWith('ph:')) {
|
|
138
|
+
return `<span class="messenger-help-collection-icon">
|
|
139
|
+
<iconify-icon icon="${icon}" width="22" height="22"></iconify-icon>
|
|
140
|
+
</span>`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return this._defaultCollectionIcon();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
_defaultCollectionIcon() {
|
|
147
|
+
return `<span class="messenger-help-collection-icon">
|
|
148
|
+
<iconify-icon icon="ph:book-open-duotone" width="22" height="22"></iconify-icon>
|
|
149
|
+
</span>`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
_renderCollectionItem(collection) {
|
|
153
|
+
const articleCount = collection.articleCount || 0;
|
|
154
|
+
|
|
155
|
+
return `
|
|
156
|
+
<div class="messenger-help-collection" data-collection-id="${collection.id}">
|
|
157
|
+
${this._resolveCollectionIcon(collection.icon)}
|
|
158
|
+
<div class="messenger-help-collection-content">
|
|
159
|
+
<div class="messenger-help-collection-title">${collection.title}</div>
|
|
160
|
+
${collection.description ? `<p class="messenger-help-collection-desc">${collection.description}</p>` : ''}
|
|
161
|
+
<div class="messenger-help-collection-meta">
|
|
162
|
+
${this._renderAuthorAvatar(collection)}
|
|
163
|
+
<span class="messenger-help-collection-count">
|
|
164
|
+
${articleCount} ${articleCount === 1 ? 'article' : 'articles'}
|
|
165
|
+
</span>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
_renderEmptyState() {
|
|
173
|
+
if (this.state.helpSearchQuery) {
|
|
174
|
+
return `
|
|
175
|
+
<div class="messenger-empty-state">
|
|
176
|
+
<div class="messenger-empty-state-icon">
|
|
177
|
+
<iconify-icon icon="ph:magnifying-glass-duotone" width="48" height="48"></iconify-icon>
|
|
178
|
+
</div>
|
|
179
|
+
<h3>No results found</h3>
|
|
180
|
+
<p>Try a different search term</p>
|
|
181
|
+
</div>
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return `
|
|
186
|
+
<div class="messenger-empty-state">
|
|
187
|
+
<div class="messenger-empty-state-icon">
|
|
188
|
+
<iconify-icon icon="ph:books-duotone" width="48" height="48"></iconify-icon>
|
|
189
|
+
</div>
|
|
190
|
+
<h3>Help collections</h3>
|
|
191
|
+
<p>No collections available yet</p>
|
|
192
|
+
</div>
|
|
193
|
+
`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
_attachEvents() {
|
|
197
|
+
this.element
|
|
198
|
+
.querySelector('.messenger-help-close-btn')
|
|
199
|
+
.addEventListener('click', () => {
|
|
200
|
+
this.state.setOpen(false);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const searchInput = this.element.querySelector(
|
|
204
|
+
'.messenger-help-search-input'
|
|
205
|
+
);
|
|
206
|
+
let searchTimeout;
|
|
207
|
+
searchInput.addEventListener('input', (e) => {
|
|
208
|
+
clearTimeout(searchTimeout);
|
|
209
|
+
searchTimeout = setTimeout(() => {
|
|
210
|
+
this.state.setHelpSearchQuery(e.target.value);
|
|
211
|
+
}, 300);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
this._attachCollectionEvents();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
_attachCollectionEvents() {
|
|
218
|
+
this.element
|
|
219
|
+
.querySelectorAll('.messenger-help-collection')
|
|
220
|
+
.forEach((item) => {
|
|
221
|
+
item.addEventListener('click', () => {
|
|
222
|
+
const collection = this.state.helpArticles.find(
|
|
223
|
+
(c) => c.id === item.dataset.collectionId
|
|
224
|
+
);
|
|
225
|
+
if (collection?.url) {
|
|
226
|
+
window.open(collection.url, '_blank');
|
|
227
|
+
} else if (this.options.onArticleClick) {
|
|
228
|
+
this.options.onArticleClick(collection);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
destroy() {
|
|
235
|
+
if (this._unsubscribe) this._unsubscribe();
|
|
236
|
+
if (this.element?.parentNode)
|
|
237
|
+
this.element.parentNode.removeChild(this.element);
|
|
238
|
+
}
|
|
239
|
+
}
|