@ihoomanai/chat-widget 2.3.0 → 2.5.0
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/index.cjs.js +219 -8
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +219 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/dist/index.umd.js +219 -8
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/dist/index.umd.min.js.map +1 -1
- package/dist/widget.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/widget.ts +262 -8
package/src/widget.ts
CHANGED
|
@@ -72,6 +72,9 @@ const icons = {
|
|
|
72
72
|
bot: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="10" rx="2"></rect><circle cx="12" cy="5" r="2"></circle><path d="M12 7v4"></path></svg>`,
|
|
73
73
|
agent: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>`,
|
|
74
74
|
ticket: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><line x1="10" y1="9" x2="8" y2="9"></line></svg>`,
|
|
75
|
+
history: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>`,
|
|
76
|
+
back: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>`,
|
|
77
|
+
plus: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>`,
|
|
75
78
|
};
|
|
76
79
|
|
|
77
80
|
/**
|
|
@@ -90,7 +93,7 @@ let state: WidgetState = {
|
|
|
90
93
|
/**
|
|
91
94
|
* Current view state
|
|
92
95
|
*/
|
|
93
|
-
type WidgetView = 'chat' | 'ticket';
|
|
96
|
+
type WidgetView = 'chat' | 'ticket' | 'history';
|
|
94
97
|
let currentView: WidgetView = 'chat';
|
|
95
98
|
let isLiveAgentMode = false;
|
|
96
99
|
|
|
@@ -104,6 +107,9 @@ interface WidgetElements {
|
|
|
104
107
|
window?: HTMLElement;
|
|
105
108
|
chatView?: HTMLElement;
|
|
106
109
|
ticketView?: HTMLElement;
|
|
110
|
+
historyView?: HTMLElement;
|
|
111
|
+
historyList?: HTMLElement;
|
|
112
|
+
historyNewBtn?: HTMLButtonElement;
|
|
107
113
|
messages?: HTMLElement;
|
|
108
114
|
input?: HTMLTextAreaElement;
|
|
109
115
|
sendBtn?: HTMLButtonElement;
|
|
@@ -129,6 +135,7 @@ let ws: WebSocket | null = null;
|
|
|
129
135
|
let pollInterval: ReturnType<typeof setInterval> | null = null;
|
|
130
136
|
let reconnectAttempts = 0;
|
|
131
137
|
const maxReconnectAttempts = 5;
|
|
138
|
+
let intentionalDisconnect = false; // Flag to prevent reconnection on intentional close
|
|
132
139
|
|
|
133
140
|
|
|
134
141
|
// ============================================================================
|
|
@@ -257,9 +264,10 @@ function generateStyles(): string {
|
|
|
257
264
|
.ihooman-toggle:active { transform: scale(0.95); }
|
|
258
265
|
.ihooman-toggle::before { content: ''; position: absolute; inset: 0; background: linear-gradient(to bottom, rgba(255,255,255,0.2), transparent); border-radius: 50%; }
|
|
259
266
|
.ihooman-toggle svg { width: 26px; height: 26px; color: white; transition: transform 0.3s ease, opacity 0.2s ease; position: relative; z-index: 1; }
|
|
260
|
-
.ihooman-toggle
|
|
261
|
-
.ihooman-toggle
|
|
262
|
-
.ihooman-toggle
|
|
267
|
+
.ihooman-toggle .chat-icon { display: flex; align-items: center; justify-content: center; transition: transform 0.3s ease, opacity 0.2s ease; }
|
|
268
|
+
.ihooman-toggle .close-icon { position: absolute; display: flex; align-items: center; justify-content: center; transform: rotate(-90deg) scale(0); opacity: 0; transition: transform 0.3s ease, opacity 0.2s ease; }
|
|
269
|
+
.ihooman-toggle.open .chat-icon { transform: rotate(90deg) scale(0); opacity: 0; }
|
|
270
|
+
.ihooman-toggle.open .close-icon { transform: rotate(0) scale(1); opacity: 1; }
|
|
263
271
|
.ihooman-pulse { position: absolute; inset: 0; border-radius: 50%; background: ${primaryColor}; animation: ihooman-pulse 2s ease-out infinite; }
|
|
264
272
|
@keyframes ihooman-pulse { 0% { transform: scale(1); opacity: 0.5; } 100% { transform: scale(1.6); opacity: 0; } }
|
|
265
273
|
.ihooman-toggle.open .ihooman-pulse { display: none; }
|
|
@@ -344,6 +352,20 @@ function generateStyles(): string {
|
|
|
344
352
|
.ihooman-ticket-submit:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
|
|
345
353
|
.ihooman-ticket-back { padding: 10px; background: transparent; color: ${mutedColor}; border: 1px solid ${borderColor}; border-radius: 10px; font-size: 13px; cursor: pointer; transition: all 0.2s; }
|
|
346
354
|
.ihooman-ticket-back:hover { background: ${isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.03)'}; }
|
|
355
|
+
.ihooman-history-view { display: none; flex-direction: column; flex: 1; overflow: hidden; background: ${bgColor}; }
|
|
356
|
+
.ihooman-history-view.show { display: flex; }
|
|
357
|
+
.ihooman-history-header { padding: 12px 16px; border-bottom: 1px solid ${borderColor}; display: flex; justify-content: space-between; align-items: center; }
|
|
358
|
+
.ihooman-history-title { font-size: 14px; font-weight: 600; color: ${textColor}; margin: 0; }
|
|
359
|
+
.ihooman-history-new { display: inline-flex; align-items: center; gap: 4px; background: linear-gradient(135deg, ${gradientFrom}, ${gradientTo}); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 12px; font-weight: 500; cursor: pointer; transition: all 0.2s; }
|
|
360
|
+
.ihooman-history-new:hover { transform: translateY(-1px); box-shadow: 0 2px 8px rgba(0, 174, 255, 0.3); }
|
|
361
|
+
.ihooman-history-new svg { width: 14px; height: 14px; }
|
|
362
|
+
.ihooman-history-list { flex: 1; overflow-y: auto; padding: 8px; }
|
|
363
|
+
.ihooman-history-item { padding: 12px; border: 1px solid ${borderColor}; border-radius: 8px; margin-bottom: 6px; cursor: pointer; transition: all 0.2s; background: ${bgColor}; }
|
|
364
|
+
.ihooman-history-item:hover { background: ${isDark ? 'rgba(255,255,255,0.05)' : '#f8fafc'}; }
|
|
365
|
+
.ihooman-history-item.active { background: ${isDark ? 'rgba(0, 174, 255, 0.1)' : '#eff6ff'}; border-color: ${primaryColor}; }
|
|
366
|
+
.ihooman-history-preview { font-size: 13px; color: ${textColor}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
367
|
+
.ihooman-history-meta { font-size: 11px; color: ${mutedColor}; margin-top: 4px; display: flex; justify-content: space-between; }
|
|
368
|
+
.ihooman-history-empty { padding: 40px; text-align: center; color: ${mutedColor}; font-size: 14px; }
|
|
347
369
|
@media (max-width: 480px) { .ihooman-window { width: calc(100vw - 20px); height: calc(100vh - 100px); left: 10px; right: 10px; bottom: 80px; max-height: none; } .ihooman-toggle { ${positionRight ? 'right: 16px' : 'left: 16px'}; bottom: 16px; } }
|
|
348
370
|
`;
|
|
349
371
|
}
|
|
@@ -382,7 +404,8 @@ function createWidget(): void {
|
|
|
382
404
|
<div class="ihooman-header-status"><span class="ihooman-status-dot"></span><span class="ihooman-status-text">Online</span></div>
|
|
383
405
|
</div>
|
|
384
406
|
<div class="ihooman-header-actions">
|
|
385
|
-
<button class="ihooman-header-btn" data-action="
|
|
407
|
+
<button class="ihooman-header-btn" data-action="history" title="Chat history">${icons.history}</button>
|
|
408
|
+
<button class="ihooman-header-btn" data-action="refresh" title="New conversation">${icons.plus}</button>
|
|
386
409
|
<button class="ihooman-header-btn" data-action="minimize" title="Minimize">${icons.minimize}</button>
|
|
387
410
|
</div>
|
|
388
411
|
</div>
|
|
@@ -411,6 +434,15 @@ function createWidget(): void {
|
|
|
411
434
|
<button class="ihooman-ticket-back" id="ihooman-ticket-back">← Back to Chat</button>
|
|
412
435
|
</div>
|
|
413
436
|
|
|
437
|
+
<!-- History View -->
|
|
438
|
+
<div class="ihooman-history-view">
|
|
439
|
+
<div class="ihooman-history-header">
|
|
440
|
+
<span class="ihooman-history-title">Your Conversations</span>
|
|
441
|
+
<button class="ihooman-history-new">${icons.plus} New Chat</button>
|
|
442
|
+
</div>
|
|
443
|
+
<div class="ihooman-history-list"></div>
|
|
444
|
+
</div>
|
|
445
|
+
|
|
414
446
|
${config.poweredBy ? `<div class="ihooman-powered">Powered by <a href="https://ihooman.ai" target="_blank" rel="noopener">Ihooman AI</a></div>` : ''}
|
|
415
447
|
</div>
|
|
416
448
|
</div>
|
|
@@ -426,6 +458,9 @@ function createWidget(): void {
|
|
|
426
458
|
window: widget.querySelector('.ihooman-window') as HTMLElement,
|
|
427
459
|
chatView: widget.querySelector('.ihooman-chat-view') as HTMLElement,
|
|
428
460
|
ticketView: widget.querySelector('.ihooman-ticket-view') as HTMLElement,
|
|
461
|
+
historyView: widget.querySelector('.ihooman-history-view') as HTMLElement,
|
|
462
|
+
historyList: widget.querySelector('.ihooman-history-list') as HTMLElement,
|
|
463
|
+
historyNewBtn: widget.querySelector('.ihooman-history-new') as HTMLButtonElement,
|
|
429
464
|
messages: widget.querySelector('.ihooman-messages') as HTMLElement,
|
|
430
465
|
input: widget.querySelector('.ihooman-input') as HTMLTextAreaElement,
|
|
431
466
|
sendBtn: widget.querySelector('.ihooman-input-btn.send') as HTMLButtonElement,
|
|
@@ -478,6 +513,7 @@ function setupEventListeners(): void {
|
|
|
478
513
|
|
|
479
514
|
elements.widget?.querySelector('[data-action="refresh"]')?.addEventListener('click', startNewConversation);
|
|
480
515
|
elements.widget?.querySelector('[data-action="minimize"]')?.addEventListener('click', close);
|
|
516
|
+
elements.widget?.querySelector('[data-action="history"]')?.addEventListener('click', toggleHistoryView);
|
|
481
517
|
|
|
482
518
|
// Ticket form buttons
|
|
483
519
|
if (elements.ticketSubmitBtn) {
|
|
@@ -486,6 +522,14 @@ function setupEventListeners(): void {
|
|
|
486
522
|
if (elements.ticketBackBtn) {
|
|
487
523
|
elements.ticketBackBtn.addEventListener('click', () => showView('chat'));
|
|
488
524
|
}
|
|
525
|
+
|
|
526
|
+
// History view buttons
|
|
527
|
+
if (elements.historyNewBtn) {
|
|
528
|
+
elements.historyNewBtn.addEventListener('click', () => {
|
|
529
|
+
startNewConversation();
|
|
530
|
+
showView('chat');
|
|
531
|
+
});
|
|
532
|
+
}
|
|
489
533
|
}
|
|
490
534
|
|
|
491
535
|
|
|
@@ -585,9 +629,9 @@ function handleEscalationAction(action: 'live-agent' | 'create-ticket'): void {
|
|
|
585
629
|
}
|
|
586
630
|
|
|
587
631
|
/**
|
|
588
|
-
* Switch between chat and
|
|
632
|
+
* Switch between chat, ticket, and history views
|
|
589
633
|
*/
|
|
590
|
-
function showView(view: 'chat' | 'ticket'): void {
|
|
634
|
+
function showView(view: 'chat' | 'ticket' | 'history'): void {
|
|
591
635
|
currentView = view;
|
|
592
636
|
|
|
593
637
|
if (elements.chatView) {
|
|
@@ -596,6 +640,177 @@ function showView(view: 'chat' | 'ticket'): void {
|
|
|
596
640
|
if (elements.ticketView) {
|
|
597
641
|
elements.ticketView.classList.toggle('show', view === 'ticket');
|
|
598
642
|
}
|
|
643
|
+
if (elements.historyView) {
|
|
644
|
+
elements.historyView.classList.toggle('show', view === 'history');
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Load history when showing history view
|
|
648
|
+
if (view === 'history') {
|
|
649
|
+
loadConversationHistory();
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Toggle between chat and history views
|
|
655
|
+
*/
|
|
656
|
+
function toggleHistoryView(): void {
|
|
657
|
+
if (currentView === 'history') {
|
|
658
|
+
showView('chat');
|
|
659
|
+
} else {
|
|
660
|
+
showView('history');
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Format time ago string
|
|
666
|
+
*/
|
|
667
|
+
function timeAgo(date: Date | string): string {
|
|
668
|
+
const diff = Date.now() - new Date(date).getTime();
|
|
669
|
+
if (diff < 60000) return 'now';
|
|
670
|
+
if (diff < 3600000) return Math.floor(diff / 60000) + 'm';
|
|
671
|
+
if (diff < 86400000) return Math.floor(diff / 3600000) + 'h';
|
|
672
|
+
return Math.floor(diff / 86400000) + 'd';
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Conversation history item interface
|
|
677
|
+
*/
|
|
678
|
+
interface ConversationHistoryItem {
|
|
679
|
+
session_id: string;
|
|
680
|
+
preview: string;
|
|
681
|
+
message_count: number;
|
|
682
|
+
status: string;
|
|
683
|
+
updated_at: string;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Load conversation history from the server
|
|
688
|
+
*/
|
|
689
|
+
async function loadConversationHistory(): Promise<void> {
|
|
690
|
+
if (!elements.historyList || !state.visitorId) return;
|
|
691
|
+
|
|
692
|
+
elements.historyList.innerHTML = '<div class="ihooman-history-empty">Loading...</div>';
|
|
693
|
+
|
|
694
|
+
try {
|
|
695
|
+
const response = await fetch(
|
|
696
|
+
`${config.serverUrl}/api/widget/conversations?widget_id=${config.widgetId}&visitor_id=${state.visitorId}&limit=20`
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
if (!response.ok) {
|
|
700
|
+
throw new Error('Failed to load history');
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const conversations: ConversationHistoryItem[] = await response.json();
|
|
704
|
+
|
|
705
|
+
if (!conversations.length) {
|
|
706
|
+
elements.historyList.innerHTML = '<div class="ihooman-history-empty">No conversations yet</div>';
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
elements.historyList.innerHTML = conversations.map(conv => `
|
|
711
|
+
<div class="ihooman-history-item ${conv.session_id === state.sessionId ? 'active' : ''}" data-session-id="${conv.session_id}">
|
|
712
|
+
<div class="ihooman-history-preview">${escapeHtml(conv.preview || 'New conversation')}</div>
|
|
713
|
+
<div class="ihooman-history-meta">
|
|
714
|
+
<span>${conv.message_count} msgs</span>
|
|
715
|
+
<span>${conv.status === 'pending' ? '🟡 Pending' : conv.status === 'closed' ? '✓ Closed' : ''} ${timeAgo(conv.updated_at)}</span>
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
`).join('');
|
|
719
|
+
|
|
720
|
+
// Add click handlers to history items
|
|
721
|
+
elements.historyList.querySelectorAll('.ihooman-history-item').forEach(item => {
|
|
722
|
+
item.addEventListener('click', () => {
|
|
723
|
+
const sessionId = (item as HTMLElement).dataset.sessionId;
|
|
724
|
+
if (sessionId) {
|
|
725
|
+
switchToConversation(sessionId);
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
} catch (error) {
|
|
731
|
+
console.error('Error loading conversation history:', error);
|
|
732
|
+
elements.historyList.innerHTML = '<div class="ihooman-history-empty">Failed to load history</div>';
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Switch to a specific conversation
|
|
738
|
+
*/
|
|
739
|
+
async function switchToConversation(sessionId: string): Promise<void> {
|
|
740
|
+
state.sessionId = sessionId;
|
|
741
|
+
if (config.persistSession) {
|
|
742
|
+
storage('session_id', sessionId);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Clear current messages
|
|
746
|
+
if (elements.messages) {
|
|
747
|
+
elements.messages.innerHTML = '';
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Reset live agent mode
|
|
751
|
+
isLiveAgentMode = false;
|
|
752
|
+
stopLiveAgentPolling();
|
|
753
|
+
updateStatusBar('hidden');
|
|
754
|
+
|
|
755
|
+
// Reconnect WebSocket with new session
|
|
756
|
+
intentionalDisconnect = true;
|
|
757
|
+
if (ws) {
|
|
758
|
+
ws.close();
|
|
759
|
+
ws = null;
|
|
760
|
+
}
|
|
761
|
+
connectWebSocket();
|
|
762
|
+
|
|
763
|
+
// Switch to chat view
|
|
764
|
+
showView('chat');
|
|
765
|
+
|
|
766
|
+
// Load conversation messages
|
|
767
|
+
await loadConversationMessages(sessionId);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Load messages for a specific conversation
|
|
772
|
+
*/
|
|
773
|
+
async function loadConversationMessages(sessionId: string): Promise<void> {
|
|
774
|
+
try {
|
|
775
|
+
const response = await fetch(
|
|
776
|
+
`${config.serverUrl}/api/widget/transcript/${sessionId}?widget_id=${config.widgetId}`
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
if (!response.ok) {
|
|
780
|
+
throw new Error('Failed to load messages');
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const data = await response.json();
|
|
784
|
+
|
|
785
|
+
if (elements.messages) {
|
|
786
|
+
elements.messages.innerHTML = '';
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// Add messages to the chat
|
|
790
|
+
if (data.messages && data.messages.length > 0) {
|
|
791
|
+
data.messages.forEach((msg: { content: string; sender_type: string; extra_data?: Record<string, unknown> }) => {
|
|
792
|
+
const sender = msg.sender_type === 'user' ? 'user' : 'bot';
|
|
793
|
+
addMessage(msg.content, sender, msg.extra_data || {});
|
|
794
|
+
});
|
|
795
|
+
} else if (config.welcomeMessage) {
|
|
796
|
+
addMessage(config.welcomeMessage, 'bot');
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Check conversation status
|
|
800
|
+
if (data.status === 'pending') {
|
|
801
|
+
isLiveAgentMode = true;
|
|
802
|
+
startLiveAgentPolling();
|
|
803
|
+
updateStatusBar('waiting', '⏳ Waiting for agent...');
|
|
804
|
+
} else if (data.status === 'closed') {
|
|
805
|
+
updateStatusBar('hidden');
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
} catch (error) {
|
|
809
|
+
console.error('Error loading conversation messages:', error);
|
|
810
|
+
if (config.welcomeMessage) {
|
|
811
|
+
addMessage(config.welcomeMessage, 'bot');
|
|
812
|
+
}
|
|
813
|
+
}
|
|
599
814
|
}
|
|
600
815
|
|
|
601
816
|
/**
|
|
@@ -991,6 +1206,12 @@ function connectWebSocket(chatEndpoint?: string): void {
|
|
|
991
1206
|
updateStatus(false);
|
|
992
1207
|
emit('disconnected');
|
|
993
1208
|
|
|
1209
|
+
// Don't reconnect if this was an intentional disconnect (e.g., starting new conversation)
|
|
1210
|
+
if (intentionalDisconnect) {
|
|
1211
|
+
intentionalDisconnect = false;
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
994
1215
|
// Attempt reconnection with exponential backoff
|
|
995
1216
|
if (reconnectAttempts < maxReconnectAttempts) {
|
|
996
1217
|
reconnectAttempts++;
|
|
@@ -1181,17 +1402,48 @@ function toggle(): void {
|
|
|
1181
1402
|
* Start a new conversation
|
|
1182
1403
|
*/
|
|
1183
1404
|
function startNewConversation(): void {
|
|
1405
|
+
// Clear session and visitor to force a completely new conversation
|
|
1184
1406
|
state.sessionId = null;
|
|
1407
|
+
state.visitorId = null;
|
|
1185
1408
|
state.messages = [];
|
|
1409
|
+
isLiveAgentMode = false;
|
|
1410
|
+
|
|
1411
|
+
// Clear stored session
|
|
1186
1412
|
storage('session_id', null);
|
|
1413
|
+
// Generate new visitor ID
|
|
1414
|
+
state.visitorId = generateId('v_');
|
|
1415
|
+
storage('visitor_id', state.visitorId);
|
|
1187
1416
|
|
|
1417
|
+
// Clear UI
|
|
1188
1418
|
if (elements.messages) {
|
|
1189
1419
|
elements.messages.innerHTML = '';
|
|
1190
1420
|
}
|
|
1191
1421
|
|
|
1422
|
+
// Hide status bar
|
|
1423
|
+
updateStatusBar('hidden');
|
|
1424
|
+
|
|
1425
|
+
// Stop any live agent polling
|
|
1426
|
+
stopLiveAgentPolling();
|
|
1427
|
+
|
|
1428
|
+
// Reset reconnect attempts for fresh connection
|
|
1429
|
+
reconnectAttempts = 0;
|
|
1430
|
+
|
|
1431
|
+
// Close existing WebSocket with intentional flag to prevent auto-reconnect
|
|
1432
|
+
if (ws) {
|
|
1433
|
+
intentionalDisconnect = true;
|
|
1434
|
+
ws.close();
|
|
1435
|
+
ws = null;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
// Connect with new visitor ID
|
|
1439
|
+
connectWebSocket();
|
|
1440
|
+
|
|
1441
|
+
// Show welcome message
|
|
1192
1442
|
if (config.welcomeMessage) {
|
|
1193
1443
|
addMessage(config.welcomeMessage, 'bot');
|
|
1194
1444
|
}
|
|
1445
|
+
|
|
1446
|
+
emit('newConversation');
|
|
1195
1447
|
}
|
|
1196
1448
|
|
|
1197
1449
|
/**
|
|
@@ -1204,7 +1456,8 @@ function destroy(): void {
|
|
|
1204
1456
|
// Stop live agent polling
|
|
1205
1457
|
stopLiveAgentPolling();
|
|
1206
1458
|
|
|
1207
|
-
// Close WebSocket
|
|
1459
|
+
// Close WebSocket (intentionally, don't reconnect)
|
|
1460
|
+
intentionalDisconnect = true;
|
|
1208
1461
|
if (ws) {
|
|
1209
1462
|
ws.close();
|
|
1210
1463
|
ws = null;
|
|
@@ -1237,6 +1490,7 @@ function destroy(): void {
|
|
|
1237
1490
|
};
|
|
1238
1491
|
elements = {};
|
|
1239
1492
|
reconnectAttempts = 0;
|
|
1493
|
+
intentionalDisconnect = false;
|
|
1240
1494
|
}
|
|
1241
1495
|
|
|
1242
1496
|
/**
|