@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.
@@ -5736,10 +5736,6 @@
5736
5736
  }
5737
5737
  }
5738
5738
 
5739
- /**
5740
- * MessengerWidget - Full-featured Messenger/Chat widget
5741
- */
5742
-
5743
5739
  class MessengerWidget extends BaseWidget {
5744
5740
  constructor(options) {
5745
5741
  super({ ...options, type: 'messenger' });
@@ -5755,13 +5751,11 @@
5755
5751
  logoUrl: options.logoUrl || 'https://product7.io/p7logo.svg',
5756
5752
  featuredContent: options.featuredContent || null,
5757
5753
  primaryColor: options.primaryColor || '#1c1c1e',
5758
- // Callbacks
5759
5754
  onSendMessage: options.onSendMessage || null,
5760
5755
  onArticleClick: options.onArticleClick || null,
5761
5756
  onChangelogClick: options.onChangelogClick || null,
5762
5757
  };
5763
5758
 
5764
- // Create state
5765
5759
  this.messengerState = new MessengerState({
5766
5760
  teamName: this.messengerOptions.teamName,
5767
5761
  teamAvatars: this.messengerOptions.teamAvatars,
@@ -5776,7 +5770,6 @@
5776
5770
  this.wsService = null;
5777
5771
  this._wsUnsubscribers = [];
5778
5772
 
5779
- // Bind methods
5780
5773
  this._handleOpenChange = this._handleOpenChange.bind(this);
5781
5774
  this._handleWebSocketMessage = this._handleWebSocketMessage.bind(this);
5782
5775
  this._handleTypingStarted = this._handleTypingStarted.bind(this);
@@ -5785,42 +5778,34 @@
5785
5778
  }
5786
5779
 
5787
5780
  _render() {
5788
- // Create container
5789
5781
  const container = document.createElement('div');
5790
5782
  container.className = `messenger-widget theme-${this.messengerOptions.theme}`;
5791
5783
  container.style.zIndex = '999999';
5792
5784
 
5793
- // Create launcher
5794
5785
  this.launcher = new MessengerLauncher(this.messengerState, {
5795
5786
  position: this.messengerOptions.position,
5796
5787
  primaryColor: this.messengerOptions.primaryColor,
5797
5788
  });
5798
5789
  container.appendChild(this.launcher.render());
5799
5790
 
5800
- // Create panel with all callbacks
5801
5791
  this.panel = new MessengerPanel(this.messengerState, {
5802
5792
  position: this.messengerOptions.position,
5803
5793
  theme: this.messengerOptions.theme,
5804
5794
  primaryColor: this.messengerOptions.primaryColor,
5805
5795
  logoUrl: this.messengerOptions.logoUrl,
5806
5796
  featuredContent: this.messengerOptions.featuredContent,
5807
- // Chat callbacks
5808
5797
  onSendMessage:
5809
5798
  this.messengerOptions.onSendMessage ||
5810
5799
  this._handleSendMessage.bind(this),
5811
5800
  onStartConversation: this._handleStartConversation.bind(this),
5812
5801
  onTyping: this.sendTypingIndicator.bind(this),
5813
- // Conversation list callbacks
5814
5802
  onSelectConversation: this._handleSelectConversation.bind(this),
5815
5803
  onStartNewConversation: this._handleNewConversationClick.bind(this),
5816
- // Pre-chat form callbacks
5817
5804
  onIdentifyContact: this._handleIdentifyContact.bind(this),
5818
- // Article/changelog callbacks
5819
5805
  onArticleClick: this.messengerOptions.onArticleClick,
5820
5806
  onChangelogClick: this.messengerOptions.onChangelogClick,
5821
5807
  });
5822
5808
 
5823
- // Register views
5824
5809
  this.panel.registerView('home', HomeView);
5825
5810
  this.panel.registerView('messages', ConversationsView);
5826
5811
  this.panel.registerView('chat', ChatView);
@@ -5835,13 +5820,15 @@
5835
5820
  }
5836
5821
 
5837
5822
  _attachEvents() {
5838
- // Subscribe to state changes
5839
5823
  this._stateUnsubscribe = this.messengerState.subscribe((type, data) => {
5840
5824
  if (type === 'openChange') {
5841
5825
  this._handleOpenChange(data.isOpen);
5842
5826
  }
5843
5827
  if (type === 'conversationChange') {
5844
- this._handleActiveConversationChange(data.conversationId, data.previousConversationId);
5828
+ this._handleActiveConversationChange(
5829
+ data.conversationId,
5830
+ data.previousConversationId
5831
+ );
5845
5832
  }
5846
5833
  });
5847
5834
  }
@@ -5857,31 +5844,38 @@
5857
5844
  }
5858
5845
  }
