@product7/feedback-sdk 1.3.1 → 1.3.3

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,50 +5844,74 @@
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
- async _handleStartConversation(messageContent, pendingAttachments) {
5877
- try {
5878
- // Check for existing open conversation first
5879
- const openConversation = this.messengerState.conversations.find(
5880
- (c) => c.status === 'open'
5881
- );
5860
+ async _handleStartConversation(messageContent, pendingAttachments) {
5861
+ try {
5862
+ const userContext = this.messengerState.userContext;
5863
+ const isAuthenticated = userContext?.email && userContext?.name;
5882
5864
 
5883
- if (openConversation) {
5884
- // Route message to existing open conversation
5885
- this.messengerState.setActiveConversation(openConversation.id);
5886
- await this._handleSendMessage(
5887
- openConversation.id,
5888
- { content: messageContent },
5889
- pendingAttachments
5890
- );
5891
- return openConversation;
5865
+ // If user is authenticated, silently identify them first
5866
+ if (isAuthenticated) {
5867
+ try {
5868
+ await this.apiService.identifyContact({
5869
+ name: userContext.name,
5870
+ email: userContext.email,
5871
+ });
5872
+ console.log('[MessengerWidget] User auto-identified for conversation');
5873
+ } catch (error) {
5874
+ // If identification fails with a non-critical error, continue anyway
5875
+ if (error?.code !== 'ALREADY_IDENTIFIED') {
5876
+ console.warn('[MessengerWidget] Auto-identification failed:', error);
5877
+ }
5892
5878
  }
5893
-
5894
- return await this.startNewConversation(messageContent, '', pendingAttachments);
5895
- } catch (error) {
5896
- console.error('[MessengerWidget] Failed to start conversation:', error);
5879
+ } else {
5880
+ // Unauthenticated user - show pre-chat form
5881
+ this.messengerState.pendingMessage = {
5882
+ content: messageContent,
5883
+ attachments: pendingAttachments,
5884
+ };
5885
+ this.messengerState.setView('prechat');
5897
5886
  return null;
5898
5887
  }
5888
+
5889
+ // Check for existing open conversation
5890
+ const openConversation = this.messengerState.conversations.find(
5891
+ (c) => c.status === 'open'
5892
+ );
5893
+
5894
+ if (openConversation) {
5895
+ this.messengerState.setActiveConversation(openConversation.id);
5896
+ await this._handleSendMessage(
5897
+ openConversation.id,
5898
+ { content: messageContent },
5899
+ pendingAttachments
5900
+ );
5901
+ return openConversation;
5902
+ }
5903
+
5904
+ return await this.startNewConversation(
5905
+ messageContent,
5906
+ '',
5907
+ pendingAttachments
5908
+ );
5909
+ } catch (error) {
5910
+ console.error('[MessengerWidget] Failed to start conversation:', error);
5911
+ return null;
5899
5912
  }
5913
+ }
5900
5914
 
5901
- /**
5902
- * Handle selecting a conversation from the list
5903
- */
5904
5915
  async _handleSelectConversation(conversationId) {
5905
5916
  try {
5906
5917
  await this.fetchMessages(conversationId);
@@ -5909,34 +5920,23 @@
5909
5920
  }
5910
5921
  }
5911
5922
 
5912
- /**
5913
- * Handle clicking "new conversation" button
5914
- * Reuses the most recent open conversation if one exists
5915
- */
5916
5923
  _handleNewConversationClick() {
5917
- // Check for an existing open conversation to reuse
5918
5924
  const openConversation = this.messengerState.conversations.find(
5919
5925
  (c) => c.status === 'open'
5920
5926
  );
5921
5927
 
5922
5928
  if (openConversation) {
5923
- // Reuse existing open conversation
5924
5929
  this.messengerState.setActiveConversation(openConversation.id);
5925
5930
  this.messengerState.setView('chat');
5926
5931
  this._handleSelectConversation(openConversation.id);
5927
5932
  } else {
5928
- // No open conversation — start a new one
5929
5933
  this.messengerState.setActiveConversation(null);
5930
5934
  this.messengerState.setView('chat');
5931
5935
  }
5932
5936
  }
5933
5937
 
5934
- /**
5935
- * Handle identifying contact from pre-chat form
5936
- */
5937
5938
  async _handleIdentifyContact(contactData) {
5938
5939
  try {
5939
- // Call API to identify/update contact
5940
5940
  const response = await this.apiService.identifyContact({
5941
5941
  name: contactData.name,
5942
5942
  email: contactData.email,
@@ -5945,12 +5945,24 @@
5945
5945
  if (response.status) {
5946
5946
  console.log('[MessengerWidget] Contact identified:', contactData.email);
5947
5947
 
5948
- // Update local user context
5949
5948
  if (!this.messengerState.userContext) {
5950
5949
  this.messengerState.userContext = {};
5951
5950
  }
5952
5951
  this.messengerState.userContext.name = contactData.name;
5953
5952
  this.messengerState.userContext.email = contactData.email;
5953
+
5954
+ const pendingMessage = this.messengerState.pendingMessage;
5955
+ if (pendingMessage) {
5956
+ this.messengerState.pendingMessage = null;
5957
+
5958
+ await this.startNewConversation(
5959
+ pendingMessage.content,
5960
+ '',
5961
+ pendingMessage.attachments
5962
+ );
5963
+ } else {
5964
+ this.messengerState.setView('chat');
5965
+ }
5954
5966
  }
5955
5967
 
5956
5968
  return response;
@@ -5986,14 +5998,17 @@
5986
5998
  name: att.file.name,
5987
5999
  });
5988
6000
  } catch (err) {
5989
- console.error('[MessengerWidget] Skipping failed attachment upload:', att.file.name, err);
6001
+ console.error(
6002
+ '[MessengerWidget] Skipping failed attachment upload:',
6003
+ att.file.name,
6004
+ err
6005
+ );
5990
6006
  }
5991
6007
  }
5992
6008
  return uploaded;
5993
6009
  }
5994
6010
 
5995
6011
  async _handleSendMessage(conversationId, message, pendingAttachments) {
5996
- // Emit event for external listeners
5997
6012
  this.sdk.eventBus.emit('messenger:messageSent', {
5998
6013
  widget: this,
5999
6014
  conversationId,
@@ -6001,22 +6016,18 @@
6001
6016
  });
6002
6017
 
6003
6018
  try {
6004
- // Upload attachments to CDN first
6005
- const uploadedAttachments = await this._uploadPendingAttachments(pendingAttachments);
6019
+ const uploadedAttachments =
6020
+ await this._uploadPendingAttachments(pendingAttachments);
6006
6021
 
6007
- // Send message through API
6008
6022
  const response = await this.apiService.sendMessage(conversationId, {
6009
6023
  content: message.content,
6010
6024
  attachments: uploadedAttachments,
6011
6025
  });
6012
6026
 
6013
6027
  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
6028
  console.log('[MessengerWidget] Message sent:', response.data.id);
6017
6029
  }
6018
6030
 
6019
- // In mock mode, simulate an agent response after a delay
6020
6031
  if (this.apiService?.mock) {
6021
6032
  setTimeout(() => {
6022
6033
  const mockResponse = {
@@ -6034,29 +6045,24 @@
6034
6045
  }
6035
6046
  } catch (error) {
6036
6047
  console.error('[MessengerWidget] Failed to send message:', error);
6037
- // Could add error handling UI here
6038
6048
  }
6039
6049
  }
6040
6050
 
6041
- /**
6042
- * Handle incoming WebSocket message
6043
- */
6044
6051
  _handleWebSocketMessage(data) {
6045
6052
  const { conversation_id, message } = data;
6046
6053
 
6047
- // Parse attachments from server message
6048
6054
  let attachments = [];
6049
6055
  if (message.attachments) {
6050
6056
  try {
6051
- attachments = typeof message.attachments === 'string'
6052
- ? JSON.parse(message.attachments)
6053
- : message.attachments;
6057
+ attachments =
6058
+ typeof message.attachments === 'string'
6059
+ ? JSON.parse(message.attachments)
6060
+ : message.attachments;
6054
6061
  } catch (e) {
6055
- // ignore parse errors
6062
+ // ignore
6056
6063
  }
6057
6064
  }
6058
6065
 
6059
- // Transform message to local format
6060
6066
  const localMessage = {
6061
6067
  id: message.id,
6062
6068
  content: message.content,
@@ -6069,10 +6075,8 @@
6069
6075
  },
6070
6076
  };
6071
6077
 
6072
- // Add message to state
6073
6078
  this.messengerState.addMessage(conversation_id, localMessage);
6074
6079
 
6075
- // Update unread count if panel is closed or viewing different conversation
6076
6080
  if (
6077
6081
  !this.messengerState.isOpen ||
6078
6082
  this.messengerState.activeConversationId !== conversation_id
@@ -6081,9 +6085,6 @@
6081
6085
  }
6082
6086
  }
6083
6087
 
6084
- /**
6085
- * Handle typing started event
6086
- */
6087
6088
  _handleTypingStarted(data) {
6088
6089
  if (data.is_agent) {
6089
6090
  this.messengerState._notify('typingStarted', {
@@ -6093,31 +6094,20 @@
6093
6094
  }
6094
6095
  }
6095
6096
 
6096
- /**
6097
- * Handle typing stopped event
6098
- */
6099
6097
  _handleTypingStopped(data) {
6100
6098
  this.messengerState._notify('typingStopped', {
6101
6099
  conversationId: data.conversation_id,
6102
6100
  });
6103
6101
  }
6104
6102
 
6105
- /**
6106
- * Handle conversation closed event
6107
- */
6108
6103
  _handleConversationClosed(data) {
6109
6104
  const conversationId =
6110
- data?.conversation_id ||
6111
- data?.id ||
6112
- data?.conversation?.id;
6105
+ data?.conversation_id || data?.id || data?.conversation?.id;
6113
6106
  if (!conversationId) return;
6114
6107
 
6115
6108
  this.messengerState.updateConversation(conversationId, { status: 'closed' });
6116
6109
  }
6117
6110
 
6118
- /**
6119
- * Update unread count from API
6120
- */
6121
6111
  async _updateUnreadCount() {
6122
6112
  try {
6123
6113
  const response = await this.apiService.getUnreadCount();
@@ -6132,9 +6122,6 @@
6132
6122
  }
6133
6123
  }
6134
6124
 
6135
- /**
6136
- * Initialize WebSocket connection
6137
- */
6138
6125
  _initWebSocket() {
6139
6126
  if (this.wsService) {
6140
6127
  this.wsService.disconnect();
@@ -6147,7 +6134,6 @@
6147
6134
  mock: this.apiService.mock,
6148
6135
  });
6149
6136
 
6150
- // Subscribe to WebSocket events
6151
6137
  this._wsUnsubscribers.push(
6152
6138
  this.wsService.on('message', this._handleWebSocketMessage)
6153
6139
  );
@@ -6163,7 +6149,6 @@
6163
6149
  this._wsUnsubscribers.push(
6164
6150
  this.wsService.on('connected', () => {
6165
6151
  console.log('[MessengerWidget] WebSocket connected');
6166
- // Re-subscribe to active conversation on reconnect
6167
6152
  if (this.messengerState.activeConversationId) {
6168
6153
  this.wsService.send('conversation:subscribe', {
6169
6154
  conversation_id: this.messengerState.activeConversationId,
@@ -6177,34 +6162,21 @@
6177
6162
  })
6178
6163
  );
6179
6164
 
6180
- // Connect
6181
6165
  this.wsService.connect();
6182
6166
  }
6183
6167
 
6184
- /**
6185
- * Open the messenger panel
6186
- */
6187
6168
  open() {
6188
6169
  this.messengerState.setOpen(true);
6189
6170
  }
6190
6171
 
6191
- /**
6192
- * Close the messenger panel
6193
- */
6194
6172
  close() {
6195
6173
  this.messengerState.setOpen(false);
6196
6174
  }
6197
6175
 
6198
- /**
6199
- * Toggle the messenger panel
6200
- */
6201
6176
  toggle() {
6202
6177
  this.messengerState.setOpen(!this.messengerState.isOpen);
6203
6178
  }
6204
6179
 
6205
- /**
6206
- * Navigate to a specific view
6207
- */
6208
6180
  navigateTo(view) {
6209
6181
  this.messengerState.setView(view);
6210
6182
  if (!this.messengerState.isOpen) {
@@ -6212,52 +6184,31 @@
6212
6184
  }
6213
6185
  }
6214
6186
 
6215
- /**
6216
- * Set conversations
6217
- */
6218
6187
  setConversations(conversations) {
6219
6188
  this.messengerState.setConversations(conversations);
6220
6189
  }
6221
6190
 
6222
- /**
6223
- * Add a message to a conversation
6224
- */
6225
6191
  addMessage(conversationId, message) {
6226
6192
  this.messengerState.addMessage(conversationId, message);
6227
6193
  }
6228
6194
 
6229
- /**
6230
- * Set help articles
6231
- */
6232
6195
  setHelpArticles(articles) {
6233
6196
  this.messengerState.setHelpArticles(articles);
6234
6197
  }
6235
6198
 
6236
- /**
6237
- * Set home changelog items
6238
- */
6239
6199
  setHomeChangelogItems(items) {
6240
6200
  this.messengerState.setHomeChangelogItems(items);
6241
6201
  }
6242
6202
 
6243
- /**
6244
- * Set changelog items
6245
- */
6246
6203
  setChangelogItems(items) {
6247
6204
  this.messengerState.setChangelogItems(items);
6248
6205
  }
6249
6206
 
6250
- /**
6251
- * Update unread count (for external updates)
6252
- */
6253
6207
  setUnreadCount(count) {
6254
6208
  this.messengerState.unreadCount = count;
6255
6209
  this.messengerState._notify('unreadCountChange', { count });
6256
6210
  }
6257
6211
 
6258
- /**
6259
- * Get current state
6260
- */
6261
6212
  getState() {
6262
6213
  return {
6263
6214
  isOpen: this.messengerState.isOpen,
@@ -6267,11 +6218,7 @@
6267
6218
  };
6268
6219
  }
6269
6220
 
6270
- /**
6271
- * Load initial data (mock or API)
6272
- */
6273
6221
  async loadInitialData() {
6274
- // Load conversations
6275
6222
  try {
6276
6223
  const conversations = await this._fetchConversations();
6277
6224
  this.messengerState.setConversations(conversations);
@@ -6279,7 +6226,6 @@
6279
6226
  console.error('[MessengerWidget] Failed to load conversations:', error);
6280
6227
  }
6281
6228
 
6282
- // Load help articles if enabled
6283
6229
  if (this.messengerOptions.enableHelp) {
6284
6230
  try {
6285
6231
  const articles = await this._fetchHelpArticles();
@@ -6289,7 +6235,6 @@
6289
6235
  }
6290
6236
  }
6291
6237
 
6292
- // Load changelog if enabled
6293
6238
  if (this.messengerOptions.enableChangelog) {
6294
6239
  try {
6295
6240
  const { homeItems, changelogItems } = await this._fetchChangelog();
@@ -6305,7 +6250,6 @@
6305
6250
  try {
6306
6251
  const response = await this.apiService.getConversations();
6307
6252
  if (response.status && response.data) {
6308
- // Transform API response to local format
6309
6253
  return response.data.map((conv) => ({
6310
6254
  id: conv.id,
6311
6255
  title:
@@ -6336,7 +6280,6 @@
6336
6280
  try {
6337
6281
  const response = await this.apiService.getHelpCollections();
6338
6282
  if (response.status && response.data) {
6339
- // Transform API response to local format
6340
6283
  return response.data.map((collection) => ({
6341
6284
  id: collection.id,
6342
6285
  title: collection.title || collection.name,
@@ -6354,9 +6297,6 @@
6354
6297
  }
6355
6298
  }
6356
6299
 
6357
- /**
6358
- * Fetch messages for a conversation
6359
- */
6360
6300
  async fetchMessages(conversationId) {
6361
6301
  try {
6362
6302
  const response = await this.apiService.getConversation(conversationId);
@@ -6365,11 +6305,12 @@
6365
6305
  let attachments;
6366
6306
  if (msg.attachments) {
6367
6307
  try {
6368
- attachments = typeof msg.attachments === 'string'
6369
- ? JSON.parse(msg.attachments)
6370
- : msg.attachments;
6308
+ attachments =
6309
+ typeof msg.attachments === 'string'
6310
+ ? JSON.parse(msg.attachments)
6311
+ : msg.attachments;
6371
6312
  } catch (e) {
6372
- // ignore parse errors
6313
+ // ignore
6373
6314
  }
6374
6315
  }
6375
6316
  return {
@@ -6377,16 +6318,18 @@
6377
6318
  content: msg.content,
6378
6319
  isOwn: msg.sender_type === 'customer',
6379
6320
  timestamp: msg.created_at,
6380
- attachments: attachments && attachments.length > 0 ? attachments : undefined,
6321
+ attachments:
6322
+ attachments && attachments.length > 0 ? attachments : undefined,
6381
6323
  sender: {
6382
- name: msg.sender_name || (msg.sender_type === 'customer' ? 'You' : 'Support'),
6324
+ name:
6325
+ msg.sender_name ||
6326
+ (msg.sender_type === 'customer' ? 'You' : 'Support'),
6383
6327
  avatarUrl: msg.sender_avatar || null,
6384
6328
  },
6385
6329
  };
6386
6330
  });
6387
6331
  this.messengerState.setMessages(conversationId, messages);
6388
6332
 
6389
- // Mark as read
6390
6333
  await this.apiService.markConversationAsRead(conversationId);
6391
6334
  this.messengerState.markAsRead(conversationId);
6392
6335
 
@@ -6399,19 +6342,18 @@
6399
6342
  }
6400
6343
  }
6401
6344
 
6402
- /**
6403
- * Start a new conversation
6404
- */
6405
6345
  async startNewConversation(message, subject = '', pendingAttachments = []) {
6406
6346
  try {
6407
- // Upload attachments to CDN first
6408
- const uploadedAttachments = await this._uploadPendingAttachments(pendingAttachments);
6347
+ const uploadedAttachments =
6348
+ await this._uploadPendingAttachments(pendingAttachments);
6409
6349
 
6410
6350
  console.log('[MessengerWidget] Starting conversation...', {
6411
6351
  message,
6412
6352
  attachmentCount: uploadedAttachments.length,
6413
6353
  hasSession: this.apiService.isSessionValid(),
6414
- sessionToken: this.apiService.sessionToken ? this.apiService.sessionToken.substring(0, 10) + '...' : null,
6354
+ sessionToken: this.apiService.sessionToken
6355
+ ? this.apiService.sessionToken.substring(0, 10) + '...'
6356
+ : null,
6415
6357
  baseURL: this.apiService.baseURL,
6416
6358
  mock: this.apiService.mock,
6417
6359
  });
@@ -6436,10 +6378,8 @@
6436
6378
  status: 'open',
6437
6379
  };
6438
6380
 
6439
- // Add to state
6440
6381
  this.messengerState.addConversation(newConversation);
6441
6382
 
6442
- // Set initial message in messages cache
6443
6383
  this.messengerState.setMessages(conv.id, [
6444
6384
  {
6445
6385
  id: 'msg_' + Date.now(),
@@ -6449,7 +6389,6 @@
6449
6389
  },
6450
6390
  ]);
6451
6391
 
6452
- // Navigate to chat
6453
6392
  this.messengerState.setActiveConversation(conv.id);
6454
6393
  this.messengerState.setView('chat');
6455
6394
 
@@ -6462,20 +6401,14 @@
6462
6401
  }
6463
6402
  }
6464
6403
 
6465
- /**
6466
- * Send typing indicator
6467
- */
6468
6404
  async sendTypingIndicator(conversationId, isTyping) {
6469
6405
  try {
6470
6406
  await this.apiService.sendTypingIndicator(conversationId, isTyping);
6471
6407
  } catch (error) {
6472
- // Silently fail - typing indicators are not critical
6408
+ // Silent fail
6473
6409
  }
6474
6410
  }
6475
6411
 
6476
- /**
6477
- * Check agent availability
6478
- */
6479
6412
  async checkAgentAvailability() {
6480
6413
  try {
6481
6414
  const response = await this.apiService.checkAgentsOnline();
@@ -6484,9 +6417,10 @@
6484
6417
  this.messengerState.onlineCount = response.data.online_count || 0;
6485
6418
  this.messengerState.responseTime = response.data.response_time || '';
6486
6419
 
6487
- // Update team avatars from online agents
6488
6420
  if (response.data.available_agents) {
6489
- this.messengerState.setTeamAvatarsFromAgents(response.data.available_agents);
6421
+ this.messengerState.setTeamAvatarsFromAgents(
6422
+ response.data.available_agents
6423
+ );
6490
6424
  }
6491
6425
 
6492
6426
  this.messengerState._notify('availabilityUpdate', response.data);
@@ -6578,11 +6512,9 @@
6578
6512
  };
6579
6513
  }
6580
6514
 
6581
- // Fetch changelogs from API
6582
6515
  const response = await this.apiService.getChangelogs({ limit: 20 });
6583
6516
  const changelogs = response.data || [];
6584
6517
 
6585
- // Map API response to expected format
6586
6518
  const mappedItems = changelogs.map((item) => ({
6587
6519
  id: item.id,
6588
6520
  title: item.title,
@@ -6600,39 +6532,32 @@
6600
6532
  };
6601
6533
  }
6602
6534
 
6603
- onMount() {
6604
- // Load initial data after mounting
6605
- this.loadInitialData();
6535
+ async onMount() {
6536
+ this.loadInitialData();
6606
6537
 
6607
- // Initialize WebSocket for real-time updates
6608
- if (this.apiService?.sessionToken) {
6609
- this._initWebSocket();
6610
- }
6538
+ if (this.apiService?.sessionToken) {
6539
+ this._initWebSocket();
6540
+ }
6611
6541
 
6612
- // Check agent availability
6613
- this.checkAgentAvailability();
6542
+ this.checkAgentAvailability();
6614
6543
 
6615
- // Periodically check availability (every 60 seconds)
6616
- this._availabilityInterval = setInterval(() => {
6617
- this.checkAgentAvailability();
6618
- }, 60000);
6619
- }
6544
+ this._availabilityInterval = setInterval(() => {
6545
+ this.checkAgentAvailability();
6546
+ }, 60000);
6547
+ }
6620
6548
 
6621
6549
  onDestroy() {
6622
6550
  if (this._stateUnsubscribe) {
6623
6551
  this._stateUnsubscribe();
6624
6552
  }
6625
6553
 
6626
- // Clean up WebSocket
6627
6554
  if (this.wsService) {
6628
6555
  this.wsService.disconnect();
6629
6556
  }
6630
6557
 
6631
- // Clean up WebSocket event listeners
6632
6558
  this._wsUnsubscribers.forEach((unsub) => unsub());
6633
6559
  this._wsUnsubscribers = [];
6634
6560
 
6635
- // Clean up availability interval
6636
6561
  if (this._availabilityInterval) {
6637
6562
  clearInterval(this._availabilityInterval);
6638
6563
  }