@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
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import { WebSocketService } from '../core/WebSocketService.js';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from '../styles/
|
|
3
|
+
applyliveChatCustomStyles,
|
|
4
|
+
removeliveChatCustomStyles,
|
|
5
|
+
} from '../styles/liveChatCustomStyles.js';
|
|
6
6
|
import { NotificationSound } from '../utils/NotificationSound.js';
|
|
7
7
|
import { BaseWidget } from './BaseWidget.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { ChangelogView } from './
|
|
12
|
-
import { ChatView } from './
|
|
13
|
-
import { ConversationsView } from './
|
|
14
|
-
import { HelpView } from './
|
|
15
|
-
import { HomeView } from './
|
|
16
|
-
import { PreChatFormView } from './
|
|
17
|
-
|
|
18
|
-
export class
|
|
8
|
+
import { LiveChatState } from './live-chat/LiveChatState.js';
|
|
9
|
+
import { LiveChatLauncher } from './live-chat/components/LiveChatLauncher.js';
|
|
10
|
+
import { LiveChatPanel } from './live-chat/components/LiveChatPanel.js';
|
|
11
|
+
import { ChangelogView } from './live-chat/views/ChangelogView.js';
|
|
12
|
+
import { ChatView } from './live-chat/views/ChatView.js';
|
|
13
|
+
import { ConversationsView } from './live-chat/views/ConversationsView.js';
|
|
14
|
+
import { HelpView } from './live-chat/views/HelpView.js';
|
|
15
|
+
import { HomeView } from './live-chat/views/HomeView.js';
|
|
16
|
+
import { PreChatFormView } from './live-chat/views/PreChatFormView.js';
|
|
17
|
+
|
|
18
|
+
export class LiveChatWidget extends BaseWidget {
|
|
19
19
|
constructor(options) {
|
|
20
|
-
super({ ...options, type: '
|
|
20
|
+
super({ ...options, type: 'liveChat' });
|
|
21
21
|
this._explicitOptions = options || {};
|
|
22
22
|
const resolvedTheme = options.theme || 'light';
|
|
23
23
|
const hasExplicitTextColor = Object.prototype.hasOwnProperty.call(
|
|
@@ -37,7 +37,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
37
37
|
? options.enableChangelog
|
|
38
38
|
: options.enableNews !== false;
|
|
39
39
|
|
|
40
|
-
this.
|
|
40
|
+
this.liveChatOptions = {
|
|
41
41
|
position: options.position || 'right',
|
|
42
42
|
theme: resolvedTheme,
|
|
43
43
|
primaryColor: options.primaryColor || '#155EEF',
|
|
@@ -73,27 +73,27 @@ export class WebChatWidget extends BaseWidget {
|
|
|
73
73
|
|
|
74
74
|
const sdkMetadata = this.sdk?.apiService?.getMetadata() || null;
|
|
75
75
|
|
|
76
|
-
this.
|
|
77
|
-
teamName: this.
|
|
78
|
-
teamAvatars: this.
|
|
79
|
-
greetingMessage: this.
|
|
80
|
-
welcomeMessage: this.
|
|
81
|
-
onlineMessage: this.
|
|
82
|
-
responseTime: this.
|
|
83
|
-
enableHelp: this.
|
|
84
|
-
enableChangelog: this.
|
|
76
|
+
this.LiveChatState = new LiveChatState({
|
|
77
|
+
teamName: this.liveChatOptions.teamName,
|
|
78
|
+
teamAvatars: this.liveChatOptions.teamAvatars,
|
|
79
|
+
greetingMessage: this.liveChatOptions.greetingMessage,
|
|
80
|
+
welcomeMessage: this.liveChatOptions.welcomeMessage,
|
|
81
|
+
onlineMessage: this.liveChatOptions.onlineMessage,
|
|
82
|
+
responseTime: this.liveChatOptions.responseTime,
|
|
83
|
+
enableHelp: this.liveChatOptions.enableHelp,
|
|
84
|
+
enableChangelog: this.liveChatOptions.enableChangelog,
|
|
85
85
|
metadata: sdkMetadata,
|
|
86
86
|
urls: {
|
|
87
|
-
feedback: this.
|
|
88
|
-
changelog: this.
|
|
89
|
-
help: this.
|
|
90
|
-
roadmap: this.
|
|
87
|
+
feedback: this.liveChatOptions.feedbackUrl,
|
|
88
|
+
changelog: this.liveChatOptions.changelogUrl,
|
|
89
|
+
help: this.liveChatOptions.helpUrl,
|
|
90
|
+
roadmap: this.liveChatOptions.roadmapUrl,
|
|
91
91
|
},
|
|
92
92
|
});
|
|
93
93
|
|
|
94
94
|
// If identify() was called before this widget was created, pre-seed identity
|
|
95
95
|
if (this.sdk?.identified && sdkMetadata) {
|
|
96
|
-
this.
|
|
96
|
+
this.LiveChatState.isIdentified = true;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
this.launcher = null;
|
|
@@ -136,62 +136,62 @@ export class WebChatWidget extends BaseWidget {
|
|
|
136
136
|
trigger: false,
|
|
137
137
|
displayMode: 'modal',
|
|
138
138
|
boardName:
|
|
139
|
-
this.
|
|
140
|
-
primaryColor: this.
|
|
141
|
-
theme: this.
|
|
139
|
+
this.liveChatOptions.feedbackBoardName || this.sdk.config.boardName,
|
|
140
|
+
primaryColor: this.liveChatOptions.primaryColor,
|
|
141
|
+
theme: this.liveChatOptions.theme,
|
|
142
142
|
});
|
|
143
143
|
widget.mount();
|
|
144
144
|
return widget;
|
|
145
145
|
} catch (e) {
|
|
146
|
-
console.warn('[
|
|
146
|
+
console.warn('[LiveChat] Could not create internal feedback widget:', e);
|
|
147
147
|
return null;
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
_render() {
|
|
152
152
|
const container = document.createElement('div');
|
|
153
|
-
container.className = `
|
|
153
|
+
container.className = `live-chat-widget theme-${this.liveChatOptions.theme}`;
|
|
154
154
|
container.style.zIndex = '999999';
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
primaryColor: this.
|
|
158
|
-
textColor: this.
|
|
159
|
-
backgroundColor: this.
|
|
160
|
-
theme: this.
|
|
156
|
+
applyliveChatCustomStyles({
|
|
157
|
+
primaryColor: this.liveChatOptions.primaryColor,
|
|
158
|
+
textColor: this.liveChatOptions.textColor,
|
|
159
|
+
backgroundColor: this.liveChatOptions.backgroundColor,
|
|
160
|
+
theme: this.liveChatOptions.theme,
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
// Create internal feedback widget (no floating button) so the
|
|
164
164
|
// "Leave a feedback" button in the home view can open it inline.
|
|
165
|
-
if (!this.
|
|
165
|
+
if (!this.liveChatOptions.onFeedbackClick) {
|
|
166
166
|
this._feedbackWidget = this._createInternalFeedbackWidget();
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
if (this._hasTrigger()) {
|
|
170
|
-
this.launcher = new
|
|
171
|
-
position: this.
|
|
172
|
-
primaryColor: this.
|
|
170
|
+
this.launcher = new LiveChatLauncher(this.LiveChatState, {
|
|
171
|
+
position: this.liveChatOptions.position,
|
|
172
|
+
primaryColor: this.liveChatOptions.primaryColor,
|
|
173
173
|
});
|
|
174
174
|
container.appendChild(this.launcher.render());
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
this.panel = new
|
|
178
|
-
position: this.
|
|
179
|
-
theme: this.
|
|
180
|
-
primaryColor: this.
|
|
181
|
-
logoUrl: this.
|
|
182
|
-
featuredContent: this.
|
|
177
|
+
this.panel = new LiveChatPanel(this.LiveChatState, {
|
|
178
|
+
position: this.liveChatOptions.position,
|
|
179
|
+
theme: this.liveChatOptions.theme,
|
|
180
|
+
primaryColor: this.liveChatOptions.primaryColor,
|
|
181
|
+
logoUrl: this.liveChatOptions.logoUrl,
|
|
182
|
+
featuredContent: this.liveChatOptions.featuredContent,
|
|
183
183
|
onSendMessage:
|
|
184
|
-
this.
|
|
184
|
+
this.liveChatOptions.onSendMessage || this._handleSendMessage.bind(this),
|
|
185
185
|
onStartConversation: this._handleStartConversation.bind(this),
|
|
186
186
|
onTyping: this.sendTypingIndicator.bind(this),
|
|
187
187
|
onSelectConversation: this._handleSelectConversation.bind(this),
|
|
188
188
|
onStartNewConversation: this._handleNewConversationClick.bind(this),
|
|
189
189
|
onIdentifyContact: this._handleIdentifyContact.bind(this),
|
|
190
190
|
onFeedbackClick:
|
|
191
|
-
this.
|
|
191
|
+
this.liveChatOptions.onFeedbackClick ||
|
|
192
192
|
(this._feedbackWidget ? () => this._feedbackWidget.open() : null),
|
|
193
|
-
onArticleClick: this.
|
|
194
|
-
onChangelogClick: this.
|
|
193
|
+
onArticleClick: this.liveChatOptions.onArticleClick,
|
|
194
|
+
onChangelogClick: this.liveChatOptions.onChangelogClick,
|
|
195
195
|
});
|
|
196
196
|
|
|
197
197
|
this.panel.registerView('home', HomeView);
|
|
@@ -208,7 +208,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
_attachEvents() {
|
|
211
|
-
this._stateUnsubscribe = this.
|
|
211
|
+
this._stateUnsubscribe = this.LiveChatState.subscribe((type, data) => {
|
|
212
212
|
if (type === 'openChange') {
|
|
213
213
|
this._handleOpenChange(data.isOpen);
|
|
214
214
|
}
|
|
@@ -224,11 +224,11 @@ export class WebChatWidget extends BaseWidget {
|
|
|
224
224
|
_handleOpenChange(isOpen) {
|
|
225
225
|
if (isOpen) {
|
|
226
226
|
this.panel.show();
|
|
227
|
-
this.sdk.eventBus.emit('
|
|
227
|
+
this.sdk.eventBus.emit('liveChat:opened', { widget: this });
|
|
228
228
|
} else {
|
|
229
229
|
this.panel.hide();
|
|
230
|
-
this.
|
|
231
|
-
this.sdk.eventBus.emit('
|
|
230
|
+
this.LiveChatState.reset();
|
|
231
|
+
this.sdk.eventBus.emit('liveChat:closed', { widget: this });
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -247,21 +247,21 @@ export class WebChatWidget extends BaseWidget {
|
|
|
247
247
|
|
|
248
248
|
async _handleStartConversation(messageContent, pendingAttachments) {
|
|
249
249
|
try {
|
|
250
|
-
if (!this.
|
|
251
|
-
this.
|
|
250
|
+
if (!this.LiveChatState.isIdentified) {
|
|
251
|
+
this.LiveChatState.pendingMessage = {
|
|
252
252
|
content: messageContent,
|
|
253
253
|
attachments: pendingAttachments,
|
|
254
254
|
};
|
|
255
|
-
this.
|
|
255
|
+
this.LiveChatState.setView('prechat');
|
|
256
256
|
return null;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
const openConversation = this.
|
|
259
|
+
const openConversation = this.LiveChatState.conversations.find(
|
|
260
260
|
(c) => c.status === 'open'
|
|
261
261
|
);
|
|
262
262
|
|
|
263
263
|
if (openConversation) {
|
|
264
|
-
this.
|
|
264
|
+
this.LiveChatState.setActiveConversation(openConversation.id);
|
|
265
265
|
await this._handleSendMessage(
|
|
266
266
|
openConversation.id,
|
|
267
267
|
{ content: messageContent },
|
|
@@ -276,7 +276,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
276
276
|
pendingAttachments
|
|
277
277
|
);
|
|
278
278
|
} catch (error) {
|
|
279
|
-
console.error('[
|
|
279
|
+
console.error('[LiveChatWidget] Failed to start conversation:', error);
|
|
280
280
|
return null;
|
|
281
281
|
}
|
|
282
282
|
}
|
|
@@ -285,36 +285,36 @@ export class WebChatWidget extends BaseWidget {
|
|
|
285
285
|
try {
|
|
286
286
|
await this.fetchMessages(conversationId);
|
|
287
287
|
} catch (error) {
|
|
288
|
-
console.error('[
|
|
288
|
+
console.error('[LiveChatWidget] Failed to fetch messages:', error);
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
_handleNewConversationClick() {
|
|
293
|
-
const openConversation = this.
|
|
293
|
+
const openConversation = this.LiveChatState.conversations.find(
|
|
294
294
|
(c) => c.status === 'open'
|
|
295
295
|
);
|
|
296
296
|
|
|
297
297
|
if (openConversation) {
|
|
298
|
-
this.
|
|
299
|
-
this.
|
|
298
|
+
this.LiveChatState.setActiveConversation(openConversation.id);
|
|
299
|
+
this.LiveChatState.setView('chat');
|
|
300
300
|
this._handleSelectConversation(openConversation.id);
|
|
301
301
|
} else {
|
|
302
|
-
this.
|
|
303
|
-
this.
|
|
302
|
+
this.LiveChatState.setActiveConversation(null);
|
|
303
|
+
this.LiveChatState.setView('chat');
|
|
304
304
|
}
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
async _handleIdentifyContact(contactData) {
|
|
308
308
|
try {
|
|
309
309
|
// Route through sdk.identify() so the SDK-level identity state is updated
|
|
310
|
-
// and applyIdentity() handles the
|
|
310
|
+
// and applyIdentity() handles the live chat state + WebSocket as a side effect.
|
|
311
311
|
const result = await this.sdk.identify({
|
|
312
312
|
email: contactData.email,
|
|
313
313
|
name: contactData.name,
|
|
314
314
|
});
|
|
315
315
|
return result;
|
|
316
316
|
} catch (error) {
|
|
317
|
-
console.error('[
|
|
317
|
+
console.error('[LiveChatWidget] Failed to identify contact:', error);
|
|
318
318
|
throw error;
|
|
319
319
|
}
|
|
320
320
|
}
|
|
@@ -326,7 +326,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
applyIdentity(metadata = {}) {
|
|
329
|
-
this.
|
|
329
|
+
this.LiveChatState.setIdentified(true, metadata);
|
|
330
330
|
|
|
331
331
|
if (this.apiService?.sessionToken && !this.wsService?.isConnected) {
|
|
332
332
|
this._initWebSocket();
|
|
@@ -341,7 +341,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
341
341
|
}
|
|
342
342
|
throw new Error('Upload failed');
|
|
343
343
|
} catch (error) {
|
|
344
|
-
console.error('[
|
|
344
|
+
console.error('[LiveChatWidget] Failed to upload file:', error);
|
|
345
345
|
throw error;
|
|
346
346
|
}
|
|
347
347
|
}
|
|
@@ -360,7 +360,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
360
360
|
});
|
|
361
361
|
} catch (err) {
|
|
362
362
|
console.error(
|
|
363
|
-
'[
|
|
363
|
+
'[LiveChatWidget] Skipping failed attachment upload:',
|
|
364
364
|
att.file.name,
|
|
365
365
|
err
|
|
366
366
|
);
|
|
@@ -370,7 +370,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
async _handleSendMessage(conversationId, message, pendingAttachments) {
|
|
373
|
-
this.sdk.eventBus.emit('
|
|
373
|
+
this.sdk.eventBus.emit('liveChat:messageSent', {
|
|
374
374
|
widget: this,
|
|
375
375
|
conversationId,
|
|
376
376
|
message,
|
|
@@ -386,7 +386,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
386
386
|
});
|
|
387
387
|
|
|
388
388
|
if (response.status && response.data) {
|
|
389
|
-
console.log('[
|
|
389
|
+
console.log('[LiveChatWidget] Message sent:', response.data.id);
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
if (this.apiService?.mock) {
|
|
@@ -401,11 +401,11 @@ export class WebChatWidget extends BaseWidget {
|
|
|
401
401
|
avatarUrl: null,
|
|
402
402
|
},
|
|
403
403
|
};
|
|
404
|
-
this.
|
|
404
|
+
this.LiveChatState.addMessage(conversationId, mockResponse);
|
|
405
405
|
}, 1500);
|
|
406
406
|
}
|
|
407
407
|
} catch (error) {
|
|
408
|
-
console.error('[
|
|
408
|
+
console.error('[LiveChatWidget] Failed to send message:', error);
|
|
409
409
|
}
|
|
410
410
|
}
|
|
411
411
|
|
|
@@ -437,20 +437,20 @@ export class WebChatWidget extends BaseWidget {
|
|
|
437
437
|
},
|
|
438
438
|
};
|
|
439
439
|
|
|
440
|
-
this.
|
|
440
|
+
this.LiveChatState.upsertMessage(conversation_id, localMessage, {
|
|
441
441
|
reconcileOwnOptimistic: true,
|
|
442
442
|
optimisticMatchWindowMs: 30000,
|
|
443
443
|
});
|
|
444
444
|
|
|
445
445
|
const isOwnMessage = message.sender_type === 'customer';
|
|
446
446
|
|
|
447
|
-
if (!isOwnMessage && this.
|
|
447
|
+
if (!isOwnMessage && this.LiveChatState.isIdentified) {
|
|
448
448
|
this._notificationSound.play();
|
|
449
449
|
}
|
|
450
450
|
|
|
451
451
|
if (
|
|
452
|
-
!this.
|
|
453
|
-
this.
|
|
452
|
+
!this.LiveChatState.isOpen ||
|
|
453
|
+
this.LiveChatState.activeConversationId !== conversation_id
|
|
454
454
|
) {
|
|
455
455
|
this._updateUnreadCount();
|
|
456
456
|
}
|
|
@@ -458,7 +458,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
458
458
|
|
|
459
459
|
_handleTypingStarted(data) {
|
|
460
460
|
if (data.is_agent) {
|
|
461
|
-
this.
|
|
461
|
+
this.LiveChatState._notify('typingStarted', {
|
|
462
462
|
conversationId: data.conversation_id,
|
|
463
463
|
userName: data.user_name,
|
|
464
464
|
});
|
|
@@ -466,7 +466,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
466
466
|
}
|
|
467
467
|
|
|
468
468
|
_handleTypingStopped(data) {
|
|
469
|
-
this.
|
|
469
|
+
this.LiveChatState._notify('typingStopped', {
|
|
470
470
|
conversationId: data.conversation_id,
|
|
471
471
|
});
|
|
472
472
|
}
|
|
@@ -476,7 +476,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
476
476
|
data?.conversation_id || data?.id || data?.conversation?.id;
|
|
477
477
|
if (!conversationId) return;
|
|
478
478
|
|
|
479
|
-
this.
|
|
479
|
+
this.LiveChatState.updateConversation(conversationId, {
|
|
480
480
|
status: 'closed',
|
|
481
481
|
});
|
|
482
482
|
}
|
|
@@ -485,13 +485,13 @@ export class WebChatWidget extends BaseWidget {
|
|
|
485
485
|
try {
|
|
486
486
|
const response = await this.apiService.getUnreadCount();
|
|
487
487
|
if (response.status && response.data) {
|
|
488
|
-
this.
|
|
489
|
-
this.
|
|
490
|
-
count: this.
|
|
488
|
+
this.LiveChatState.unreadCount = response.data.unread_count || 0;
|
|
489
|
+
this.LiveChatState._notify('unreadCountChange', {
|
|
490
|
+
count: this.LiveChatState.unreadCount,
|
|
491
491
|
});
|
|
492
492
|
}
|
|
493
493
|
} catch (error) {
|
|
494
|
-
console.error('[
|
|
494
|
+
console.error('[LiveChatWidget] Failed to get unread count:', error);
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
497
|
|
|
@@ -521,23 +521,23 @@ export class WebChatWidget extends BaseWidget {
|
|
|
521
521
|
);
|
|
522
522
|
this._wsUnsubscribers.push(
|
|
523
523
|
this.wsService.on('connected', () => {
|
|
524
|
-
console.log('[
|
|
525
|
-
if (this.
|
|
524
|
+
console.log('[LiveChatWidget] WebSocket connected');
|
|
525
|
+
if (this.LiveChatState.activeConversationId) {
|
|
526
526
|
this.wsService.send('conversation:subscribe', {
|
|
527
|
-
conversation_id: this.
|
|
527
|
+
conversation_id: this.LiveChatState.activeConversationId,
|
|
528
528
|
});
|
|
529
529
|
}
|
|
530
530
|
})
|
|
531
531
|
);
|
|
532
532
|
this._wsUnsubscribers.push(
|
|
533
533
|
this.wsService.on('disconnected', () => {
|
|
534
|
-
console.log('[
|
|
535
|
-
this.
|
|
534
|
+
console.log('[LiveChatWidget] WebSocket disconnected');
|
|
535
|
+
this.LiveChatState._notify('connectionChange', { connected: false });
|
|
536
536
|
})
|
|
537
537
|
);
|
|
538
538
|
this._wsUnsubscribers.push(
|
|
539
539
|
this.wsService.on('connected', () => {
|
|
540
|
-
this.
|
|
540
|
+
this.LiveChatState._notify('connectionChange', { connected: true });
|
|
541
541
|
})
|
|
542
542
|
);
|
|
543
543
|
|
|
@@ -545,78 +545,78 @@ export class WebChatWidget extends BaseWidget {
|
|
|
545
545
|
}
|
|
546
546
|
|
|
547
547
|
open() {
|
|
548
|
-
this.
|
|
548
|
+
this.LiveChatState.setOpen(true);
|
|
549
549
|
}
|
|
550
550
|
|
|
551
551
|
close() {
|
|
552
|
-
this.
|
|
552
|
+
this.LiveChatState.setOpen(false);
|
|
553
553
|
}
|
|
554
554
|
|
|
555
555
|
toggle() {
|
|
556
|
-
this.
|
|
556
|
+
this.LiveChatState.setOpen(!this.LiveChatState.isOpen);
|
|
557
557
|
}
|
|
558
558
|
|
|
559
559
|
navigateTo(view) {
|
|
560
|
-
this.
|
|
561
|
-
if (!this.
|
|
560
|
+
this.LiveChatState.setView(view);
|
|
561
|
+
if (!this.LiveChatState.isOpen) {
|
|
562
562
|
this.open();
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
565
|
|
|
566
566
|
setConversations(conversations) {
|
|
567
|
-
this.
|
|
567
|
+
this.LiveChatState.setConversations(conversations);
|
|
568
568
|
}
|
|
569
569
|
|
|
570
570
|
addMessage(conversationId, message) {
|
|
571
|
-
this.
|
|
571
|
+
this.LiveChatState.addMessage(conversationId, message);
|
|
572
572
|
}
|
|
573
573
|
|
|
574
574
|
setHelpArticles(articles) {
|
|
575
|
-
this.
|
|
575
|
+
this.LiveChatState.setHelpArticles(articles);
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
setHomeChangelogItems(items) {
|
|
579
|
-
this.
|
|
579
|
+
this.LiveChatState.setHomeChangelogItems(items);
|
|
580
580
|
}
|
|
581
581
|
|
|
582
582
|
setChangelogItems(items) {
|
|
583
|
-
this.
|
|
583
|
+
this.LiveChatState.setChangelogItems(items);
|
|
584
584
|
}
|
|
585
585
|
|
|
586
586
|
setUnreadCount(count) {
|
|
587
|
-
this.
|
|
588
|
-
this.
|
|
587
|
+
this.LiveChatState.unreadCount = count;
|
|
588
|
+
this.LiveChatState._notify('unreadCountChange', { count });
|
|
589
589
|
}
|
|
590
590
|
|
|
591
591
|
getState() {
|
|
592
592
|
return {
|
|
593
|
-
isOpen: this.
|
|
594
|
-
currentView: this.
|
|
595
|
-
unreadCount: this.
|
|
596
|
-
conversations: this.
|
|
593
|
+
isOpen: this.LiveChatState.isOpen,
|
|
594
|
+
currentView: this.LiveChatState.currentView,
|
|
595
|
+
unreadCount: this.LiveChatState.unreadCount,
|
|
596
|
+
conversations: this.LiveChatState.conversations,
|
|
597
597
|
};
|
|
598
598
|
}
|
|
599
599
|
|
|
600
600
|
_applyPreviewData() {
|
|
601
|
-
const data = this.
|
|
601
|
+
const data = this.liveChatOptions.previewData;
|
|
602
602
|
if (!data || typeof data !== 'object') {
|
|
603
603
|
return;
|
|
604
604
|
}
|
|
605
605
|
|
|
606
606
|
if (Array.isArray(data.conversations)) {
|
|
607
|
-
this.
|
|
607
|
+
this.LiveChatState.setConversations(data.conversations);
|
|
608
608
|
}
|
|
609
609
|
|
|
610
610
|
if (Array.isArray(data.helpArticles)) {
|
|
611
|
-
this.
|
|
611
|
+
this.LiveChatState.setHelpArticles(data.helpArticles);
|
|
612
612
|
}
|
|
613
613
|
|
|
614
614
|
if (Array.isArray(data.homeChangelogItems)) {
|
|
615
|
-
this.
|
|
615
|
+
this.LiveChatState.setHomeChangelogItems(data.homeChangelogItems);
|
|
616
616
|
}
|
|
617
617
|
|
|
618
618
|
if (Array.isArray(data.changelogItems)) {
|
|
619
|
-
this.
|
|
619
|
+
this.LiveChatState.setChangelogItems(data.changelogItems);
|
|
620
620
|
}
|
|
621
621
|
|
|
622
622
|
if (typeof data.unreadCount === 'number') {
|
|
@@ -625,49 +625,49 @@ export class WebChatWidget extends BaseWidget {
|
|
|
625
625
|
|
|
626
626
|
if (data.availability && typeof data.availability === 'object') {
|
|
627
627
|
const availability = data.availability;
|
|
628
|
-
this.
|
|
628
|
+
this.LiveChatState.agentsOnline = Boolean(
|
|
629
629
|
availability.agentsOnline ??
|
|
630
630
|
availability.agents_online ??
|
|
631
631
|
availability.is_online
|
|
632
632
|
);
|
|
633
|
-
this.
|
|
633
|
+
this.LiveChatState.onlineCount =
|
|
634
634
|
availability.onlineCount ?? availability.online_count ?? 0;
|
|
635
|
-
this.
|
|
635
|
+
this.LiveChatState.responseTime =
|
|
636
636
|
availability.responseTime ??
|
|
637
637
|
availability.response_time ??
|
|
638
|
-
this.
|
|
639
|
-
this.
|
|
638
|
+
this.LiveChatState.responseTime;
|
|
639
|
+
this.LiveChatState._notify('availabilityUpdate', availability);
|
|
640
640
|
}
|
|
641
641
|
|
|
642
642
|
if (typeof data.currentView === 'string') {
|
|
643
|
-
this.
|
|
643
|
+
this.LiveChatState.setView(data.currentView);
|
|
644
644
|
}
|
|
645
645
|
}
|
|
646
646
|
|
|
647
647
|
async loadInitialData() {
|
|
648
648
|
try {
|
|
649
649
|
const conversations = await this._fetchConversations();
|
|
650
|
-
this.
|
|
650
|
+
this.LiveChatState.setConversations(conversations);
|
|
651
651
|
} catch (error) {
|
|
652
|
-
console.error('[
|
|
652
|
+
console.error('[LiveChatWidget] Failed to load conversations:', error);
|
|
653
653
|
}
|
|
654
654
|
|
|
655
|
-
if (this.
|
|
655
|
+
if (this.liveChatOptions.enableHelp) {
|
|
656
656
|
try {
|
|
657
657
|
const articles = await this._fetchHelpArticles();
|
|
658
|
-
this.
|
|
658
|
+
this.LiveChatState.setHelpArticles(articles);
|
|
659
659
|
} catch (error) {
|
|
660
|
-
console.error('[
|
|
660
|
+
console.error('[LiveChatWidget] Failed to load help articles:', error);
|
|
661
661
|
}
|
|
662
662
|
}
|
|
663
663
|
|
|
664
|
-
if (this.
|
|
664
|
+
if (this.liveChatOptions.enableChangelog) {
|
|
665
665
|
try {
|
|
666
666
|
const { homeItems, changelogItems } = await this._fetchChangelog();
|
|
667
|
-
this.
|
|
668
|
-
this.
|
|
667
|
+
this.LiveChatState.setHomeChangelogItems(homeItems);
|
|
668
|
+
this.LiveChatState.setChangelogItems(changelogItems);
|
|
669
669
|
} catch (error) {
|
|
670
|
-
console.error('[
|
|
670
|
+
console.error('[LiveChatWidget] Failed to load changelog:', error);
|
|
671
671
|
}
|
|
672
672
|
}
|
|
673
673
|
}
|
|
@@ -697,7 +697,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
697
697
|
}
|
|
698
698
|
return [];
|
|
699
699
|
} catch (error) {
|
|
700
|
-
console.error('[
|
|
700
|
+
console.error('[LiveChatWidget] Failed to fetch conversations:', error);
|
|
701
701
|
return [];
|
|
702
702
|
}
|
|
703
703
|
}
|
|
@@ -707,7 +707,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
707
707
|
const response = await this.apiService.getHelpCollections();
|
|
708
708
|
if (response.success && response.data) {
|
|
709
709
|
const collections = response.data.collections || response.data;
|
|
710
|
-
const helpBase = (this.
|
|
710
|
+
const helpBase = (this.liveChatOptions.helpUrl || '').replace(/\/$/, '');
|
|
711
711
|
|
|
712
712
|
const sorted = [...collections].sort(
|
|
713
713
|
(a, b) => (a.order ?? 0) - (b.order ?? 0)
|
|
@@ -728,7 +728,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
728
728
|
}
|
|
729
729
|
return [];
|
|
730
730
|
} catch (error) {
|
|
731
|
-
console.error('[
|
|
731
|
+
console.error('[LiveChatWidget] Failed to fetch help articles:', error);
|
|
732
732
|
return [];
|
|
733
733
|
}
|
|
734
734
|
}
|
|
@@ -765,16 +765,16 @@ export class WebChatWidget extends BaseWidget {
|
|
|
765
765
|
},
|
|
766
766
|
};
|
|
767
767
|
});
|
|
768
|
-
this.
|
|
768
|
+
this.LiveChatState.setMessages(conversationId, messages);
|
|
769
769
|
|
|
770
770
|
await this.apiService.markConversationAsRead(conversationId);
|
|
771
|
-
this.
|
|
771
|
+
this.LiveChatState.markAsRead(conversationId);
|
|
772
772
|
|
|
773
773
|
return messages;
|
|
774
774
|
}
|
|
775
775
|
return [];
|
|
776
776
|
} catch (error) {
|
|
777
|
-
console.error('[
|
|
777
|
+
console.error('[LiveChatWidget] Failed to fetch messages:', error);
|
|
778
778
|
return [];
|
|
779
779
|
}
|
|
780
780
|
}
|
|
@@ -802,7 +802,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
802
802
|
status: 'open',
|
|
803
803
|
};
|
|
804
804
|
|
|
805
|
-
this.
|
|
805
|
+
this.LiveChatState.addConversation(newConversation);
|
|
806
806
|
|
|
807
807
|
const initialMessages = [
|
|
808
808
|
{
|
|
@@ -815,23 +815,23 @@ export class WebChatWidget extends BaseWidget {
|
|
|
815
815
|
|
|
816
816
|
initialMessages.push({
|
|
817
817
|
id: 'system_rt_' + Date.now(),
|
|
818
|
-
content: this.
|
|
818
|
+
content: this.LiveChatState.agentsOnline
|
|
819
819
|
? 'One of our customer support agents will be with you shortly.'
|
|
820
|
-
: this.
|
|
820
|
+
: this.LiveChatState.responseTime,
|
|
821
821
|
isSystem: true,
|
|
822
822
|
timestamp: new Date().toISOString(),
|
|
823
823
|
});
|
|
824
824
|
|
|
825
|
-
this.
|
|
825
|
+
this.LiveChatState.setMessages(conv.id, initialMessages);
|
|
826
826
|
|
|
827
|
-
this.
|
|
828
|
-
this.
|
|
827
|
+
this.LiveChatState.setActiveConversation(conv.id);
|
|
828
|
+
this.LiveChatState.setView('chat');
|
|
829
829
|
|
|
830
830
|
return conv;
|
|
831
831
|
}
|
|
832
832
|
return null;
|
|
833
833
|
} catch (error) {
|
|
834
|
-
console.error('[
|
|
834
|
+
console.error('[LiveChatWidget] Failed to start conversation:', error);
|
|
835
835
|
return null;
|
|
836
836
|
}
|
|
837
837
|
}
|
|
@@ -846,28 +846,28 @@ export class WebChatWidget extends BaseWidget {
|
|
|
846
846
|
|
|
847
847
|
async _fetchAndApplySettings() {
|
|
848
848
|
try {
|
|
849
|
-
const response = await this.apiService.
|
|
849
|
+
const response = await this.apiService.getLiveChatSettings();
|
|
850
850
|
if (!response?.status || !response?.data) return;
|
|
851
851
|
|
|
852
852
|
const s = response.data;
|
|
853
853
|
|
|
854
854
|
// Only apply values that were NOT explicitly passed in options
|
|
855
855
|
if (s.team_name && !this._hasExplicitOption('teamName')) {
|
|
856
|
-
this.
|
|
857
|
-
this.
|
|
856
|
+
this.liveChatOptions.teamName = s.team_name;
|
|
857
|
+
this.LiveChatState.teamName = s.team_name;
|
|
858
858
|
}
|
|
859
859
|
if (s.logo_url && !this._hasExplicitOption('logoUrl')) {
|
|
860
|
-
this.
|
|
860
|
+
this.liveChatOptions.logoUrl = s.logo_url;
|
|
861
861
|
}
|
|
862
862
|
if (s.greeting_message && !this._hasExplicitOption('greetingMessage')) {
|
|
863
|
-
this.
|
|
863
|
+
this.LiveChatState.greetingMessage = s.greeting_message;
|
|
864
864
|
}
|
|
865
865
|
if (s.response_time && !this._hasExplicitOption('responseTime')) {
|
|
866
|
-
this.
|
|
866
|
+
this.LiveChatState.responseTime = s.response_time;
|
|
867
867
|
}
|
|
868
868
|
|
|
869
869
|
// Notify views to re-render with new values
|
|
870
|
-
this.
|
|
870
|
+
this.LiveChatState._notify('availabilityUpdate', {});
|
|
871
871
|
} catch (e) {
|
|
872
872
|
// non-fatal
|
|
873
873
|
}
|
|
@@ -884,23 +884,23 @@ export class WebChatWidget extends BaseWidget {
|
|
|
884
884
|
try {
|
|
885
885
|
const response = await this.apiService.checkAgentsOnline();
|
|
886
886
|
if (response.status && response.data) {
|
|
887
|
-
this.
|
|
887
|
+
this.LiveChatState.agentsOnline =
|
|
888
888
|
response.data.agents_online ?? response.data.is_online ?? false;
|
|
889
|
-
this.
|
|
890
|
-
this.
|
|
889
|
+
this.LiveChatState.onlineCount = response.data.online_count || 0;
|
|
890
|
+
this.LiveChatState.responseTime = response.data.response_time || '';
|
|
891
891
|
|
|
892
892
|
if (response.data.available_agents) {
|
|
893
|
-
this.
|
|
893
|
+
this.LiveChatState.setTeamAvatarsFromAgents(
|
|
894
894
|
response.data.available_agents
|
|
895
895
|
);
|
|
896
896
|
}
|
|
897
897
|
|
|
898
|
-
this.
|
|
898
|
+
this.LiveChatState._notify('availabilityUpdate', response.data);
|
|
899
899
|
return response.data;
|
|
900
900
|
}
|
|
901
901
|
return { agents_online: false, online_count: 0 };
|
|
902
902
|
} catch (error) {
|
|
903
|
-
console.error('[
|
|
903
|
+
console.error('[LiveChatWidget] Failed to check availability:', error);
|
|
904
904
|
return { agents_online: false, online_count: 0 };
|
|
905
905
|
}
|
|
906
906
|
}
|
|
@@ -991,7 +991,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
991
991
|
|
|
992
992
|
if (response.success && response.data) {
|
|
993
993
|
const changelogs = Array.isArray(response.data) ? response.data : [];
|
|
994
|
-
const changelogBase = (this.
|
|
994
|
+
const changelogBase = (this.liveChatOptions.changelogUrl || '').replace(
|
|
995
995
|
/\/$/,
|
|
996
996
|
''
|
|
997
997
|
);
|
|
@@ -1017,7 +1017,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
1017
1017
|
|
|
1018
1018
|
return { homeItems: [], changelogItems: [] };
|
|
1019
1019
|
} catch (error) {
|
|
1020
|
-
console.error('[
|
|
1020
|
+
console.error('[LiveChatWidget] Failed to fetch changelog:', error);
|
|
1021
1021
|
return { homeItems: [], changelogItems: [] };
|
|
1022
1022
|
}
|
|
1023
1023
|
}
|
|
@@ -1025,7 +1025,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
1025
1025
|
async onMount() {
|
|
1026
1026
|
this._applyPreviewData();
|
|
1027
1027
|
|
|
1028
|
-
if (this.
|
|
1028
|
+
if (this.liveChatOptions.autoLoadData) {
|
|
1029
1029
|
// Fetch workspace settings and apply only if not explicitly configured
|
|
1030
1030
|
this._fetchAndApplySettings();
|
|
1031
1031
|
|
|
@@ -1043,10 +1043,10 @@ export class WebChatWidget extends BaseWidget {
|
|
|
1043
1043
|
}
|
|
1044
1044
|
|
|
1045
1045
|
if (
|
|
1046
|
-
this.
|
|
1047
|
-
this.
|
|
1046
|
+
this.liveChatOptions.initialView &&
|
|
1047
|
+
this.liveChatOptions.initialView !== this.LiveChatState.currentView
|
|
1048
1048
|
) {
|
|
1049
|
-
this.
|
|
1049
|
+
this.LiveChatState.setView(this.liveChatOptions.initialView);
|
|
1050
1050
|
}
|
|
1051
1051
|
}
|
|
1052
1052
|
|
|
@@ -1068,7 +1068,7 @@ export class WebChatWidget extends BaseWidget {
|
|
|
1068
1068
|
}
|
|
1069
1069
|
|
|
1070
1070
|
destroy() {
|
|
1071
|
-
|
|
1071
|
+
removeliveChatCustomStyles();
|
|
1072
1072
|
|
|
1073
1073
|
if (this.launcher) {
|
|
1074
1074
|
this.launcher.destroy();
|