5859
5846
 
5860
- /**
5861
- * Subscribe/unsubscribe to conversation WebSocket channel
5862
- */
5863
5847
  _handleActiveConversationChange(conversationId, previousConversationId) {
5864
5848
  if (previousConversationId && this.wsService) {
5865
- this.wsService.send('conversation:unsubscribe', { conversation_id: previousConversationId });
5849
+ this.wsService.send('conversation:unsubscribe', {
5850
+ conversation_id: previousConversationId,
5851
+ });
5866
5852
  }
5867
5853
  if (conversationId && this.wsService) {
5868
- this.wsService.send('conversation:subscribe', { conversation_id: conversationId });
5854
+ this.wsService.send('conversation:subscribe', {
5855
+ conversation_id: conversationId,
5856
+ });
5869
5857
  }
5870
5858
  }
5871
5859
 
5872
- /**
5873
- * Handle starting a new conversation
5874
- * If there's an existing open conversation, send the message there instead
5875
- */
5876
5860
  async _handleStartConversation(messageContent, pendingAttachments) {
5877
5861
  try {
5878
- // Check for existing open conversation first
5862
+ const userContext = this.messengerState.userContext;
5863
+ const isIdentified = userContext?.email;
5864
+
5865
+ if (!isIdentified) {
5866
+ this.messengerState.pendingMessage = {
5867
+ content: messageContent,
5868
+ attachments: pendingAttachments,
5869
+ };
5870
+ this.messengerState.setView('prechat');
5871
+ return null;
5872
+ }
5873
+
5879
5874
  const openConversation = this.messengerState.conversations.find(
5880
5875
  (c) => c.status === 'open'
5881
5876
  );
5882
5877
 
5883
5878
  if (openConversation) {
5884
- // Route message to existing open conversation
5885
5879
  this.messengerState.setActiveConversation(openConversation.id);
5886
5880
  await this._handleSendMessage(
5887
5881
  openConversation.id,
@@ -5891,16 +5885,17 @@
5891
5885
  return openConversation;
5892
5886
  }
5893
5887
 
5894
- return await this.startNewConversation(messageContent, '', pendingAttachments);
5888
+ return await this.startNewConversation(
5889
+ messageContent,
5890
+ '',
5891
+ pendingAttachments
5892
+ );
5895
5893
  } catch (error) {
5896
5894
  console.error('[MessengerWidget] Failed to start conversation:', error);
5897
5895
  return null;
5898
5896
  }
5899
5897
  }
5900
5898
 
5901
- /**
5902
- * Handle selecting a conversation from the list
5903
- */
5904
5899
  async _handleSelectConversation(conversationId) {
5905
5900
  try {
5906
5901
  await this.fetchMessages(conversationId);
@@ -5909,34 +5904,23 @@
5909
5904
  }
5910
5905
  }
5911
5906
 
5912
- /**
5913
- * Handle clicking "new conversation" button
5914
- * Reuses the most recent open conversation if one exists
5915
- */
5916
5907
  _handleNewConversationClick() {
5917
- // Check for an existing open conversation to reuse
5918
5908
  const openConversation = this.messengerState.conversations.find(
5919
5909
  (c) => c.status === 'open'
5920
5910
  );
5921
5911
 
5922
5912
  if (openConversation) {
5923
- // Reuse existing open conversation
5924
5913
  this.messengerState.setActiveConversation(openConversation.id);
5925
5914
  this.messengerState.setView('chat');
5926
5915
  this._handleSelectConversation(openConversation.id);
5927
5916
  } else {
5928
- // No open conversation — start a new one
5929
5917
  this.messengerState.setActiveConversation(null);
5930
5918
  this.messengerState.setView('chat');
5931
5919
  }
5932
5920
  }
5933
5921
 
5934
- /**
5935
- * Handle identifying contact from pre-chat form
5936
- */
5937
5922
  async _handleIdentifyContact(contactData) {
5938
5923
  try {
5939
- // Call API to identify/update contact
5940
5924
  const response = await this.apiService.identifyContact({
5941
5925
  name: contactData.name,
5942
5926
  email: contactData.email,
@@ -5945,12 +5929,24 @@
5945
5929
  if (response.status) {
5946
5930
  console.log('[MessengerWidget] Contact identified:', contactData.email);
5947
5931
 
5948
- // Update local user context
5949
5932
  if (!this.messengerState.userContext) {
5950
5933
  this.messengerState.userContext = {};
5951
5934
  }
5952
5935
  this.messengerState.userContext.name = contactData.name;
5953
5936
  this.messengerState.userContext.email = contactData.email;
5937
+
5938
+ const pendingMessage = this.messengerState.pendingMessage;
5939
+ if (pendingMessage) {
5940
+ this.messengerState.pendingMessage = null;
5941
+
5942
+ await this.startNewConversation(
5943
+ pendingMessage.content,
5944
+ '',
5945
+ pendingMessage.attachments
5946
+ );
5947
+ } else {
5948
+ this.messengerState.setView('chat');
5949
+ }
5954
5950
  }
5955
5951
 
5956
5952
  return response;
@@ -5986,14 +5982,17 @@
5986
5982
  name: att.file.name,
5987
5983
  });
5988
5984
  } catch (err) {
5989
- console.error('[MessengerWidget] Skipping failed attachment upload:', att.file.name, err);
5985
+ console.error(
5986
+ '[MessengerWidget] Skipping failed attachment upload:',
5987
+ att.file.name,
5988
+ err
5989
+ );
5990
5990
  }
5991
5991
  }
5992
5992
  return uploaded;
5993
5993
  }
