(function() {
const AGENT_ID = "692da0151980498cdf0f59c3";
const API_URL = "https://glav-bot.ru/api/functions";
// Persist Visitor ID
let VISITOR_ID = localStorage.getItem('chat_visitor_id_' + AGENT_ID);
if (!VISITOR_ID) {
VISITOR_ID = 'visitor_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
localStorage.setItem('chat_visitor_id_' + AGENT_ID, VISITOR_ID);
}
const WIDGET_COLOR = "#0d0d0d";
const WELCOME_MESSAGE = "Привет! Как могу помочь?";
const AGENT_NAME = "Summator Support";
const SUGGESTIONS = [];
console.log('ChatBot Init:', { AGENT_ID, API_URL }); // Debug log
let isOpen = false;
let messages = [];
if (document.getElementById('chatbot-widget-root')) return;
const root = document.createElement('div');
root.id = 'chatbot-widget-root';
document.body.appendChild(root);
const style = document.createElement('style');
style.textContent = `
#chatbot-widget-root { font-family: system-ui, -apple-system, sans-serif; }
#chatbot-widget-root * { box-sizing: border-box; }
#chatbot-button { position: fixed; bottom: 20px; right: 20px; width: 60px; height: 60px;
border-radius: 50%; background: ${WIDGET_COLOR}; border: none; cursor: pointer;
box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 2147483646; display: flex; align-items: center;
justify-content: center; transition: transform 0.2s; }
#chatbot-button:hover { transform: scale(1.05); }
#chatbot-button svg { width: 28px; height: 28px; fill: white; }
#chatbot-window { position: fixed; bottom: 90px; right: 20px; width: 380px; height: 600px;
max-height: calc(100vh - 110px);
background: white; border-radius: 16px; box-shadow: 0 8px 32px rgba(0,0,0,0.15);
display: none; flex-direction: column; z-index: 2147483647;
opacity: 0; transform: translateY(20px); transition: opacity 0.3s, transform 0.3s; }
#chatbot-window.open { display: flex; opacity: 1; transform: translateY(0); }
#chatbot-header { background: ${WIDGET_COLOR}; color: white; padding: 16px;
border-radius: 16px 16px 0 0; font-weight: 600; display: flex; justify-content: space-between; align-items: center; }
#chatbot-close { background: none; border: none; color: white; cursor: pointer; opacity: 0.8; padding: 4px; }
#chatbot-close:hover { opacity: 1; }
#chatbot-messages { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.message { max-width: 85%; padding: 10px 14px; font-size: 14px; line-height: 1.5; }
.message.user { align-self: flex-end; background: #e5e7eb; color: #1f2937;
border-radius: 16px 16px 4px 16px; }
.message.assistant { align-self: flex-start; background: #f3f4f6; color: #1f2937;
border-radius: 16px 16px 16px 4px; }
.message.assistant strong { font-weight: 600; }
.message.assistant p { margin: 0; }
.message.typing { color: #6b7280; font-size: 20px; padding: 4px 14px; line-height: 10px; }
.message.typing .dot { animation: typing 1.4s infinite ease-in-out both; margin: 0 1px; }
.message.typing .dot:nth-child(1) { animation-delay: -0.32s; }
.message.typing .dot:nth-child(2) { animation-delay: -0.16s; }
@keyframes typing { 0%, 80%, 100% { opacity: 0; } 40% { opacity: 1; } }
#chatbot-input-area { border-top: 1px solid #e5e7eb; padding: 12px; display: flex; gap: 8px; background: white; border-radius: 0 0 16px 16px; }
#chatbot-input { flex: 1; border: 1px solid #e5e7eb; border-radius: 8px; padding: 10px;
outline: none; font-size: 14px; transition: border-color 0.2s; }
#chatbot-input:focus { border-color: ${WIDGET_COLOR}; }
#chatbot-send { background: ${WIDGET_COLOR}; color: white; border: none;
padding: 0 12px; border-radius: 8px; cursor: pointer; display: flex; align-items: center; justify-content: center; }
#chatbot-send:disabled { opacity: 0.5; cursor: not-allowed; }
#chatbot-suggestions { display: flex; flex-wrap: wrap; gap: 8px; padding: 8px 16px 16px 16px; min-height: 40px; }
.suggestion-btn { background: #f3f4f6; border: 1px solid #e5e7eb; color: #4b5563;
padding: 8px 14px; border-radius: 16px; font-size: 13px; cursor: pointer; transition: all 0.2s; white-space: nowrap; flex-shrink: 0; box-shadow: 0 1px 2px rgba(0,0,0,0.05); }
.suggestion-btn:hover { background: ${WIDGET_COLOR}; color: white; border-color: ${WIDGET_COLOR}; transform: translateY(-1px); }
@media (max-width: 480px) {
#chatbot-window { width: 100%; height: 100%; bottom: 0; right: 0; border-radius: 0; max-height: 100vh; }
#chatbot-header { border-radius: 0; }
#chatbot-button { bottom: 20px; right: 20px; }
}
`;
document.head.appendChild(style);
const button = document.createElement('button');
button.id = 'chatbot-button';
button.innerHTML = '';
button.onclick = toggleChat;
root.appendChild(button);
const chatWindow = document.createElement('div');
chatWindow.id = 'chatbot-window';
chatWindow.innerHTML = `
`;
root.appendChild(chatWindow);
document.getElementById('chatbot-close').onclick = toggleChat;
const input = document.getElementById('chatbot-input');
const sendBtn = document.getElementById('chatbot-send');
const messagesDiv = document.getElementById('chatbot-messages');
let lastMessageTimestamp = null;
let pollInterval = null;
let typingIndicator = null;
function showTyping() {
if (typingIndicator) return;
typingIndicator = document.createElement('div');
typingIndicator.className = 'message assistant typing';
typingIndicator.innerHTML = '...';
messagesDiv.appendChild(typingIndicator);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
function hideTyping() {
if (typingIndicator) {
typingIndicator.remove();
typingIndicator = null;
}
}
// Poll for new messages
async function pollMessages() {
if (!isOpen) return;
try {
const response = await fetch(API_URL + '/getWebsiteMessages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
agentId: AGENT_ID,
visitorId: VISITOR_ID,
afterTimestamp: lastMessageTimestamp
})
});
const data = await response.json();
// Handle Typing Indicator
if (data.operatorTyping) {
showTyping();
} else {
hideTyping();
}
if (data.messages && data.messages.length > 0) {
data.messages.forEach(msg => {
// Update timestamp to latest
if (!lastMessageTimestamp || new Date(msg.timestamp) > new Date(lastMessageTimestamp)) {
lastMessageTimestamp = msg.timestamp;
}
// Message Handling Logic
const msgContent = msg.content;
const msgRole = msg.role;
// Hide system messages from widget
if (msgRole === 'system') return;
// Determine display role
const displayRole = (msgRole === 'operator' || msgRole === 'assistant') ? 'assistant' : 'user';
// Check for duplicates in recent history
// We compare against raw content if possible, but we only have display content in DOM/memory.
// Note: We modify operator content with prefix.
const isOperator = msgRole === 'operator';
const contentToCheck = isOperator ? '👮 ' + msgContent : msgContent;
const isDuplicate = messages.slice(-10).some(m => m.content === contentToCheck && m.role === displayRole);
if (!isDuplicate) {
addMessage(displayRole, contentToCheck);
}
});
}
} catch (e) {
console.error('Poll error', e);
}
}
function toggleChat() {
isOpen = !isOpen;
chatWindow.classList.toggle('open', isOpen);
button.style.transform = isOpen ? 'scale(0)' : 'scale(1)';
if (isOpen) {
// Initial load / Welcome
if (messages.length === 0) {
pollMessages().then(() => {
const userMsgs = messages.filter(m => m.role === 'user');
// Show welcome message only if no messages at all
if (messages.length === 0) {
addMessage('assistant', WELCOME_MESSAGE);
}
// Always show suggestions (Persistent Menu)
renderSuggestions();
});
// Force render immediately too, don't wait for poll
renderSuggestions();
} else {
// If we opened chat and already had messages, check if we should show suggestions
renderSuggestions();
}
if (!pollInterval) pollInterval = setInterval(pollMessages, 3000);
setTimeout(() => input.focus(), 100);
} else {
clearInterval(pollInterval);
pollInterval = null;
}
}
function renderSuggestions(customSuggestions = null) {
const container = document.getElementById('chatbot-suggestions');
if (!container) return;
container.innerHTML = '';
const itemsToRender = customSuggestions || SUGGESTIONS;
console.log('Rendering suggestions:', itemsToRender); // Debug
if (itemsToRender && Array.isArray(itemsToRender) && itemsToRender.length > 0) {
itemsToRender.forEach(item => {
if (!item) return;
let text = '';
let url = null;
if (typeof item === 'string') {
text = item;
} else if (typeof item === 'object') {
text = item.text;
url = item.url;
}
if (!text) return;
const btn = document.createElement('button');
btn.className = 'suggestion-btn';
btn.textContent = text;
if (url) {
// Link button
btn.onclick = () => {
window.open(url, '_blank');
};
// Add visual indicator for link
btn.textContent += ' ↗';
} else {
// Action button
btn.onclick = () => {
input.value = text;
sendMessage();
// Do NOT clear suggestions - Persistent Menu
};
}
container.appendChild(btn);
});
}
}
function addMessage(role, content) {
messages.push({ role, content });
const msgDiv = document.createElement('div');
msgDiv.className = 'message ' + role;
if (role === 'assistant') {
let html = content
.replace(/\*\*(.+?)\*\*/g, '$1')
.replace(/\n/g, '
');
msgDiv.innerHTML = html;
} else {
msgDiv.textContent = content;
}
messagesDiv.appendChild(msgDiv);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
// Clear suggestions on user message (if not already)
// Removed clearing to keep menu persistent as requested
/*
if (role === 'user') {
const container = document.getElementById('chatbot-suggestions');
if (container) container.innerHTML = '';
}
*/
}
async function sendMessage() {
const message = input.value.trim();
if (!message) return;
const externalId = 'web_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
input.value = '';
input.disabled = true;
sendBtn.disabled = true;
addMessage('user', message);
showTyping();
try {
const response = await fetch(API_URL + '/sendWebsiteMessage', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ agentId: AGENT_ID, visitorId: VISITOR_ID, message, externalId })
});
if (!response.ok) {
hideTyping();
let errorDetails = response.status + ' ' + response.statusText;
try {
const errData = await response.json();
if (errData.error) errorDetails = errData.error;
} catch (e) {}
throw new Error(errorDetails);
}
const data = await response.json();
hideTyping();
if (data.response) {
addMessage('assistant', data.response);
}
// Update suggestions if provided by API (dynamic or fallback)
if (data.suggestions && Array.isArray(data.suggestions) && data.suggestions.length > 0) {
console.log('Received dynamic suggestions:', data.suggestions);
renderSuggestions(data.suggestions);
}
} catch (error) {
hideTyping();
console.error('Chat error:', error);
addMessage('assistant', 'Ошибка: ' + error.message + ' (' + API_URL + ')');
} finally {
input.disabled = false;
sendBtn.disabled = false;
input.focus();
}
}
sendBtn.onclick = sendMessage;
input.onkeypress = (e) => {
if (e.key === 'Enter') sendMessage();
};
})();