@ihoomanai/chat-widget 3.0.20 → 3.0.21

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/src/widget.ts CHANGED
@@ -17,7 +17,7 @@ import type {
17
17
  WidgetView,
18
18
  } from './types';
19
19
 
20
- const VERSION = '3.0.13';
20
+ const VERSION = '3.0.21';
21
21
  const STORAGE_PREFIX = 'ihooman_chat_';
22
22
  const DEFAULT_SERVER_URL = 'https://api.ihooman.ai';
23
23
 
@@ -91,6 +91,7 @@ let state: WidgetState = {
91
91
 
92
92
  let currentView: WidgetView = 'chat';
93
93
  let isLiveAgentMode = false;
94
+ let isConversationClosed = false;
94
95
  let shownProactiveIds: string[] = [];
95
96
  let proactiveCooldowns: Record<string, number> = {};
96
97
  let proactiveCheckInterval: ReturnType<typeof setInterval> | null = null;
@@ -334,6 +335,8 @@ function generateStyles(): string {
334
335
  .ihooman-input-btn.send:hover { opacity: 0.9; }
335
336
  .ihooman-input-btn.send:disabled { opacity: 0.5; cursor: not-allowed; }
336
337
  .ihooman-input-btn svg { width: 16px; height: 16px; }
338
+ .ihooman-input:disabled { opacity: 0.6; cursor: not-allowed; }
339
+ .ihooman-input-btn.attach:disabled { opacity: 0.4; cursor: not-allowed; }
337
340
  .ihooman-file-input { display: none; }
338
341
  .ihooman-powered { text-align: center; padding: 8px; font-size: 11px; color: ${mutedColor}; background: ${bgColor}; }
339
342
  .ihooman-powered a { color: ${primaryColor}; text-decoration: none; }
@@ -1133,7 +1136,26 @@ function hideTyping(): void {
1133
1136
  if (typing) typing.remove();
1134
1137
  }
1135
1138
 
1139
+ function disableInput(): void {
1140
+ if (elements.input) {
1141
+ elements.input.disabled = true;
1142
+ elements.input.placeholder = 'Conversation closed — start a new chat to continue';
1143
+ }
1144
+ if (elements.sendBtn) elements.sendBtn.disabled = true;
1145
+ if (elements.attachBtn) elements.attachBtn.disabled = true;
1146
+ }
1147
+
1148
+ function enableInput(): void {
1149
+ if (elements.input) {
1150
+ elements.input.disabled = false;
1151
+ elements.input.placeholder = config.placeholder || 'Type a message...';
1152
+ }
1153
+ if (elements.sendBtn) elements.sendBtn.disabled = !elements.input?.value.trim();
1154
+ if (elements.attachBtn) elements.attachBtn.disabled = false;
1155
+ }
1156
+
1136
1157
  function handleSendClick(): void {
1158
+ if (isConversationClosed) return;
1137
1159
  const content = elements.input?.value.trim();
1138
1160
  if (!content) return;
1139
1161
 
@@ -1163,6 +1185,7 @@ function hidePresetQuestions(): void {
1163
1185
  }
1164
1186
 
1165
1187
  async function sendMessageToServer(content: string): Promise<void> {
1188
+ if (isConversationClosed) return;
1166
1189
  if (ws && ws.readyState === WebSocket.OPEN) {
1167
1190
  ws.send(JSON.stringify({ type: 'message', content }));
1168
1191
  return;
@@ -1506,10 +1529,12 @@ function connectWebSocket(chatEndpoint?: string): void {
1506
1529
  emit('escalation:accepted', { type: 'live_agent' });
1507
1530
  }
1508
1531
  if (metadata.closed_by_agent) {
1509
- // Agent has closed the conversation - return to AI mode
1532
+ // Agent has closed the conversation - disable input, require new conversation
1510
1533
  isLiveAgentMode = false;
1534
+ isConversationClosed = true;
1511
1535
  stopLiveAgentPolling();
1512
1536
  updateStatusBar('hidden');
1537
+ disableInput();
1513
1538
  emit('escalation:end', { type: 'live_agent' });
1514
1539
  }
1515
1540
 
@@ -1541,8 +1566,10 @@ function connectWebSocket(chatEndpoint?: string): void {
1541
1566
  emit('escalation:accepted', { type: 'live_agent' });
1542
1567
  } else if (data.status === 'disconnected') {
1543
1568
  isLiveAgentMode = false;
1569
+ isConversationClosed = true;
1544
1570
  stopLiveAgentPolling();
1545
1571
  updateStatusBar('hidden');
1572
+ disableInput();
1546
1573
  emit('escalation:end', { type: 'live_agent' });
1547
1574
  }
1548
1575
  } else if (data.type === 'error') {
@@ -1663,6 +1690,7 @@ function startNewConversation(): void {
1663
1690
  state.visitorId = null;
1664
1691
  state.messages = [];
1665
1692
  isLiveAgentMode = false;
1693
+ isConversationClosed = false;
1666
1694
 
1667
1695
  storage('session_id', null);
1668
1696
  state.visitorId = generateId('v_');
@@ -1672,6 +1700,7 @@ function startNewConversation(): void {
1672
1700
 
1673
1701
  updateStatusBar('hidden');
1674
1702
  stopLiveAgentPolling();
1703
+ enableInput();
1675
1704
 
1676
1705
  reconnectAttempts = 0;
1677
1706
 
@@ -1724,7 +1753,7 @@ function destroy(): void {
1724
1753
  }
1725
1754
 
1726
1755
  function sendMessage(content: string): void {
1727
- if (!content.trim()) return;
1756
+ if (!content.trim() || isConversationClosed) return;
1728
1757
  if (elements.input) elements.input.value = content;
1729
1758
  handleSendClick();
1730
1759
  }