5994
5994
 
5995
5995
  async _handleSendMessage(conversationId, message, pendingAttachments) {
5996
- // Emit event for external listeners
5997
5996
  this.sdk.eventBus.emit('messenger:messageSent', {
5998
5997
  widget: this,
5999
5998
  conversationId,
@@ -6001,22 +6000,18 @@
6001
6000
  });
6002
6001
 
6003
6002
  try {
6004
- // Upload attachments to CDN first
6005
- const uploadedAttachments = await this._uploadPendingAttachments(pendingAttachments);
6003
+ const uploadedAttachments =
6004
+ await this._uploadPendingAttachments(pendingAttachments);
6006
6005
 
6007
- // Send message through API
6008
6006
  const response = await this.apiService.sendMessage(conversationId, {
6009
6007
  content: message.content,
6010
6008
  attachments: uploadedAttachments,
6011
6009
  });
6012
6010
 
6013
6011
  if (response.status && response.data) {
6014
- // Update the message ID with server-assigned ID
6015
- // Message is already added to state optimistically in ChatView
6016
6012
  console.log('[MessengerWidget] Message sent:', response.data.id);
6017
6013
  }
6018
6014
 
6019
- // In mock mode, simulate an agent response after a delay
6020
6015
  if (this.apiService?.mock) {
6021
6016
  setTimeout(() => {
6022
6017
  const mockResponse = {
@@ -6034,29 +6029,24 @@
6034
6029
  }
6035
6030
  } catch (error) {
6036
6031
  console.error('[MessengerWidget] Failed to send message:', error);
6037
- // Could add error handling UI here
6038
6032
  }
6039
6033
  }
6040
6034
 
6041
- /**
6042
- * Handle incoming WebSocket message
6043
- */
6044
6035
  _handleWebSocketMessage(data) {
6045
6036
  const { conversation_id, message } = data;
6046
6037
 
6047
- // Parse attachments from server message
6048
6038
  let attachments = [];
6049
6039
  if (message.attachments) {
6050
6040
  try {
6051
- attachments = typeof message.attachments === 'string'
6052
- ? JSON.parse(message.attachments)
6053
- : message.attachments;
6041
+ attachments =
6042
+ typeof message.attachments === 'string'
6043
+ ? JSON.parse(message.attachments)
6044
+ : message.attachments;
6054
6045
  } catch (e) {
6055
- // ignore parse errors
6046
+ // ignore
6056
6047
  }
6057
6048
  }
6058
6049
 
6059
- // Transform message to local format
6060
6050
  const localMessage = {
6061
6051
  id: message.id,
6062
6052
  content: message.content,
@@ -6069,10 +6059,8 @@
6069
6059
  },
6070
6060
  };
6071
6061
 
6072
- // Add message to state
6073
6062
  this.messengerState.addMessage(conversation_id, localMessage);
6074
6063
 
6075
- // Update unread count if panel is closed or viewing different conversation
6076
6064
  if (
6077
6065
  !this.messengerState.isOpen ||
6078
6066
  this.messengerState.activeConversationId !== conversation_id
@@ -6081,9 +6069,6 @@
6081
6069
  }
6082
6070
  }
6083
6071
 
6084
- /**
6085
- * Handle typing started event
6086
- */
6087
6072
  _handleTypingStarted(data) {
6088
6073
  if (data.is_agent) {
6089
6074
  this.messengerState._notify('typingStarted', {
@@ -6093,31 +6078,20 @@
6093
6078
  }
6094
6079
  }
6095
6080
 
6096
- /**
6097
- * Handle typing stopped event
6098
- */
6099
6081
  _handleTypingStopped(data) {
6100
6082
  this.messengerState._notify('typingStopped', {
6101
6083
  conversationId: data.conversation_id,
6102
6084
  });
6103
6085
  }
6104
6086
 
6105
- /**
6106
- * Handle conversation closed event
6107
- */
6108
6087
  _handleConversationClosed(data) {
6109
6088
  const conversationId =
6110
- data?.conversation_id ||
6111
- data?.id ||
6112
- data?.conversation?.id;
6089
+ data?.conversation_id || data?.id || data?.conversation?.id;
6113
6090
  if (!conversationId) return;
6114
6091
 
6115
6092
  this.messengerState.updateConversation(conversationId, { status: 'closed' });
6116
6093
  }
6117
6094
 
6118
- /**
6119
- * Update unread count from API
6120
- */
6121
6095
  async _updateUnreadCount() {
6122
6096
  try {
6123
6097
  const response = await this.apiService.getUnreadCount();
@@ -6132,9 +6106,6 @@
6132
6106
  }
6133
6107
  }
6134
6108
 
6135
- /**
6136
- * Initialize WebSocket connection
6137
- */
6138
6109
  _initWebSocket() {
6139
6110
  if (this.wsService) {
6140
6111
  this.wsService.disconnect();
@@ -6147,7 +6118,6 @@
6147
6118
  mock: this.apiService.mock,
6148
6119
  });
6149
6120
 
6150
- // Subscribe to WebSocket events
6151
6121
  this._wsUnsubscribers.push(
6152
6122
  this.wsService.on('message', this._handleWebSocketMessage)
6153
6123
  );
@@ -6163,7 +6133,6 @@
6163
6133
  this._wsUnsubscribers.push(
6164
6134
  this.wsService.on('connected', () => {
6165
6135
  console.log('[MessengerWidget] WebSocket connected');
6166
- // Re-subscribe to active conversation on reconnect
6167
6136
  if (this.messengerState.activeConversationId) {
6168
6137
  this.wsService.send('conversation:subscribe', {
6169
6138
  conversation_id: this.messengerState.activeConversationId,
@@ -6177,34 +6146,21 @@
6177
6146
  })
6178
6147
  );
6179
6148
 
6180
- // Connect
6181
6149
  this.wsService.connect();
6182
6150
  }
6183
6151
 
6184
- /**
6185
- * Open the messenger panel
6186
- */
6187
6152
  open() {
6188
6153
  this.messengerState.setOpen(true);
6189
6154
  }
6190
6155
 
6191
- /**
6192
- * Close the messenger panel
6193
- */
6194
6156
  close() {
6195
6157
  this.messengerState.setOpen(false);
6196
6158
  }
6197
6159
 
6198
- /**
6199
- * Toggle the messenger panel
6200
- */
6201
6160
  toggle() {
6202
6161
  this.messengerState.setOpen(!this.messengerState.isOpen);
6203
6162
  }
6204
6163
 
6205
- /**
6206
- * Navigate to a specific view
6207
- */
6208
6164
  navigateTo(view) {
6209
6165
  this.messengerState.setView(view);
6210
6166
  if (!this.messengerState.isOpen) {
@@ -6212,52 +6168,31 @@
6212
6168
  }
6213
6169
  }
6214
6170
 
6215
- /**
6216
- * Set conversations
6217
- */
6218
6171
  setConversations(conversations) {
6219
6172
  this.messengerState.setConversations(conversations);
6220
6173
  }
6221
6174
 
6222
- /**
6223
- * Add a message to a conversation
6224
- */
6225
6175
  addMessage(conversationId, message) {
6226
6176
  this.messengerState.addMessage(conversationId, message);
6227
6177
  }
6228
6178
 
6229
- /**
6230
- * Set help articles
6231
- */
6232
6179
  setHelpArticles(articles) {
6233
6180
  this.messengerState.setHelpArticles(articles);
6234
6181
  }
6235
6182
 
6236
- /**
6237
- * Set home changelog items
6238
- */
6239
6183
  setHomeChangelogItems(items) {
6240
6184
  this.messengerState.setHomeChangelogItems(items);
6241
6185
  }
6242
6186
 
6243
- /**
6244
- * Set changelog items
6245
- */
6246
6187
  setChangelogItems(items) {
6247
6188
  this.messengerState.setChangelogItems(items);
6248
6189
  }
6249
6190
 
6250
- /**
6251
- * Update unread count (for external updates)
6252
- */
6253
6191
  setUnreadCount(count) {
6254
6192
  this.messengerState.unreadCount = count;
6255
6193
  this.messengerState._notify('unreadCountChange', { count });
6256
6194
  }
6257
6195
 
6258
- /**
6259
- * Get current state
6260
- */
6261
6196
  getState() {
6262
6197
  return {
6263
6198
  isOpen: this.messengerState.isOpen,
@@ -6267,11 +6202,7 @@
6267
6202
  };
6268
6203
  }
6269
6204
 
6270
- /**
6271
- * Load initial data (mock or API)
6272
- */
6273
6205
  async loadInitialData() {
6274
- // Load conversations
6275
6206
  try {
6276
6207
  const conversations = await this._fetchConversations();
6277
6208
  this.messengerState.setConversations(conversations);
@@ -6279,7 +6210,6 @@
6279
6210
  console.error('[MessengerWidget] Failed to load conversations:', error);
6280
6211
  }
6281
6212
 
6282
- // Load help articles if enabled
6283
6213
  if (this.messengerOptions.enableHelp) {
6284
6214
  try {
6285
6215
  const articles = await this._fetchHelpArticles();
@@ -6289,7 +6219,6 @@
6289
6219
  }
6290
6220
  }
6291
6221
 
6292
- // Load changelog if enabled
6293
6222
  if (this.messengerOptions.enableChangelog) {
6294
6223
  try {
6295
6224
  const { homeItems, changelogItems } = await this._fetchChangelog();
@@ -6305,7 +6234,6 @@
6305
6234
  try {
6306
6235
  const response = await this.apiService.getConversations();
6307
6236
  if (response.status && response.data) {
6308
- // Transform API response to local format
6309
6237
  return response.data.map((conv) => ({
6310
6238
  id: conv.id,
6311
6239
  title:
@@ -6336,7 +6264,6 @@
6336
6264
  try {
6337
6265
  const response = await this.apiService.getHelpCollections();
6338
6266
  if (response.status && response.data) {
6339
- // Transform API response to local format
6340
6267
  return response.data.map((collection) => ({
6341
6268
  id: collection.id,
6342
6269
  title: collection.title || collection.name,
@@ -6354,9 +6281,6 @@
6354
6281
  }
6355
6282
  }
6356
6283
 
6357
- /**
6358
- * Fetch messages for a conversation
6359
- */
6360
6284
  async fetchMessages(conversationId) {
6361
6285
  try {
6362
6286
  const response = await this.apiService.getConversation(conversationId);
@@ -6365,11 +6289,12 @@
6365
6289
  let attachments;
6366
6290
  if (msg.attachments) {
6367
6291
  try {
6368
- attachments = typeof msg.attachments === 'string'
6369
- ? JSON.parse(msg.attachments)
6370
- : msg.attachments;
6292
+ attachments =
6293
+ typeof msg.attachments === 'string'
6294
+ ? JSON.parse(msg.attachments)
6295
+ : msg.attachments;
6371
6296
  } catch (e) {
6372
- // ignore parse errors
6297
+ // ignore
6373
6298
  }
6374
6299
  }
6375
6300
  return {
@@ -6377,16 +6302,18 @@
6377
6302
  content: msg.content,
6378
6303
  isOwn: msg.sender_type === 'customer',
6379
6304
  timestamp: msg.created_at,
6380
- attachments: attachments && attachments.length > 0 ? attachments : undefined,
6305
+ attachments:
6306
+ attachments && attachments.length > 0 ? attachments : undefined,
6381
6307
  sender: {
6382
- name: msg.sender_name || (msg.sender_type === 'customer' ? 'You' : 'Support'),
6308
+ name:
6309
+ msg.sender_name ||
6310
+ (msg.sender_type === 'customer' ? 'You' : 'Support'),
6383
6311
  avatarUrl: msg.sender_avatar || null,
6384
6312
  },
6385
6313
  };
6386
6314
  });
6387
6315
  this.messengerState.setMessages(conversationId, messages);
6388
6316
 
6389
- // Mark as read
6390
6317
  await this.apiService.markConversationAsRead(conversationId);
6391
6318
  this.messengerState.markAsRead(conversationId);
6392
6319
 
@@ -6399,19 +6326,18 @@
6399
6326
  }
6400
6327
  }
6401
6328
 
6402
- /**
6403
- * Start a new conversation
6404
- */
6405
6329
  async startNewConversation(message, subject = '', pendingAttachments = []) {
6406
6330
  try {
6407
- // Upload attachments to CDN first
6408
- const uploadedAttachments = await this._uploadPendingAttachments(pendingAttachments);
6331
+ const uploadedAttachments =
6332
+ await this._uploadPendingAttachments(pendingAttachments);
6409
6333
 
6410
6334
  console.log('[MessengerWidget] Starting conversation...', {
6411
6335
  message,
6412
6336
  attachmentCount: uploadedAttachments.length,
6413
6337
  hasSession: this.apiService.isSessionValid(),
6414
- sessionToken: this.apiService.sessionToken ? this.apiService.sessionToken.substring(0, 10) + '...' : null,
6338
+ sessionToken: this.apiService.sessionToken
6339
+ ? this.apiService.sessionToken.substring(0, 10) + '...'
6340
+ : null,
6415
6341
  baseURL: this.apiService.baseURL,
6416
6342
  mock: this.apiService.mock,
6417
6343
  });
@@ -6436,10 +6362,8 @@
6436
6362
  status: 'open',
6437
6363
  };
6438
6364
 
6439
- // Add to state
6440
6365
  this.messengerState.addConversation(newConversation);
6441
6366
 
6442
- // Set initial message in messages cache
6443
6367
  this.messengerState.setMessages(conv.id, [
6444
6368
  {
6445
6369
  id: 'msg_' + Date.now(),
@@ -6449,7 +6373,6 @@
6449
6373
  },
6450
6374
  ]);
6451
6375
 
6452
- // Navigate to chat
6453
6376
  this.messengerState.setActiveConversation(conv.id);
6454
6377
  this.messengerState.setView('chat');
6455
6378
 
@@ -6462,20 +6385,14 @@
6462
6385
  }
6463
6386
  }
6464
6387
 
6465
- /**
6466
- * Send typing indicator
6467
- */
6468
6388
  async sendTypingIndicator(conversationId, isTyping) {
6469
6389
  try {
6470
6390
  await this.apiService.sendTypingIndicator(conversationId, isTyping);
6471
6391
  } catch (error) {
6472
- // Silently fail - typing indicators are not critical
6392
+ // Silent fail
6473
6393
  }
6474
6394
  }
6475
6395
 
6476
- /**
6477
- * Check agent availability
6478
- */
6479
6396
  async checkAgentAvailability() {
6480
6397
  try {
6481
6398
  const response = await this.apiService.checkAgentsOnline();
@@ -6484,9 +6401,10 @@
6484
6401
  this.messengerState.onlineCount = response.data.online_count || 0;
6485
6402
  this.messengerState.responseTime = response.data.response_time || '';
6486
6403
 
6487
- // Update team avatars from online agents
6488
6404
  if (response.data.available_agents) {
6489
- this.messengerState.setTeamAvatarsFromAgents(response.data.available_agents);
6405
+ this.messengerState.setTeamAvatarsFromAgents(
6406
+ response.data.available_agents
6407
+ );
6490
6408
  }
6491
6409
 
6492
6410
  this.messengerState._notify('availabilityUpdate', response.data);
@@ -6578,11 +6496,9 @@
6578
6496
  };
6579
6497
  }
6580
6498
 
6581
- // Fetch changelogs from API
6582
6499
  const response = await this.apiService.getChangelogs({ limit: 20 });
6583
6500
  const changelogs = response.data || [];
6584
6501
 
6585
- // Map API response to expected format
6586
6502
  const mappedItems = changelogs.map((item) => ({
6587
6503
  id: item.id,
6588
6504
  title: item.title,
@@ -6600,19 +6516,30 @@
6600
6516
  };
6601
6517
  }
6602
6518
 
6603
- onMount() {
6604
- // Load initial data after mounting
6519
+ async onMount() {
6520
+ const userContext = this.messengerState.userContext;
6521
+ if (userContext?.email && userContext?.name) {
6522
+ try {
6523
+ await this.apiService.identifyContact({
6524
+ name: userContext.name,
6525
+ email: userContext.email,
6526
+ });
6527
+ console.log('[MessengerWidget] User identified successfully');
6528
+ } catch (error) {
6529
+ if (error?.code !== 'ALREADY_IDENTIFIED') {
6530
+ console.warn('[MessengerWidget] Identification failed:', error);
6531
+ }
6532
+ }
6533
+ }
6534
+
6605
6535
  this.loadInitialData();
6606
6536
 
6607
- // Initialize WebSocket for real-time updates
6608
6537
  if (this.apiService?.sessionToken) {
6609
6538
  this._initWebSocket();
6610
6539
  }
6611
6540
 
6612
- // Check agent availability
6613
6541
  this.checkAgentAvailability();
6614
6542
 
6615
- // Periodically check availability (every 60 seconds)
6616
6543
  this._availabilityInterval = setInterval(() => {
6617
6544
  this.checkAgentAvailability();
6618
6545
  }, 60000);
@@ -6623,16 +6550,13 @@
6623
6550
  this._stateUnsubscribe();
6624
6551
  }
6625
6552
 
6626
- // Clean up WebSocket
6627
6553
  if (this.wsService) {
6628
6554
  this.wsService.disconnect();
6629
6555
  }
6630
6556
 
6631
- // Clean up WebSocket event listeners
6632
6557
  this._wsUnsubscribers.forEach((unsub) => unsub());
6633
6558
  this._wsUnsubscribers = [];
6634
6559
 
6635
- // Clean up availability interval
6636
6560
  if (this._availabilityInterval) {
6637
6561
  clearInterval(this._availabilityInterval);
6638
6562
  }