@product7/feedback-sdk 1.3.1 → 1.3.2
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/dist/feedback-sdk.js +88 -164
- 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/widgets/MessengerWidget.js +90 -164
package/package.json
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* MessengerWidget - Full-featured Messenger/Chat widget
|
|
3
|
-
*/
|
|
1
|
+
|
|
4
2
|
import { BaseWidget } from './BaseWidget.js';
|
|
5
3
|
import { MessengerState } from './messenger/MessengerState.js';
|
|
6
4
|
import { MessengerLauncher } from './messenger/components/MessengerLauncher.js';
|
|
@@ -28,13 +26,11 @@ export class MessengerWidget extends BaseWidget {
|
|
|
28
26
|
logoUrl: options.logoUrl || 'https://product7.io/p7logo.svg',
|
|
29
27
|
featuredContent: options.featuredContent || null,
|
|
30
28
|
primaryColor: options.primaryColor || '#1c1c1e',
|
|
31
|
-
// Callbacks
|
|
32
29
|
onSendMessage: options.onSendMessage || null,
|
|
33
30
|
onArticleClick: options.onArticleClick || null,
|
|
34
31
|
onChangelogClick: options.onChangelogClick || null,
|
|
35
32
|
};
|
|
36
33
|
|
|
37
|
-
// Create state
|
|
38
34
|
this.messengerState = new MessengerState({
|
|
39
35
|
teamName: this.messengerOptions.teamName,
|
|
40
36
|
teamAvatars: this.messengerOptions.teamAvatars,
|
|
@@ -49,7 +45,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
49
45
|
this.wsService = null;
|
|
50
46
|
this._wsUnsubscribers = [];
|
|
51
47
|
|
|
52
|
-
// Bind methods
|
|
53
48
|
this._handleOpenChange = this._handleOpenChange.bind(this);
|
|
54
49
|
this._handleWebSocketMessage = this._handleWebSocketMessage.bind(this);
|
|
55
50
|
this._handleTypingStarted = this._handleTypingStarted.bind(this);
|
|
@@ -58,42 +53,34 @@ export class MessengerWidget extends BaseWidget {
|
|
|
58
53
|
}
|
|
59
54
|
|
|
60
55
|
_render() {
|
|
61
|
-
// Create container
|
|
62
56
|
const container = document.createElement('div');
|
|
63
57
|
container.className = `messenger-widget theme-${this.messengerOptions.theme}`;
|
|
64
58
|
container.style.zIndex = '999999';
|
|
65
59
|
|
|
66
|
-
// Create launcher
|
|
67
60
|
this.launcher = new MessengerLauncher(this.messengerState, {
|
|
68
61
|
position: this.messengerOptions.position,
|
|
69
62
|
primaryColor: this.messengerOptions.primaryColor,
|
|
70
63
|
});
|
|
71
64
|
container.appendChild(this.launcher.render());
|
|
72
65
|
|
|
73
|
-
// Create panel with all callbacks
|
|
74
66
|
this.panel = new MessengerPanel(this.messengerState, {
|
|
75
67
|
position: this.messengerOptions.position,
|
|
76
68
|
theme: this.messengerOptions.theme,
|
|
77
69
|
primaryColor: this.messengerOptions.primaryColor,
|
|
78
70
|
logoUrl: this.messengerOptions.logoUrl,
|
|
79
71
|
featuredContent: this.messengerOptions.featuredContent,
|
|
80
|
-
// Chat callbacks
|
|
81
72
|
onSendMessage:
|
|
82
73
|
this.messengerOptions.onSendMessage ||
|
|
83
74
|
this._handleSendMessage.bind(this),
|
|
84
75
|
onStartConversation: this._handleStartConversation.bind(this),
|
|
85
76
|
onTyping: this.sendTypingIndicator.bind(this),
|
|
86
|
-
// Conversation list callbacks
|
|
87
77
|
onSelectConversation: this._handleSelectConversation.bind(this),
|
|
88
78
|
onStartNewConversation: this._handleNewConversationClick.bind(this),
|
|
89
|
-
// Pre-chat form callbacks
|
|
90
79
|
onIdentifyContact: this._handleIdentifyContact.bind(this),
|
|
91
|
-
// Article/changelog callbacks
|
|
92
80
|
onArticleClick: this.messengerOptions.onArticleClick,
|
|
93
81
|
onChangelogClick: this.messengerOptions.onChangelogClick,
|
|
94
82
|
});
|
|
95
83
|
|
|
96
|
-
// Register views
|
|
97
84
|
this.panel.registerView('home', HomeView);
|
|
98
85
|
this.panel.registerView('messages', ConversationsView);
|
|
99
86
|
this.panel.registerView('chat', ChatView);
|
|
@@ -108,13 +95,15 @@ export class MessengerWidget extends BaseWidget {
|
|
|
108
95
|
}
|
|
109
96
|
|
|
110
97
|
_attachEvents() {
|
|
111
|
-
// Subscribe to state changes
|
|
112
98
|
this._stateUnsubscribe = this.messengerState.subscribe((type, data) => {
|
|
113
99
|
if (type === 'openChange') {
|
|
114
100
|
this._handleOpenChange(data.isOpen);
|
|
115
101
|
}
|
|
116
102
|
if (type === 'conversationChange') {
|
|
117
|
-
this._handleActiveConversationChange(
|
|
103
|
+
this._handleActiveConversationChange(
|
|
104
|
+
data.conversationId,
|
|
105
|
+
data.previousConversationId
|
|
106
|
+
);
|
|
118
107
|
}
|
|
119
108
|
});
|
|
120
109
|
}
|
|
@@ -130,31 +119,38 @@ export class MessengerWidget extends BaseWidget {
|
|
|
130
119
|
}
|
|
131
120
|
}
|
|
132
121
|
|
|
133
|
-
/**
|
|
134
|
-
* Subscribe/unsubscribe to conversation WebSocket channel
|
|
135
|
-
*/
|
|
136
122
|
_handleActiveConversationChange(conversationId, previousConversationId) {
|
|
137
123
|
if (previousConversationId && this.wsService) {
|
|
138
|
-
this.wsService.send('conversation:unsubscribe', {
|
|
124
|
+
this.wsService.send('conversation:unsubscribe', {
|
|
125
|
+
conversation_id: previousConversationId,
|
|
126
|
+
});
|
|
139
127
|
}
|
|
140
128
|
if (conversationId && this.wsService) {
|
|
141
|
-
this.wsService.send('conversation:subscribe', {
|
|
129
|
+
this.wsService.send('conversation:subscribe', {
|
|
130
|
+
conversation_id: conversationId,
|
|
131
|
+
});
|
|
142
132
|
}
|
|
143
133
|
}
|
|
144
134
|
|
|
145
|
-
/**
|
|
146
|
-
* Handle starting a new conversation
|
|
147
|
-
* If there's an existing open conversation, send the message there instead
|
|
148
|
-
*/
|
|
149
135
|
async _handleStartConversation(messageContent, pendingAttachments) {
|
|
150
136
|
try {
|
|
151
|
-
|
|
137
|
+
const userContext = this.messengerState.userContext;
|
|
138
|
+
const isIdentified = userContext?.email;
|
|
139
|
+
|
|
140
|
+
if (!isIdentified) {
|
|
141
|
+
this.messengerState.pendingMessage = {
|
|
142
|
+
content: messageContent,
|
|
143
|
+
attachments: pendingAttachments,
|
|
144
|
+
};
|
|
145
|
+
this.messengerState.setView('prechat');
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
152
149
|
const openConversation = this.messengerState.conversations.find(
|
|
153
150
|
(c) => c.status === 'open'
|
|
154
151
|
);
|
|
155
152
|
|
|
156
153
|
if (openConversation) {
|
|
157
|
-
// Route message to existing open conversation
|
|
158
154
|
this.messengerState.setActiveConversation(openConversation.id);
|
|
159
155
|
await this._handleSendMessage(
|
|
160
156
|
openConversation.id,
|
|
@@ -164,16 +160,17 @@ export class MessengerWidget extends BaseWidget {
|
|
|
164
160
|
return openConversation;
|
|
165
161
|
}
|
|
166
162
|
|
|
167
|
-
return await this.startNewConversation(
|
|
163
|
+
return await this.startNewConversation(
|
|
164
|
+
messageContent,
|
|
165
|
+
'',
|
|
166
|
+
pendingAttachments
|
|
167
|
+
);
|
|
168
168
|
} catch (error) {
|
|
169
169
|
console.error('[MessengerWidget] Failed to start conversation:', error);
|
|
170
170
|
return null;
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
/**
|
|
175
|
-
* Handle selecting a conversation from the list
|
|
176
|
-
*/
|
|
177
174
|
async _handleSelectConversation(conversationId) {
|
|
178
175
|
try {
|
|
179
176
|
await this.fetchMessages(conversationId);
|
|
@@ -182,34 +179,23 @@ export class MessengerWidget extends BaseWidget {
|
|
|
182
179
|
}
|
|
183
180
|
}
|
|
184
181
|
|
|
185
|
-
/**
|
|
186
|
-
* Handle clicking "new conversation" button
|
|
187
|
-
* Reuses the most recent open conversation if one exists
|
|
188
|
-
*/
|
|
189
182
|
_handleNewConversationClick() {
|
|
190
|
-
// Check for an existing open conversation to reuse
|
|
191
183
|
const openConversation = this.messengerState.conversations.find(
|
|
192
184
|
(c) => c.status === 'open'
|
|
193
185
|
);
|
|
194
186
|
|
|
195
187
|
if (openConversation) {
|
|
196
|
-
// Reuse existing open conversation
|
|
197
188
|
this.messengerState.setActiveConversation(openConversation.id);
|
|
198
189
|
this.messengerState.setView('chat');
|
|
199
190
|
this._handleSelectConversation(openConversation.id);
|
|
200
191
|
} else {
|
|
201
|
-
// No open conversation — start a new one
|
|
202
192
|
this.messengerState.setActiveConversation(null);
|
|
203
193
|
this.messengerState.setView('chat');
|
|
204
194
|
}
|
|
205
195
|
}
|
|
206
196
|
|
|
207
|
-
/**
|
|
208
|
-
* Handle identifying contact from pre-chat form
|
|
209
|
-
*/
|
|
210
197
|
async _handleIdentifyContact(contactData) {
|
|
211
198
|
try {
|
|
212
|
-
// Call API to identify/update contact
|
|
213
199
|
const response = await this.apiService.identifyContact({
|
|
214
200
|
name: contactData.name,
|
|
215
201
|
email: contactData.email,
|
|
@@ -218,12 +204,24 @@ export class MessengerWidget extends BaseWidget {
|
|
|
218
204
|
if (response.status) {
|
|
219
205
|
console.log('[MessengerWidget] Contact identified:', contactData.email);
|
|
220
206
|
|
|
221
|
-
// Update local user context
|
|
222
207
|
if (!this.messengerState.userContext) {
|
|
223
208
|
this.messengerState.userContext = {};
|
|
224
209
|
}
|
|
225
210
|
this.messengerState.userContext.name = contactData.name;
|
|
226
211
|
this.messengerState.userContext.email = contactData.email;
|
|
212
|
+
|
|
213
|
+
const pendingMessage = this.messengerState.pendingMessage;
|
|
214
|
+
if (pendingMessage) {
|
|
215
|
+
this.messengerState.pendingMessage = null;
|
|
216
|
+
|
|
217
|
+
await this.startNewConversation(
|
|
218
|
+
pendingMessage.content,
|
|
219
|
+
'',
|
|
220
|
+
pendingMessage.attachments
|
|
221
|
+
);
|
|
222
|
+
} else {
|
|
223
|
+
this.messengerState.setView('chat');
|
|
224
|
+
}
|
|
227
225
|
}
|
|
228
226
|
|
|
229
227
|
return response;
|
|
@@ -259,14 +257,17 @@ export class MessengerWidget extends BaseWidget {
|
|
|
259
257
|
name: att.file.name,
|
|
260
258
|
});
|
|
261
259
|
} catch (err) {
|
|
262
|
-
console.error(
|
|
260
|
+
console.error(
|
|
261
|
+
'[MessengerWidget] Skipping failed attachment upload:',
|
|
262
|
+
att.file.name,
|
|
263
|
+
err
|
|
264
|
+
);
|
|
263
265
|
}
|
|
264
266
|
}
|
|
265
267
|
return uploaded;
|
|
266
268
|
}
|
|
267
269
|
|
|
268
270
|
async _handleSendMessage(conversationId, message, pendingAttachments) {
|
|
269
|
-
// Emit event for external listeners
|
|
270
271
|
this.sdk.eventBus.emit('messenger:messageSent', {
|
|
271
272
|
widget: this,
|
|
272
273
|
conversationId,
|
|
@@ -274,22 +275,18 @@ export class MessengerWidget extends BaseWidget {
|
|
|
274
275
|
});
|
|
275
276
|
|
|
276
277
|
try {
|
|
277
|
-
|
|
278
|
-
|
|
278
|
+
const uploadedAttachments =
|
|
279
|
+
await this._uploadPendingAttachments(pendingAttachments);
|
|
279
280
|
|
|
280
|
-
// Send message through API
|
|
281
281
|
const response = await this.apiService.sendMessage(conversationId, {
|
|
282
282
|
content: message.content,
|
|
283
283
|
attachments: uploadedAttachments,
|
|
284
284
|
});
|
|
285
285
|
|
|
286
286
|
if (response.status && response.data) {
|
|
287
|
-
// Update the message ID with server-assigned ID
|
|
288
|
-
// Message is already added to state optimistically in ChatView
|
|
289
287
|
console.log('[MessengerWidget] Message sent:', response.data.id);
|
|
290
288
|
}
|
|
291
289
|
|
|
292
|
-
// In mock mode, simulate an agent response after a delay
|
|
293
290
|
if (this.apiService?.mock) {
|
|
294
291
|
setTimeout(() => {
|
|
295
292
|
const mockResponse = {
|
|
@@ -307,29 +304,24 @@ export class MessengerWidget extends BaseWidget {
|
|
|
307
304
|
}
|
|
308
305
|
} catch (error) {
|
|
309
306
|
console.error('[MessengerWidget] Failed to send message:', error);
|
|
310
|
-
// Could add error handling UI here
|
|
311
307
|
}
|
|
312
308
|
}
|
|
313
309
|
|
|
314
|
-
/**
|
|
315
|
-
* Handle incoming WebSocket message
|
|
316
|
-
*/
|
|
317
310
|
_handleWebSocketMessage(data) {
|
|
318
311
|
const { conversation_id, message } = data;
|
|
319
312
|
|
|
320
|
-
// Parse attachments from server message
|
|
321
313
|
let attachments = [];
|
|
322
314
|
if (message.attachments) {
|
|
323
315
|
try {
|
|
324
|
-
attachments =
|
|
325
|
-
|
|
326
|
-
|
|
316
|
+
attachments =
|
|
317
|
+
typeof message.attachments === 'string'
|
|
318
|
+
? JSON.parse(message.attachments)
|
|
319
|
+
: message.attachments;
|
|
327
320
|
} catch (e) {
|
|
328
|
-
// ignore
|
|
321
|
+
// ignore
|
|
329
322
|
}
|
|
330
323
|
}
|
|
331
324
|
|
|
332
|
-
// Transform message to local format
|
|
333
325
|
const localMessage = {
|
|
334
326
|
id: message.id,
|
|
335
327
|
content: message.content,
|
|
@@ -342,10 +334,8 @@ export class MessengerWidget extends BaseWidget {
|
|
|
342
334
|
},
|
|
343
335
|
};
|
|
344
336
|
|
|
345
|
-
// Add message to state
|
|
346
337
|
this.messengerState.addMessage(conversation_id, localMessage);
|
|
347
338
|
|
|
348
|
-
// Update unread count if panel is closed or viewing different conversation
|
|
349
339
|
if (
|
|
350
340
|
!this.messengerState.isOpen ||
|
|
351
341
|
this.messengerState.activeConversationId !== conversation_id
|
|
@@ -354,9 +344,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
354
344
|
}
|
|
355
345
|
}
|
|
356
346
|
|
|
357
|
-
/**
|
|
358
|
-
* Handle typing started event
|
|
359
|
-
*/
|
|
360
347
|
_handleTypingStarted(data) {
|
|
361
348
|
if (data.is_agent) {
|
|
362
349
|
this.messengerState._notify('typingStarted', {
|
|
@@ -366,31 +353,20 @@ export class MessengerWidget extends BaseWidget {
|
|
|
366
353
|
}
|
|
367
354
|
}
|
|
368
355
|
|
|
369
|
-
/**
|
|
370
|
-
* Handle typing stopped event
|
|
371
|
-
*/
|
|
372
356
|
_handleTypingStopped(data) {
|
|
373
357
|
this.messengerState._notify('typingStopped', {
|
|
374
358
|
conversationId: data.conversation_id,
|
|
375
359
|
});
|
|
376
360
|
}
|
|
377
361
|
|
|
378
|
-
/**
|
|
379
|
-
* Handle conversation closed event
|
|
380
|
-
*/
|
|
381
362
|
_handleConversationClosed(data) {
|
|
382
363
|
const conversationId =
|
|
383
|
-
data?.conversation_id ||
|
|
384
|
-
data?.id ||
|
|
385
|
-
data?.conversation?.id;
|
|
364
|
+
data?.conversation_id || data?.id || data?.conversation?.id;
|
|
386
365
|
if (!conversationId) return;
|
|
387
366
|
|
|
388
367
|
this.messengerState.updateConversation(conversationId, { status: 'closed' });
|
|
389
368
|
}
|
|
390
369
|
|
|
391
|
-
/**
|
|
392
|
-
* Update unread count from API
|
|
393
|
-
*/
|
|
394
370
|
async _updateUnreadCount() {
|
|
395
371
|
try {
|
|
396
372
|
const response = await this.apiService.getUnreadCount();
|
|
@@ -405,9 +381,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
405
381
|
}
|
|
406
382
|
}
|
|
407
383
|
|
|
408
|
-
/**
|
|
409
|
-
* Initialize WebSocket connection
|
|
410
|
-
*/
|
|
411
384
|
_initWebSocket() {
|
|
412
385
|
if (this.wsService) {
|
|
413
386
|
this.wsService.disconnect();
|
|
@@ -420,7 +393,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
420
393
|
mock: this.apiService.mock,
|
|
421
394
|
});
|
|
422
395
|
|
|
423
|
-
// Subscribe to WebSocket events
|
|
424
396
|
this._wsUnsubscribers.push(
|
|
425
397
|
this.wsService.on('message', this._handleWebSocketMessage)
|
|
426
398
|
);
|
|
@@ -436,7 +408,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
436
408
|
this._wsUnsubscribers.push(
|
|
437
409
|
this.wsService.on('connected', () => {
|
|
438
410
|
console.log('[MessengerWidget] WebSocket connected');
|
|
439
|
-
// Re-subscribe to active conversation on reconnect
|
|
440
411
|
if (this.messengerState.activeConversationId) {
|
|
441
412
|
this.wsService.send('conversation:subscribe', {
|
|
442
413
|
conversation_id: this.messengerState.activeConversationId,
|
|
@@ -450,34 +421,21 @@ export class MessengerWidget extends BaseWidget {
|
|
|
450
421
|
})
|
|
451
422
|
);
|
|
452
423
|
|
|
453
|
-
// Connect
|
|
454
424
|
this.wsService.connect();
|
|
455
425
|
}
|
|
456
426
|
|
|
457
|
-
/**
|
|
458
|
-
* Open the messenger panel
|
|
459
|
-
*/
|
|
460
427
|
open() {
|
|
461
428
|
this.messengerState.setOpen(true);
|
|
462
429
|
}
|
|
463
430
|
|
|
464
|
-
/**
|
|
465
|
-
* Close the messenger panel
|
|
466
|
-
*/
|
|
467
431
|
close() {
|
|
468
432
|
this.messengerState.setOpen(false);
|
|
469
433
|
}
|
|
470
434
|
|
|
471
|
-
/**
|
|
472
|
-
* Toggle the messenger panel
|
|
473
|
-
*/
|
|
474
435
|
toggle() {
|
|
475
436
|
this.messengerState.setOpen(!this.messengerState.isOpen);
|
|
476
437
|
}
|
|
477
438
|
|
|
478
|
-
/**
|
|
479
|
-
* Navigate to a specific view
|
|
480
|
-
*/
|
|
481
439
|
navigateTo(view) {
|
|
482
440
|
this.messengerState.setView(view);
|
|
483
441
|
if (!this.messengerState.isOpen) {
|
|
@@ -485,52 +443,31 @@ export class MessengerWidget extends BaseWidget {
|
|
|
485
443
|
}
|
|
486
444
|
}
|
|
487
445
|
|
|
488
|
-
/**
|
|
489
|
-
* Set conversations
|
|
490
|
-
*/
|
|
491
446
|
setConversations(conversations) {
|
|
492
447
|
this.messengerState.setConversations(conversations);
|
|
493
448
|
}
|
|
494
449
|
|
|
495
|
-
/**
|
|
496
|
-
* Add a message to a conversation
|
|
497
|
-
*/
|
|
498
450
|
addMessage(conversationId, message) {
|
|
499
451
|
this.messengerState.addMessage(conversationId, message);
|
|
500
452
|
}
|
|
501
453
|
|
|
502
|
-
/**
|
|
503
|
-
* Set help articles
|
|
504
|
-
*/
|
|
505
454
|
setHelpArticles(articles) {
|
|
506
455
|
this.messengerState.setHelpArticles(articles);
|
|
507
456
|
}
|
|
508
457
|
|
|
509
|
-
/**
|
|
510
|
-
* Set home changelog items
|
|
511
|
-
*/
|
|
512
458
|
setHomeChangelogItems(items) {
|
|
513
459
|
this.messengerState.setHomeChangelogItems(items);
|
|
514
460
|
}
|
|
515
461
|
|
|
516
|
-
/**
|
|
517
|
-
* Set changelog items
|
|
518
|
-
*/
|
|
519
462
|
setChangelogItems(items) {
|
|
520
463
|
this.messengerState.setChangelogItems(items);
|
|
521
464
|
}
|
|
522
465
|
|
|
523
|
-
/**
|
|
524
|
-
* Update unread count (for external updates)
|
|
525
|
-
*/
|
|
526
466
|
setUnreadCount(count) {
|
|
527
467
|
this.messengerState.unreadCount = count;
|
|
528
468
|
this.messengerState._notify('unreadCountChange', { count });
|
|
529
469
|
}
|
|
530
470
|
|
|
531
|
-
/**
|
|
532
|
-
* Get current state
|
|
533
|
-
*/
|
|
534
471
|
getState() {
|
|
535
472
|
return {
|
|
536
473
|
isOpen: this.messengerState.isOpen,
|
|
@@ -540,11 +477,7 @@ export class MessengerWidget extends BaseWidget {
|
|
|
540
477
|
};
|
|
541
478
|
}
|
|
542
479
|
|
|
543
|
-
/**
|
|
544
|
-
* Load initial data (mock or API)
|
|
545
|
-
*/
|
|
546
480
|
async loadInitialData() {
|
|
547
|
-
// Load conversations
|
|
548
481
|
try {
|
|
549
482
|
const conversations = await this._fetchConversations();
|
|
550
483
|
this.messengerState.setConversations(conversations);
|
|
@@ -552,7 +485,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
552
485
|
console.error('[MessengerWidget] Failed to load conversations:', error);
|
|
553
486
|
}
|
|
554
487
|
|
|
555
|
-
// Load help articles if enabled
|
|
556
488
|
if (this.messengerOptions.enableHelp) {
|
|
557
489
|
try {
|
|
558
490
|
const articles = await this._fetchHelpArticles();
|
|
@@ -562,7 +494,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
562
494
|
}
|
|
563
495
|
}
|
|
564
496
|
|
|
565
|
-
// Load changelog if enabled
|
|
566
497
|
if (this.messengerOptions.enableChangelog) {
|
|
567
498
|
try {
|
|
568
499
|
const { homeItems, changelogItems } = await this._fetchChangelog();
|
|
@@ -578,7 +509,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
578
509
|
try {
|
|
579
510
|
const response = await this.apiService.getConversations();
|
|
580
511
|
if (response.status && response.data) {
|
|
581
|
-
// Transform API response to local format
|
|
582
512
|
return response.data.map((conv) => ({
|
|
583
513
|
id: conv.id,
|
|
584
514
|
title:
|
|
@@ -609,7 +539,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
609
539
|
try {
|
|
610
540
|
const response = await this.apiService.getHelpCollections();
|
|
611
541
|
if (response.status && response.data) {
|
|
612
|
-
// Transform API response to local format
|
|
613
542
|
return response.data.map((collection) => ({
|
|
614
543
|
id: collection.id,
|
|
615
544
|
title: collection.title || collection.name,
|
|
@@ -627,9 +556,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
627
556
|
}
|
|
628
557
|
}
|
|
629
558
|
|
|
630
|
-
/**
|
|
631
|
-
* Fetch messages for a conversation
|
|
632
|
-
*/
|
|
633
559
|
async fetchMessages(conversationId) {
|
|
634
560
|
try {
|
|
635
561
|
const response = await this.apiService.getConversation(conversationId);
|
|
@@ -638,11 +564,12 @@ export class MessengerWidget extends BaseWidget {
|
|
|
638
564
|
let attachments;
|
|
639
565
|
if (msg.attachments) {
|
|
640
566
|
try {
|
|
641
|
-
attachments =
|
|
642
|
-
|
|
643
|
-
|
|
567
|
+
attachments =
|
|
568
|
+
typeof msg.attachments === 'string'
|
|
569
|
+
? JSON.parse(msg.attachments)
|
|
570
|
+
: msg.attachments;
|
|
644
571
|
} catch (e) {
|
|
645
|
-
// ignore
|
|
572
|
+
// ignore
|
|
646
573
|
}
|
|
647
574
|
}
|
|
648
575
|
return {
|
|
@@ -650,16 +577,18 @@ export class MessengerWidget extends BaseWidget {
|
|
|
650
577
|
content: msg.content,
|
|
651
578
|
isOwn: msg.sender_type === 'customer',
|
|
652
579
|
timestamp: msg.created_at,
|
|
653
|
-
attachments:
|
|
580
|
+
attachments:
|
|
581
|
+
attachments && attachments.length > 0 ? attachments : undefined,
|
|
654
582
|
sender: {
|
|
655
|
-
name:
|
|
583
|
+
name:
|
|
584
|
+
msg.sender_name ||
|
|
585
|
+
(msg.sender_type === 'customer' ? 'You' : 'Support'),
|
|
656
586
|
avatarUrl: msg.sender_avatar || null,
|
|
657
587
|
},
|
|
658
588
|
};
|
|
659
589
|
});
|
|
660
590
|
this.messengerState.setMessages(conversationId, messages);
|
|
661
591
|
|
|
662
|
-
// Mark as read
|
|
663
592
|
await this.apiService.markConversationAsRead(conversationId);
|
|
664
593
|
this.messengerState.markAsRead(conversationId);
|
|
665
594
|
|
|
@@ -672,19 +601,18 @@ export class MessengerWidget extends BaseWidget {
|
|
|
672
601
|
}
|
|
673
602
|
}
|
|
674
603
|
|
|
675
|
-
/**
|
|
676
|
-
* Start a new conversation
|
|
677
|
-
*/
|
|
678
604
|
async startNewConversation(message, subject = '', pendingAttachments = []) {
|
|
679
605
|
try {
|
|
680
|
-
|
|
681
|
-
|
|
606
|
+
const uploadedAttachments =
|
|
607
|
+
await this._uploadPendingAttachments(pendingAttachments);
|
|
682
608
|
|
|
683
609
|
console.log('[MessengerWidget] Starting conversation...', {
|
|
684
610
|
message,
|
|
685
611
|
attachmentCount: uploadedAttachments.length,
|
|
686
612
|
hasSession: this.apiService.isSessionValid(),
|
|
687
|
-
sessionToken: this.apiService.sessionToken
|
|
613
|
+
sessionToken: this.apiService.sessionToken
|
|
614
|
+
? this.apiService.sessionToken.substring(0, 10) + '...'
|
|
615
|
+
: null,
|
|
688
616
|
baseURL: this.apiService.baseURL,
|
|
689
617
|
mock: this.apiService.mock,
|
|
690
618
|
});
|
|
@@ -709,10 +637,8 @@ export class MessengerWidget extends BaseWidget {
|
|
|
709
637
|
status: 'open',
|
|
710
638
|
};
|
|
711
639
|
|
|
712
|
-
// Add to state
|
|
713
640
|
this.messengerState.addConversation(newConversation);
|
|
714
641
|
|
|
715
|
-
// Set initial message in messages cache
|
|
716
642
|
this.messengerState.setMessages(conv.id, [
|
|
717
643
|
{
|
|
718
644
|
id: 'msg_' + Date.now(),
|
|
@@ -722,7 +648,6 @@ export class MessengerWidget extends BaseWidget {
|
|
|
722
648
|
},
|
|
723
649
|
]);
|
|
724
650
|
|
|
725
|
-
// Navigate to chat
|
|
726
651
|
this.messengerState.setActiveConversation(conv.id);
|
|
727
652
|
this.messengerState.setView('chat');
|
|
728
653
|
|
|
@@ -735,20 +660,14 @@ export class MessengerWidget extends BaseWidget {
|
|
|
735
660
|
}
|
|
736
661
|
}
|
|
737
662
|
|
|
738
|
-
/**
|
|
739
|
-
* Send typing indicator
|
|
740
|
-
*/
|
|
741
663
|
async sendTypingIndicator(conversationId, isTyping) {
|
|
742
664
|
try {
|
|
743
665
|
await this.apiService.sendTypingIndicator(conversationId, isTyping);
|
|
744
666
|
} catch (error) {
|
|
745
|
-
//
|
|
667
|
+
// Silent fail
|
|
746
668
|
}
|
|
747
669
|
}
|
|
748
670
|
|
|
749
|
-
/**
|
|
750
|
-
* Check agent availability
|
|
751
|
-
*/
|
|
752
671
|
async checkAgentAvailability() {
|
|
753
672
|
try {
|
|
754
673
|
const response = await this.apiService.checkAgentsOnline();
|
|
@@ -757,9 +676,10 @@ export class MessengerWidget extends BaseWidget {
|
|
|
757
676
|
this.messengerState.onlineCount = response.data.online_count || 0;
|
|
758
677
|
this.messengerState.responseTime = response.data.response_time || '';
|
|
759
678
|
|
|
760
|
-
// Update team avatars from online agents
|
|
761
679
|
if (response.data.available_agents) {
|
|
762
|
-
this.messengerState.setTeamAvatarsFromAgents(
|
|
680
|
+
this.messengerState.setTeamAvatarsFromAgents(
|
|
681
|
+
response.data.available_agents
|
|
682
|
+
);
|
|
763
683
|
}
|
|
764
684
|
|
|
765
685
|
this.messengerState._notify('availabilityUpdate', response.data);
|
|
@@ -851,11 +771,9 @@ export class MessengerWidget extends BaseWidget {
|
|
|
851
771
|
};
|
|
852
772
|
}
|
|
853
773
|
|
|
854
|
-
// Fetch changelogs from API
|
|
855
774
|
const response = await this.apiService.getChangelogs({ limit: 20 });
|
|
856
775
|
const changelogs = response.data || [];
|
|
857
776
|
|
|
858
|
-
// Map API response to expected format
|
|
859
777
|
const mappedItems = changelogs.map((item) => ({
|
|
860
778
|
id: item.id,
|
|
861
779
|
title: item.title,
|
|
@@ -873,19 +791,30 @@ export class MessengerWidget extends BaseWidget {
|
|
|
873
791
|
};
|
|
874
792
|
}
|
|
875
793
|
|
|
876
|
-
onMount() {
|
|
877
|
-
|
|
794
|
+
async onMount() {
|
|
795
|
+
const userContext = this.messengerState.userContext;
|
|
796
|
+
if (userContext?.email && userContext?.name) {
|
|
797
|
+
try {
|
|
798
|
+
await this.apiService.identifyContact({
|
|
799
|
+
name: userContext.name,
|
|
800
|
+
email: userContext.email,
|
|
801
|
+
});
|
|
802
|
+
console.log('[MessengerWidget] User identified successfully');
|
|
803
|
+
} catch (error) {
|
|
804
|
+
if (error?.code !== 'ALREADY_IDENTIFIED') {
|
|
805
|
+
console.warn('[MessengerWidget] Identification failed:', error);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
878
810
|
this.loadInitialData();
|
|
879
811
|
|
|
880
|
-
// Initialize WebSocket for real-time updates
|
|
881
812
|
if (this.apiService?.sessionToken) {
|
|
882
813
|
this._initWebSocket();
|
|
883
814
|
}
|
|
884
815
|
|
|
885
|
-
// Check agent availability
|
|
886
816
|
this.checkAgentAvailability();
|
|
887
817
|
|
|
888
|
-
// Periodically check availability (every 60 seconds)
|
|
889
818
|
this._availabilityInterval = setInterval(() => {
|
|
890
819
|
this.checkAgentAvailability();
|
|
891
820
|
}, 60000);
|
|
@@ -896,16 +825,13 @@ export class MessengerWidget extends BaseWidget {
|
|
|
896
825
|
this._stateUnsubscribe();
|
|
897
826
|
}
|
|
898
827
|
|
|
899
|
-
// Clean up WebSocket
|
|
900
828
|
if (this.wsService) {
|
|
901
829
|
this.wsService.disconnect();
|
|
902
830
|
}
|
|
903
831
|
|
|
904
|
-
// Clean up WebSocket event listeners
|
|
905
832
|
this._wsUnsubscribers.forEach((unsub) => unsub());
|
|
906
833
|
this._wsUnsubscribers = [];
|
|
907
834
|
|
|
908
|
-
// Clean up availability interval
|
|
909
835
|
if (this._availabilityInterval) {
|
|
910
836
|
clearInterval(this._availabilityInterval);
|
|
911
837
|
}
|
|
@@ -921,4 +847,4 @@ export class MessengerWidget extends BaseWidget {
|
|
|
921
847
|
this.onDestroy();
|
|
922
848
|
super.destroy();
|
|
923
849
|
}
|
|
924
|
-
}
|
|
850
|
+
}
|