@product7/product7-js 0.5.4 → 0.5.6
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 +6 -5
- package/dist/README.md +6 -5
- package/dist/product7-js.js +821 -816
- package/dist/product7-js.js.map +1 -1
- package/dist/product7-js.min.js +1 -1
- package/dist/product7-js.min.js.map +1 -1
- package/package.json +1 -1
- package/src/api/services/{WebChatService.js → LiveChatService.js} +14 -14
- package/src/core/APIService.js +15 -15
- package/src/core/Product7.js +9 -4
- package/src/core/WebSocketService.js +1 -1
- package/src/docs/api.md +8 -8
- package/src/docs/example.md +9 -9
- package/src/docs/framework-integrations.md +3 -3
- package/src/index.js +37 -37
- package/src/styles/base.js +8 -8
- package/src/styles/{web-chat-components.js → live-chat-components.js} +114 -114
- package/src/styles/{web-chat-core.js → live-chat-core.js} +30 -30
- package/src/styles/{web-chat-features.js → live-chat-features.js} +20 -20
- package/src/styles/{web-chat-views.js → live-chat-views.js} +137 -137
- package/src/styles/live-chat.js +17 -0
- package/src/styles/{webChatCustomStyles.js → liveChatCustomStyles.js} +16 -16
- package/src/styles/styles.js +3 -3
- package/src/widgets/{WebChatWidget.js → LiveChatWidget.js} +166 -166
- package/src/widgets/WidgetFactory.js +2 -2
- package/src/widgets/{web-chat/WebChatState.js → live-chat/LiveChatState.js} +1 -1
- package/src/widgets/{web-chat/components/WebChatLauncher.js → live-chat/components/LiveChatLauncher.js} +15 -15
- package/src/widgets/{web-chat/components/WebChatPanel.js → live-chat/components/LiveChatPanel.js} +10 -10
- package/src/widgets/{web-chat → live-chat}/components/NavigationTabs.js +12 -12
- package/src/widgets/{web-chat → live-chat}/views/ChangelogView.js +16 -16
- package/src/widgets/{web-chat → live-chat}/views/ChatView.js +90 -90
- package/src/widgets/{web-chat → live-chat}/views/ConversationsView.js +23 -23
- package/src/widgets/{web-chat → live-chat}/views/HelpView.js +28 -28
- package/src/widgets/{web-chat → live-chat}/views/HomeView.js +52 -52
- package/src/widgets/{web-chat → live-chat}/views/PreChatFormView.js +16 -16
- package/types/index.d.ts +11 -9
- package/src/styles/web-chat.js +0 -17
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
|
|
16
16
|
render() {
|
|
17
17
|
this.element = document.createElement('div');
|
|
18
|
-
this.element.className = '
|
|
18
|
+
this.element.className = 'live-chat-view live-chat-chat-view';
|
|
19
19
|
|
|
20
20
|
this._updateContent();
|
|
21
21
|
|
|
22
22
|
this._unsubscribe = this.state.subscribe((type, data) => {
|
|
23
23
|
if (type === 'connectionChange') {
|
|
24
24
|
const banner = this.element?.querySelector(
|
|
25
|
-
'.
|
|
25
|
+
'.live-chat-connection-banner'
|
|
26
26
|
);
|
|
27
27
|
if (banner) {
|
|
28
28
|
banner.style.display = data.connected ? 'none' : 'flex';
|
|
@@ -88,50 +88,50 @@
|
|
|
88
88
|
: `<iconify-icon icon="ph:chats-circle-duotone" width="20" height="20"></iconify-icon>`;
|
|
89
89
|
|
|
90
90
|
this.element.innerHTML = `
|
|
91
|
-
<div class="
|
|
92
|
-
<button class="sdk-btn-icon
|
|
91
|
+
<div class="live-chat-chat-header">
|
|
92
|
+
<button class="sdk-btn-icon live-chat-back-btn" aria-label="Back">
|
|
93
93
|
<iconify-icon icon="ph:arrow-left" width="20" height="20"></iconify-icon>
|
|
94
94
|
</button>
|
|
95
|
-
<div class="
|
|
95
|
+
<div class="live-chat-chat-header-avatar">
|
|
96
96
|
${headerAvatarHtml}
|
|
97
97
|
</div>
|
|
98
|
-
<div class="
|
|
99
|
-
<span class="
|
|
100
|
-
<span class="
|
|
98
|
+
<div class="live-chat-chat-header-info">
|
|
99
|
+
<span class="live-chat-chat-title">${this._escapeHtml(teamName)}</span>
|
|
100
|
+
<span class="live-chat-chat-subtitle">${isClosed ? 'Conversation resolved' : this.state.responseTime || 'Typically replies within minutes'}</span>
|
|
101
101
|
</div>
|
|
102
|
-
<div class="
|
|
103
|
-
<button class="sdk-btn-icon sdk-close-btn
|
|
102
|
+
<div class="live-chat-chat-header-actions">
|
|
103
|
+
<button class="sdk-btn-icon sdk-close-btn live-chat-mobile-close-btn" aria-label="Close">
|
|
104
104
|
<iconify-icon icon="ph:x" width="18" height="18"></iconify-icon>
|
|
105
105
|
</button>
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|
|
108
108
|
|
|
109
|
-
<div class="
|
|
109
|
+
<div class="live-chat-connection-banner" style="display:none;">
|
|
110
110
|
<iconify-icon icon="ph:wifi-slash" width="14" height="14"></iconify-icon>
|
|
111
111
|
<span>Reconnecting…</span>
|
|
112
112
|
</div>
|
|
113
113
|
|
|
114
|
-
<div class="
|
|
114
|
+
<div class="live-chat-chat-messages">
|
|
115
115
|
${messagesHtml}
|
|
116
116
|
${
|
|
117
117
|
isClosed
|
|
118
118
|
? `
|
|
119
|
-
<div class="
|
|
119
|
+
<div class="live-chat-closed-banner">
|
|
120
120
|
<iconify-icon icon="ph:check-circle-duotone" width="18" height="18"></iconify-icon>
|
|
121
121
|
<span>This conversation has been resolved</span>
|
|
122
122
|
</div>
|
|
123
123
|
`
|
|
124
124
|
: ''
|
|
125
125
|
}
|
|
126
|
-
<div class="
|
|
127
|
-
<div class="
|
|
126
|
+
<div class="live-chat-typing-indicator">
|
|
127
|
+
<div class="live-chat-typing-dots">
|
|
128
128
|
<span></span><span></span><span></span>
|
|
129
129
|
</div>
|
|
130
|
-
<span class="
|
|
130
|
+
<span class="live-chat-typing-text"></span>
|
|
131
131
|
</div>
|
|
132
132
|
</div>
|
|
133
133
|
|
|
134
|
-
<div class="
|
|
134
|
+
<div class="live-chat-scroll-pill" style="display:none;">
|
|
135
135
|
<iconify-icon icon="ph:arrow-down" width="14" height="14"></iconify-icon>
|
|
136
136
|
<span>New message</span>
|
|
137
137
|
</div>
|
|
@@ -140,33 +140,33 @@
|
|
|
140
140
|
isClosed
|
|
141
141
|
? ''
|
|
142
142
|
: `
|
|
143
|
-
<div class="
|
|
143
|
+
<div class="live-chat-compose-attachments-preview"></div>
|
|
144
144
|
|
|
145
|
-
<div class="
|
|
146
|
-
<div class="
|
|
147
|
-
<textarea class="
|
|
145
|
+
<div class="live-chat-chat-compose">
|
|
146
|
+
<div class="live-chat-compose-input-wrapper">
|
|
147
|
+
<textarea class="live-chat-compose-input" placeholder="${placeholder}" rows="1"></textarea>
|
|
148
148
|
</div>
|
|
149
|
-
<div class="
|
|
150
|
-
<div class="
|
|
151
|
-
<button class="sdk-btn-icon
|
|
149
|
+
<div class="live-chat-compose-bottom">
|
|
150
|
+
<div class="live-chat-compose-actions">
|
|
151
|
+
<button class="sdk-btn-icon live-chat-compose-attach" aria-label="Attach file">
|
|
152
152
|
<iconify-icon icon="ph:paperclip-duotone" width="20" height="20"></iconify-icon>
|
|
153
153
|
</button>
|
|
154
|
-
<button class="sdk-btn-icon
|
|
154
|
+
<button class="sdk-btn-icon live-chat-emoji-btn" aria-label="Emoji">
|
|
155
155
|
<iconify-icon icon="ph:smiley-duotone" width="20" height="20"></iconify-icon>
|
|
156
156
|
</button>
|
|
157
157
|
</div>
|
|
158
|
-
<button class="
|
|
158
|
+
<button class="live-chat-compose-send" aria-label="Send" disabled>
|
|
159
159
|
<iconify-icon icon="ph:paper-plane-right" width="20" height="20"></iconify-icon>
|
|
160
160
|
</button>
|
|
161
161
|
</div>
|
|
162
|
-
<input type="file" class="
|
|
162
|
+
<input type="file" class="live-chat-compose-file-input" multiple accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.txt,.zip" />
|
|
163
163
|
</div>
|
|
164
164
|
`
|
|
165
165
|
}
|
|
166
166
|
`;
|
|
167
167
|
|
|
168
168
|
this._typingIndicator = this.element.querySelector(
|
|
169
|
-
'.
|
|
169
|
+
'.live-chat-typing-indicator'
|
|
170
170
|
);
|
|
171
171
|
this._attachEvents();
|
|
172
172
|
this._scrollToBottom();
|
|
@@ -178,11 +178,11 @@
|
|
|
178
178
|
const logoUrl = this.options.logoUrl;
|
|
179
179
|
|
|
180
180
|
const logoHtml = logoUrl
|
|
181
|
-
? `<div class="
|
|
181
|
+
? `<div class="live-chat-chat-empty-logo"><img src="${this._escapeHtml(logoUrl)}" alt="${this._escapeHtml(this.state.teamName)}" /></div>`
|
|
182
182
|
: '';
|
|
183
183
|
|
|
184
184
|
return `
|
|
185
|
-
<div class="
|
|
185
|
+
<div class="live-chat-chat-empty">
|
|
186
186
|
${logoHtml}
|
|
187
187
|
<h3>${isNewConversation ? 'Start a new conversation' : 'Start the conversation'}</h3>
|
|
188
188
|
</div>
|
|
@@ -194,12 +194,12 @@
|
|
|
194
194
|
return attachments
|
|
195
195
|
.map((att) => {
|
|
196
196
|
if (att.type === 'image') {
|
|
197
|
-
return `<img class="
|
|
197
|
+
return `<img class="live-chat-message-image" src="${this._escapeHtml(att.url)}" alt="${this._escapeHtml(att.name || 'image')}" data-url="${this._escapeHtml(att.url)}" />`;
|
|
198
198
|
}
|
|
199
|
-
return `<a class="
|
|
199
|
+
return `<a class="live-chat-message-file" href="${this._escapeHtml(att.url)}" data-url="${this._escapeHtml(att.url)}" data-name="${this._escapeHtml(att.name || 'file')}">
|
|
200
200
|
<iconify-icon icon="ph:file-duotone" width="18" height="18"></iconify-icon>
|
|
201
201
|
<span>${this._escapeHtml(att.name || 'file')}</span>
|
|
202
|
-
<iconify-icon icon="ph:download-simple" width="16" height="16" class="
|
|
202
|
+
<iconify-icon icon="ph:download-simple" width="16" height="16" class="live-chat-file-download-icon"></iconify-icon>
|
|
203
203
|
</a>`;
|
|
204
204
|
})
|
|
205
205
|
.join('');
|
|
@@ -212,8 +212,8 @@
|
|
|
212
212
|
|
|
213
213
|
const isOwn = message.isOwn;
|
|
214
214
|
const messageClass = isOwn
|
|
215
|
-
? '
|
|
216
|
-
: '
|
|
215
|
+
? 'live-chat-message-own'
|
|
216
|
+
: 'live-chat-message-received';
|
|
217
217
|
const timeStr = isLastInGroup
|
|
218
218
|
? this._formatMessageTime(message.timestamp)
|
|
219
219
|
: '';
|
|
@@ -221,25 +221,25 @@
|
|
|
221
221
|
const isOptimistic = message.isOptimistic;
|
|
222
222
|
|
|
223
223
|
const contentHtml = message.content
|
|
224
|
-
? `<div class="
|
|
224
|
+
? `<div class="live-chat-message-content">${this._formatMessageContent(message.content)}</div>`
|
|
225
225
|
: '';
|
|
226
226
|
const bubbleHtml = contentHtml
|
|
227
|
-
? `<div class="
|
|
227
|
+
? `<div class="live-chat-message-bubble">${contentHtml}</div>`
|
|
228
228
|
: '';
|
|
229
229
|
|
|
230
230
|
if (isOwn) {
|
|
231
231
|
const sentIndicator = isLastInGroup
|
|
232
|
-
? `<div class="
|
|
232
|
+
? `<div class="live-chat-message-meta live-chat-message-meta-own">
|
|
233
233
|
${
|
|
234
234
|
isOptimistic
|
|
235
|
-
? `<span class="
|
|
236
|
-
: `<span class="
|
|
235
|
+
? `<span class="live-chat-message-sent-status">Sending…</span>`
|
|
236
|
+
: `<span class="live-chat-message-sent-status">Sent</span>`
|
|
237
237
|
}
|
|
238
238
|
${timeStr ? `<span>·</span><span>${timeStr}</span>` : ''}
|
|
239
239
|
</div>`
|
|
240
240
|
: '';
|
|
241
241
|
return `
|
|
242
|
-
<div class="
|
|
242
|
+
<div class="live-chat-message ${messageClass}${isOptimistic ? ' live-chat-message-optimistic' : ''}">
|
|
243
243
|
${bubbleHtml}
|
|
244
244
|
${attachmentsHtml}
|
|
245
245
|
${sentIndicator}
|
|
@@ -249,15 +249,15 @@
|
|
|
249
249
|
|
|
250
250
|
const avatarHtml = this._renderSenderAvatar(message.sender);
|
|
251
251
|
return `
|
|
252
|
-
<div class="
|
|
253
|
-
<div class="
|
|
254
|
-
<div class="
|
|
255
|
-
<div class="
|
|
252
|
+
<div class="live-chat-message ${messageClass}">
|
|
253
|
+
<div class="live-chat-message-row">
|
|
254
|
+
<div class="live-chat-message-avatar">${avatarHtml}</div>
|
|
255
|
+
<div class="live-chat-message-wrapper">
|
|
256
256
|
${bubbleHtml}
|
|
257
257
|
${attachmentsHtml}
|
|
258
258
|
</div>
|
|
259
259
|
</div>
|
|
260
|
-
${timeStr ? `<div class="
|
|
260
|
+
${timeStr ? `<div class="live-chat-message-meta"><span>${timeStr}</span></div>` : ''}
|
|
261
261
|
</div>
|
|
262
262
|
`;
|
|
263
263
|
}
|
|
@@ -286,11 +286,11 @@
|
|
|
286
286
|
const action = rawAction.charAt(0).toUpperCase() + rawAction.slice(1);
|
|
287
287
|
|
|
288
288
|
return `
|
|
289
|
-
<div class="
|
|
290
|
-
<div class="
|
|
291
|
-
<span class="
|
|
292
|
-
<span class="
|
|
293
|
-
${timeStr ? `<span class="
|
|
289
|
+
<div class="live-chat-message-system-event">
|
|
290
|
+
<div class="live-chat-message-system-event-avatar">${logoHtml}</div>
|
|
291
|
+
<span class="live-chat-message-system-event-name">${this._escapeHtml(name)}</span>
|
|
292
|
+
<span class="live-chat-message-system-event-action">${this._escapeHtml(action)}</span>
|
|
293
|
+
${timeStr ? `<span class="live-chat-message-system-event-time">${timeStr}</span>` : ''}
|
|
294
294
|
</div>
|
|
295
295
|
`;
|
|
296
296
|
}
|
|
@@ -304,16 +304,16 @@
|
|
|
304
304
|
const timeStr = this._formatMessageTime(message.timestamp);
|
|
305
305
|
|
|
306
306
|
return `
|
|
307
|
-
<div class="
|
|
308
|
-
<div class="
|
|
309
|
-
<div class="
|
|
310
|
-
<div class="
|
|
311
|
-
<div class="
|
|
312
|
-
<div class="
|
|
307
|
+
<div class="live-chat-message live-chat-message-received">
|
|
308
|
+
<div class="live-chat-message-row">
|
|
309
|
+
<div class="live-chat-message-avatar">${avatarHtml}</div>
|
|
310
|
+
<div class="live-chat-message-wrapper">
|
|
311
|
+
<div class="live-chat-message-bubble">
|
|
312
|
+
<div class="live-chat-message-content">${this._formatMessageContent(content)}</div>
|
|
313
313
|
</div>
|
|
314
314
|
</div>
|
|
315
315
|
</div>
|
|
316
|
-
${timeStr ? `<div class="
|
|
316
|
+
${timeStr ? `<div class="live-chat-message-meta"><span>${timeStr}</span></div>` : ''}
|
|
317
317
|
</div>
|
|
318
318
|
`;
|
|
319
319
|
}
|
|
@@ -342,7 +342,7 @@
|
|
|
342
342
|
})
|
|
343
343
|
.join('');
|
|
344
344
|
|
|
345
|
-
return `<div class="
|
|
345
|
+
return `<div class="live-chat-avatar-stack">${avatarItems}</div>`;
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
_formatMessageTime(timestamp) {
|
|
@@ -372,9 +372,9 @@
|
|
|
372
372
|
|
|
373
373
|
_appendMessage(message) {
|
|
374
374
|
const messagesContainer = this.element.querySelector(
|
|
375
|
-
'.
|
|
375
|
+
'.live-chat-chat-messages'
|
|
376
376
|
);
|
|
377
|
-
const emptyState = messagesContainer.querySelector('.
|
|
377
|
+
const emptyState = messagesContainer.querySelector('.live-chat-chat-empty');
|
|
378
378
|
if (emptyState) {
|
|
379
379
|
emptyState.remove();
|
|
380
380
|
}
|
|
@@ -394,14 +394,14 @@
|
|
|
394
394
|
if (isNearBottom) {
|
|
395
395
|
this._scrollToBottom();
|
|
396
396
|
} else if (!message.isOwn) {
|
|
397
|
-
const pill = this.element.querySelector('.
|
|
397
|
+
const pill = this.element.querySelector('.live-chat-scroll-pill');
|
|
398
398
|
if (pill) pill.style.display = 'flex';
|
|
399
399
|
}
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
_scrollToBottom() {
|
|
403
403
|
const messagesContainer = this.element.querySelector(
|
|
404
|
-
'.
|
|
404
|
+
'.live-chat-chat-messages'
|
|
405
405
|
);
|
|
406
406
|
if (messagesContainer) {
|
|
407
407
|
setTimeout(() => {
|
|
@@ -412,9 +412,9 @@
|
|
|
412
412
|
|
|
413
413
|
_setupScrollPill() {
|
|
414
414
|
const messagesContainer = this.element.querySelector(
|
|
415
|
-
'.
|
|
415
|
+
'.live-chat-chat-messages'
|
|
416
416
|
);
|
|
417
|
-
const pill = this.element.querySelector('.
|
|
417
|
+
const pill = this.element.querySelector('.live-chat-scroll-pill');
|
|
418
418
|
if (!messagesContainer || !pill) return;
|
|
419
419
|
|
|
420
420
|
pill.addEventListener('click', () => {
|
|
@@ -469,8 +469,8 @@
|
|
|
469
469
|
}
|
|
470
470
|
|
|
471
471
|
_updateSendButtonState() {
|
|
472
|
-
const input = this.element.querySelector('.
|
|
473
|
-
const sendBtn = this.element.querySelector('.
|
|
472
|
+
const input = this.element.querySelector('.live-chat-compose-input');
|
|
473
|
+
const sendBtn = this.element.querySelector('.live-chat-compose-send');
|
|
474
474
|
if (input && sendBtn) {
|
|
475
475
|
sendBtn.disabled =
|
|
476
476
|
!input.value.trim() && this._pendingAttachments.length === 0;
|
|
@@ -479,7 +479,7 @@
|
|
|
479
479
|
|
|
480
480
|
_renderAttachmentPreviews() {
|
|
481
481
|
const container = this.element.querySelector(
|
|
482
|
-
'.
|
|
482
|
+
'.live-chat-compose-attachments-preview'
|
|
483
483
|
);
|
|
484
484
|
if (!container) return;
|
|
485
485
|
|
|
@@ -494,18 +494,18 @@
|
|
|
494
494
|
.map((att, i) => {
|
|
495
495
|
const isImage = att.type.startsWith('image');
|
|
496
496
|
const thumb = isImage
|
|
497
|
-
? `<img class="
|
|
498
|
-
: `<div class="
|
|
497
|
+
? `<img class="live-chat-attachment-thumb" src="${att.preview}" alt="${this._escapeHtml(att.file.name)}" />`
|
|
498
|
+
: `<div class="live-chat-attachment-thumb live-chat-attachment-file-icon"><iconify-icon icon="ph:file-duotone" width="24" height="24"></iconify-icon></div>`;
|
|
499
499
|
return `
|
|
500
|
-
<div class="
|
|
500
|
+
<div class="live-chat-attachment-preview" data-index="${i}">
|
|
501
501
|
${thumb}
|
|
502
|
-
<button class="
|
|
502
|
+
<button class="live-chat-attachment-remove" data-index="${i}" aria-label="Remove">×</button>
|
|
503
503
|
</div>
|
|
504
504
|
`;
|
|
505
505
|
})
|
|
506
506
|
.join('');
|
|
507
507
|
|
|
508
|
-
container.querySelectorAll('.
|
|
508
|
+
container.querySelectorAll('.live-chat-attachment-remove').forEach((btn) => {
|
|
509
509
|
btn.addEventListener('click', (e) => {
|
|
510
510
|
const idx = parseInt(e.currentTarget.dataset.index, 10);
|
|
511
511
|
this._pendingAttachments.splice(idx, 1);
|
|
@@ -517,13 +517,13 @@
|
|
|
517
517
|
|
|
518
518
|
_attachEvents() {
|
|
519
519
|
this.element
|
|
520
|
-
.querySelector('.
|
|
520
|
+
.querySelector('.live-chat-back-btn')
|
|
521
521
|
.addEventListener('click', () => {
|
|
522
522
|
this.state.setView('messages');
|
|
523
523
|
});
|
|
524
524
|
|
|
525
525
|
const mobileCloseBtn = this.element.querySelector(
|
|
526
|
-
'.
|
|
526
|
+
'.live-chat-mobile-close-btn'
|
|
527
527
|
);
|
|
528
528
|
if (mobileCloseBtn) {
|
|
529
529
|
mobileCloseBtn.addEventListener('click', () => {
|
|
@@ -531,8 +531,8 @@
|
|
|
531
531
|
});
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
-
const input = this.element.querySelector('.
|
|
535
|
-
const sendBtn = this.element.querySelector('.
|
|
534
|
+
const input = this.element.querySelector('.live-chat-compose-input');
|
|
535
|
+
const sendBtn = this.element.querySelector('.live-chat-compose-send');
|
|
536
536
|
|
|
537
537
|
if (input && sendBtn) {
|
|
538
538
|
input.addEventListener('input', () => {
|
|
@@ -557,7 +557,7 @@
|
|
|
557
557
|
});
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
-
const emojiBtn = this.element.querySelector('.
|
|
560
|
+
const emojiBtn = this.element.querySelector('.live-chat-emoji-btn');
|
|
561
561
|
if (emojiBtn) {
|
|
562
562
|
emojiBtn.addEventListener('click', (e) => {
|
|
563
563
|
e.stopPropagation();
|
|
@@ -565,9 +565,9 @@
|
|
|
565
565
|
});
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
-
const attachBtn = this.element.querySelector('.
|
|
568
|
+
const attachBtn = this.element.querySelector('.live-chat-compose-attach');
|
|
569
569
|
const fileInput = this.element.querySelector(
|
|
570
|
-
'.
|
|
570
|
+
'.live-chat-compose-file-input'
|
|
571
571
|
);
|
|
572
572
|
|
|
573
573
|
if (attachBtn && fileInput) {
|
|
@@ -596,11 +596,11 @@
|
|
|
596
596
|
}
|
|
597
597
|
|
|
598
598
|
const messagesContainer = this.element.querySelector(
|
|
599
|
-
'.
|
|
599
|
+
'.live-chat-chat-messages'
|
|
600
600
|
);
|
|
601
601
|
if (messagesContainer) {
|
|
602
602
|
messagesContainer.addEventListener('click', (e) => {
|
|
603
|
-
const fileLink = e.target.closest('.
|
|
603
|
+
const fileLink = e.target.closest('.live-chat-message-file');
|
|
604
604
|
if (fileLink) {
|
|
605
605
|
e.preventDefault();
|
|
606
606
|
const url = fileLink.dataset.url;
|
|
@@ -609,7 +609,7 @@
|
|
|
609
609
|
return;
|
|
610
610
|
}
|
|
611
611
|
|
|
612
|
-
const img = e.target.closest('.
|
|
612
|
+
const img = e.target.closest('.live-chat-message-image');
|
|
613
613
|
if (img) {
|
|
614
614
|
const url = img.dataset.url || img.src;
|
|
615
615
|
window.open(url, '_blank');
|
|
@@ -648,7 +648,7 @@
|
|
|
648
648
|
async _sendMessage() {
|
|
649
649
|
if (this._isConversationClosed) return;
|
|
650
650
|
|
|
651
|
-
const input = this.element.querySelector('.
|
|
651
|
+
const input = this.element.querySelector('.live-chat-compose-input');
|
|
652
652
|
const content = input.value.trim();
|
|
653
653
|
const hasAttachments = this._pendingAttachments.length > 0;
|
|
654
654
|
|
|
@@ -713,7 +713,7 @@
|
|
|
713
713
|
|
|
714
714
|
async _toggleEmojiPicker() {
|
|
715
715
|
const existing = this.element.querySelector(
|
|
716
|
-
'.
|
|
716
|
+
'.live-chat-emoji-picker-container'
|
|
717
717
|
);
|
|
718
718
|
if (existing) {
|
|
719
719
|
existing.remove();
|
|
@@ -732,12 +732,12 @@
|
|
|
732
732
|
}
|
|
733
733
|
|
|
734
734
|
const container = document.createElement('div');
|
|
735
|
-
container.className = '
|
|
735
|
+
container.className = 'live-chat-emoji-picker-container';
|
|
736
736
|
|
|
737
737
|
const picker = document.createElement('emoji-picker');
|
|
738
738
|
container.appendChild(picker);
|
|
739
739
|
|
|
740
|
-
const compose = this.element.querySelector('.
|
|
740
|
+
const compose = this.element.querySelector('.live-chat-chat-compose');
|
|
741
741
|
compose.parentNode.insertBefore(container, compose);
|
|
742
742
|
this._emojiPickerOpen = true;
|
|
743
743
|
|
|
@@ -754,7 +754,7 @@
|
|
|
754
754
|
this._emojiOutsideHandler = (e) => {
|
|
755
755
|
if (
|
|
756
756
|
!container.contains(e.target) &&
|
|
757
|
-
!e.target.closest('.
|
|
757
|
+
!e.target.closest('.live-chat-emoji-btn')
|
|
758
758
|
) {
|
|
759
759
|
container.remove();
|
|
760
760
|
this._emojiPickerOpen = false;
|
|
@@ -769,7 +769,7 @@
|
|
|
769
769
|
}
|
|
770
770
|
|
|
771
771
|
_insertEmoji(emoji) {
|
|
772
|
-
const input = this.element.querySelector('.
|
|
772
|
+
const input = this.element.querySelector('.live-chat-compose-input');
|
|
773
773
|
if (!input) return;
|
|
774
774
|
const start = input.selectionStart;
|
|
775
775
|
const end = input.selectionEnd;
|
|
@@ -813,7 +813,7 @@
|
|
|
813
813
|
if (this._typingIndicator) {
|
|
814
814
|
this._typingIndicator.style.display = 'flex';
|
|
815
815
|
const textEl = this._typingIndicator.querySelector(
|
|
816
|
-
'.
|
|
816
|
+
'.live-chat-typing-text'
|
|
817
817
|
);
|
|
818
818
|
if (textEl) {
|
|
819
819
|
textEl.textContent = `${userName || 'Support'} is typing...`;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
render() {
|
|
19
19
|
this.element = document.createElement('div');
|
|
20
|
-
this.element.className = '
|
|
20
|
+
this.element.className = 'live-chat-view live-chat-conversations-view';
|
|
21
21
|
|
|
22
22
|
this._updateContent();
|
|
23
23
|
this._attachEvents();
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
let conversationsHtml;
|
|
49
49
|
if (conversations.length === 0) {
|
|
50
50
|
conversationsHtml = `
|
|
51
|
-
<div class="
|
|
52
|
-
<div class="
|
|
51
|
+
<div class="live-chat-empty-state">
|
|
52
|
+
<div class="live-chat-empty-state-icon">
|
|
53
53
|
<iconify-icon icon="ph:chat-circle-duotone" width="48" height="48"></iconify-icon>
|
|
54
54
|
</div>
|
|
55
55
|
<h3>No conversations yet</h3>
|
|
@@ -58,26 +58,26 @@
|
|
|
58
58
|
`;
|
|
59
59
|
} else {
|
|
60
60
|
conversationsHtml = `
|
|
61
|
-
<div class="
|
|
61
|
+
<div class="live-chat-conversations-list">
|
|
62
62
|
${conversations.map((conv) => this._renderConversationItem(conv)).join('')}
|
|
63
63
|
</div>
|
|
64
64
|
`;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
this.element.innerHTML = `
|
|
68
|
-
<div class="
|
|
68
|
+
<div class="live-chat-conversations-header">
|
|
69
69
|
<h2>Messages</h2>
|
|
70
|
-
<button class="sdk-close-btn
|
|
70
|
+
<button class="sdk-close-btn live-chat-mobile-close-btn" aria-label="Close">
|
|
71
71
|
<iconify-icon icon="ph:x" width="18" height="18"></iconify-icon>
|
|
72
72
|
</button>
|
|
73
73
|
</div>
|
|
74
74
|
|
|
75
|
-
<div class="
|
|
75
|
+
<div class="live-chat-conversations-body">
|
|
76
76
|
${conversationsHtml}
|
|
77
77
|
</div>
|
|
78
78
|
|
|
79
|
-
<div class="
|
|
80
|
-
<button class="
|
|
79
|
+
<div class="live-chat-conversations-footer">
|
|
80
|
+
<button class="live-chat-new-message-btn">
|
|
81
81
|
<iconify-icon icon="ph:pencil-simple" width="16" height="16" style="flex-shrink: 0; color: var(--msg-text-secondary);"></iconify-icon>
|
|
82
82
|
<span style="flex: 1;">New conversation</span>
|
|
83
83
|
<iconify-icon icon="ph:caret-right" width="16" height="16" style="flex-shrink: 0; color: var(--msg-text-tertiary);"></iconify-icon>
|
|
@@ -98,19 +98,19 @@
|
|
|
98
98
|
);
|
|
99
99
|
|
|
100
100
|
return `
|
|
101
|
-
<div class="
|
|
102
|
-
<div class="
|
|
101
|
+
<div class="live-chat-conversation-item ${unreadClass} ${closedClass}" data-conversation-id="${conversation.id}">
|
|
102
|
+
<div class="live-chat-conversation-avatars">
|
|
103
103
|
${avatarsHtml}
|
|
104
104
|
</div>
|
|
105
|
-
<div class="
|
|
106
|
-
<div class="
|
|
107
|
-
<span class="
|
|
108
|
-
<span class="
|
|
105
|
+
<div class="live-chat-conversation-content">
|
|
106
|
+
<div class="live-chat-conversation-header">
|
|
107
|
+
<span class="live-chat-conversation-title">${conversation.title || 'Chat with team'}</span>
|
|
108
|
+
<span class="live-chat-conversation-time">${timeAgo}</span>
|
|
109
109
|
</div>
|
|
110
|
-
<div class="
|
|
111
|
-
${conversation.unread > 0 ? '<span class="
|
|
112
|
-
${isClosed ? '<span class="
|
|
113
|
-
<span class="
|
|
110
|
+
<div class="live-chat-conversation-preview">
|
|
111
|
+
${conversation.unread > 0 ? '<span class="live-chat-unread-dot"></span>' : ''}
|
|
112
|
+
${isClosed ? '<span class="live-chat-conversation-resolved-badge">Resolved</span>' : ''}
|
|
113
|
+
<span class="live-chat-conversation-message">${this._truncateMessage(conversation.lastMessage)}</span>
|
|
114
114
|
</div>
|
|
115
115
|
</div>
|
|
116
116
|
</div>
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
const color1 = this._getAvatarColor('S');
|
|
139
139
|
const color2 = this._getAvatarColor('T');
|
|
140
140
|
return `
|
|
141
|
-
<div class="
|
|
141
|
+
<div class="live-chat-avatar-stack">
|
|
142
142
|
<div class="sdk-avatar sdk-avatar-sm" style="background-color: ${color1};">S</div>
|
|
143
143
|
<div class="sdk-avatar sdk-avatar-sm" style="background-color: ${color2};">T</div>
|
|
144
144
|
</div>
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
})
|
|
158
158
|
.join('');
|
|
159
159
|
|
|
160
|
-
return `<div class="
|
|
160
|
+
return `<div class="live-chat-avatar-stack">${avatarItems}</div>`;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
_formatTimeAgo(timestamp) {
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
this.element
|
|
195
|
-
.querySelectorAll('.
|
|
195
|
+
.querySelectorAll('.live-chat-conversation-item')
|
|
196
196
|
.forEach((item) => {
|
|
197
197
|
item.addEventListener('click', () => {
|
|
198
198
|
const convId = item.dataset.conversationId;
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
});
|
|
207
207
|
});
|
|
208
208
|
|
|
209
|
-
const newMsgBtn = this.element.querySelector('.
|
|
209
|
+
const newMsgBtn = this.element.querySelector('.live-chat-new-message-btn');
|
|
210
210
|
if (newMsgBtn) {
|
|
211
211
|
newMsgBtn.addEventListener('click', () => {
|
|
212
212
|
this._startNewConversation();
|