// LeadBot Widget v8.4 - Updated: 2025-11-24T14:35:01.312Z (function() { 'use strict'; console.log('LeadBot: Widget initializing v8.4'); const scriptTag = document.currentScript || document.querySelector('script[src*="chatbotWidget"]'); const chatbotId = scriptTag ? scriptTag.getAttribute('data-chatbot-id') : null; if (!chatbotId) { console.error('LeadBot: data-chatbot-id attribute is required on the script tag'); console.error('Example: '); return; } console.log('LeadBot: Using chatbot ID:', chatbotId); const apiUrl = scriptTag.src.split('?')[0]; const configUrl = apiUrl + '?config=' + chatbotId; console.log('LeadBot: Fetching config from:', configUrl); fetch(configUrl) .then(response => { console.log('LeadBot: Response status:', response.status); if (!response.ok) { return response.json().then(err => { console.error('LeadBot: Server error details:', err); throw new Error('Config fetch failed: ' + (err.error || response.statusText) + ' (Status: ' + response.status + ')'); }); } return response.json(); }) .then(config => { console.log('LeadBot: Configuration loaded successfully', config); initializeChatbot(config, apiUrl); }) .catch(error => { console.error('LeadBot: Error loading configuration:', error); console.error('LeadBot: Config URL was:', configUrl); console.error('LeadBot: Chatbot ID was:', chatbotId); }); function initializeChatbot(config, apiUrl) { const chatbotId = config.chatbotId; const primaryColor = config.primaryColor || '#3B82F6'; const buttonText = config.buttonText || 'Chat with us'; const welcomeMessage = config.welcomeMessage || "Hi! I'd love to learn more about your needs. Let's get started!"; const showBranding = config.showBranding !== false; const customFields = config.customFields || []; const conversationMode = config.conversationMode || false; const fieldPrompts = config.fieldPrompts || {}; const fieldOrder = config.fieldOrder || []; const fieldsToCollect = config.fieldsToCollect || []; const autoOpenDelay = config.autoOpenDelay || 0; if (config.isActive === false) { console.log('LeadBot: Chatbot is currently inactive'); return; } console.log('LeadBot: Conversation mode:', conversationMode); function adjustColor(color, amount) { const num = parseInt(color.replace('#', ''), 16); const r = Math.max(0, Math.min(255, (num >> 16) + amount)); const g = Math.max(0, Math.min(255, ((num >> 8) & 0x00FF) + amount)); const b = Math.max(0, Math.min(255, (num & 0x0000FF) + amount)); return '#' + ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0'); } const defaultFieldPrompts = { name: "What's your name?", email: "What's your email address?", phone: "What's your phone number?", company: "What company do you represent?", message: "How can we help you today?" }; function generateFormFields() { const defaultFields = [ { id: 'name', label: 'Your name', type: 'text', required: true, placeholder: 'Your name *', autocomplete: 'name' }, { id: 'email', label: 'Email address', type: 'email', required: true, placeholder: 'Email address *', autocomplete: 'email' }, { id: 'phone', label: 'Phone number', type: 'tel', required: false, placeholder: 'Phone number', autocomplete: 'tel' }, { id: 'company', label: 'Company name', type: 'text', required: false, placeholder: 'Company name', autocomplete: 'organization' }, { id: 'message', label: 'Message', type: 'textarea', required: true, placeholder: 'How can we help you? *' } ]; const allFields = [...defaultFields, ...customFields]; const activeFields = allFields.filter(f => fieldsToCollect.includes(f.id)); let orderedFields = activeFields; if (fieldOrder.length > 0) { orderedFields = fieldOrder .map(id => activeFields.find(f => f.id === id)) .filter(f => f !== undefined); const orderedIds = orderedFields.map(f => f.id); const remainingFields = activeFields.filter(f => !orderedIds.includes(f.id)); orderedFields = [...orderedFields, ...remainingFields]; } return orderedFields.map(field => { if (field.type === 'textarea') { return ''; } else if (field.type === 'select') { const options = field.options?.map(opt => '').join('') || ''; return ''; } else if (field.type === 'date') { return ''; } else { return ''; } }).join(''); } function getOrderedFields() { const defaultFields = [ { id: 'name', label: 'Your name', type: 'text', required: true }, { id: 'email', label: 'Email address', type: 'email', required: true }, { id: 'phone', label: 'Phone number', type: 'tel', required: false }, { id: 'company', label: 'Company name', type: 'text', required: false }, { id: 'message', label: 'Message', type: 'textarea', required: true } ]; const allFields = [...defaultFields, ...customFields]; const activeFields = allFields.filter(f => fieldsToCollect.includes(f.id)); let orderedFields = activeFields; if (fieldOrder.length > 0) { orderedFields = fieldOrder .map(id => activeFields.find(f => f.id === id)) .filter(f => f !== undefined); const orderedIds = orderedFields.map(f => f.id); const remainingFields = activeFields.filter(f => !orderedIds.includes(f.id)); orderedFields = [...orderedFields, ...remainingFields]; } return orderedFields; } const darkerColor = adjustColor(primaryColor, -20); const style = document.createElement('style'); style.textContent = '* { box-sizing: border-box; } ' + '.leadbot-widget { position: fixed; bottom: 24px; right: 24px; z-index: 999999; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } ' + '.leadbot-button { width: 64px; height: 64px; border-radius: 50%; background: linear-gradient(135deg, ' + primaryColor + ', ' + darkerColor + '); border: none; cursor: pointer; box-shadow: 0 4px 20px rgba(0,0,0,0.2); display: flex; align-items: center; justify-content: center; transition: transform 0.3s ease, box-shadow 0.3s ease; } ' + '.leadbot-button:hover { transform: scale(1.1); box-shadow: 0 6px 24px rgba(0,0,0,0.3); } ' + '.leadbot-button svg { width: 28px; height: 28px; fill: white; } ' + '.leadbot-chat { position: fixed; bottom: 100px; right: 24px; width: 420px; max-width: calc(100vw - 48px); height: 600px; max-height: calc(100vh - 140px); background: white; border-radius: 20px; box-shadow: 0 12px 40px rgba(0,0,0,0.15); display: none; flex-direction: column; overflow: hidden; } ' + '.leadbot-chat.open { display: flex; animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); } ' + '@keyframes slideUp { from { opacity: 0; transform: translateY(30px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } } ' + '.leadbot-header { background: linear-gradient(135deg, ' + primaryColor + ' 0%, ' + darkerColor + ' 100%); color: white; padding: 20px 24px; display: flex; align-items: center; justify-content: space-between; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } ' + '.leadbot-header-content { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; } ' + '.leadbot-avatar { width: 44px; height: 44px; border-radius: 50%; background: rgba(255,255,255,0.25); display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(0,0,0,0.1); flex-shrink: 0; } ' + '.leadbot-header-content > div { min-width: 0; } ' + '.leadbot-header-content > div > div:first-child { font-weight: 700; font-size: 17px; letter-spacing: -0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } ' + '.leadbot-close { background: rgba(255,255,255,0.1); border: none; color: white; cursor: pointer; font-size: 24px; padding: 0; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: background 0.2s; flex-shrink: 0; } ' + '.leadbot-close:hover { background: rgba(255,255,255,0.25); } ' + '.leadbot-body { flex: 1; padding: 20px; overflow-y: auto; overflow-x: hidden; background: linear-gradient(to bottom, #f9fafb 0%, #ffffff 100%); } ' + '.leadbot-body::-webkit-scrollbar { width: 6px; } ' + '.leadbot-body::-webkit-scrollbar-track { background: transparent; } ' + '.leadbot-body::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 3px; } ' + '.leadbot-message { background: white; padding: 18px; border-radius: 16px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); border: 1px solid #f0f0f0; animation: messageSlideIn 0.3s ease-out; word-wrap: break-word; } ' + '@keyframes messageSlideIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } ' + '.leadbot-user-message { background: linear-gradient(135deg, ' + primaryColor + ', ' + darkerColor + '); color: white; padding: 12px 16px; border-radius: 16px; border-bottom-right-radius: 4px; margin-bottom: 16px; margin-left: 30px; box-shadow: 0 2px 8px ' + primaryColor + '40; animation: messageSlideIn 0.3s ease-out; word-wrap: break-word; } ' + '.leadbot-form { display: flex; flex-direction: column; gap: 12px; } ' + '.leadbot-input { width: 100%; padding: 12px 14px; border: 2px solid #e5e7eb; border-radius: 12px; font-size: 15px; transition: all 0.2s; background: white; box-sizing: border-box; } ' + '.leadbot-input:focus { outline: none; border-color: ' + primaryColor + '; box-shadow: 0 0 0 3px ' + primaryColor + '20; } ' + '.leadbot-textarea { min-height: 100px; resize: vertical; font-family: inherit; } ' + '.leadbot-submit { background: linear-gradient(135deg, ' + primaryColor + ', ' + darkerColor + '); color: white; border: none; padding: 14px; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 4px 12px ' + primaryColor + '40; width: 100%; } ' + '.leadbot-submit:hover { transform: translateY(-2px); box-shadow: 0 6px 16px ' + primaryColor + '50; } ' + '.leadbot-submit:active { transform: translateY(0); } ' + '.leadbot-submit:disabled { opacity: 0.6; cursor: not-allowed; transform: none; } ' + '.leadbot-footer { padding: 12px 20px; border-top: 1px solid #e5e7eb; text-align: center; } ' + '.leadbot-branding { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: #9ca3af; text-decoration: none; transition: color 0.2s; } ' + '.leadbot-branding:hover { color: ' + primaryColor + '; } ' + '.leadbot-branding svg { width: 14px; height: 14px; } ' + '.leadbot-success { text-align: center; padding: 60px 30px; } ' + '.leadbot-success-icon { width: 72px; height: 72px; background: linear-gradient(135deg, #10b981, #059669); border-radius: 50%; margin: 0 auto 24px; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3); animation: scaleIn 0.5s ease-out; } ' + '@keyframes scaleIn { from { transform: scale(0); } to { transform: scale(1); } } ' + '.leadbot-typing { display: flex; gap: 4px; padding: 16px; } ' + '.leadbot-typing span { width: 8px; height: 8px; border-radius: 50%; background: #9ca3af; animation: typing 1.4s infinite; } ' + '.leadbot-typing span:nth-child(2) { animation-delay: 0.2s; } ' + '.leadbot-typing span:nth-child(3) { animation-delay: 0.4s; } ' + '@keyframes typing { 0%, 60%, 100% { opacity: 0.3; transform: scale(0.8); } 30% { opacity: 1; transform: scale(1); } } ' + '@media (max-width: 480px) { .leadbot-widget { bottom: 16px; right: 16px; } .leadbot-button { width: 56px; height: 56px; } .leadbot-chat { width: calc(100vw - 32px); height: calc(100vh - 100px); bottom: 80px; right: 16px; } }'; document.head.appendChild(style); let conversationData = {}; let currentFieldIndex = 0; let isProcessing = false; let conversationStarted = false; const widget = document.createElement('div'); widget.className = 'leadbot-widget'; let bodyContent = ''; if (!conversationMode) { bodyContent = '
👋 Hi there!
' + welcomeMessage + '
' + generateFormFields() + '
'; } let footerContent = ''; if (showBranding) { footerContent = ''; } widget.innerHTML = ''; document.body.appendChild(widget); console.log('LeadBot: Widget created successfully'); const toggle = document.getElementById('leadbot-toggle'); const chat = document.getElementById('leadbot-chat'); const close = document.getElementById('leadbot-close'); const body = document.getElementById('leadbot-body'); toggle.addEventListener('click', () => { const wasOpen = chat.classList.contains('open'); chat.classList.toggle('open'); if (conversationMode && !wasOpen && !conversationStarted) { conversationStarted = true; startConversation(); } }); close.addEventListener('click', () => { chat.classList.remove('open'); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && chat.classList.contains('open')) { chat.classList.remove('open'); } }); // Auto-open chatbot after delay if configured if (autoOpenDelay > 0) { setTimeout(() => { if (!chat.classList.contains('open')) { chat.classList.add('open'); if (conversationMode && !conversationStarted) { conversationStarted = true; startConversation(); } } }, autoOpenDelay * 1000); } function startConversation() { console.log('LeadBot: Starting conversation mode'); currentFieldIndex = 0; conversationData = {}; body.innerHTML = '
👋 Hi there!
' + welcomeMessage + '
'; setTimeout(() => { askNextQuestion(); }, 800); } function askNextQuestion() { const fields = getOrderedFields(); console.log('LeadBot: askNextQuestion - index:', currentFieldIndex, 'total:', fields.length); if (currentFieldIndex >= fields.length) { console.log('LeadBot: All fields collected, submitting...'); submitConversation(); return; } const field = fields[currentFieldIndex]; console.log('LeadBot: Asking for field:', field.id); const prompt = fieldPrompts[field.id] || defaultFieldPrompts[field.id] || 'Please enter your ' + field.label.toLowerCase(); const uniqueInputId = 'conv-input-' + field.id + '-' + Date.now(); const uniqueButtonId = 'conv-submit-' + field.id + '-' + Date.now(); const typingDiv = document.createElement('div'); typingDiv.className = 'leadbot-message'; typingDiv.innerHTML = '
'; body.appendChild(typingDiv); body.scrollTop = body.scrollHeight; setTimeout(() => { typingDiv.remove(); const messageDiv = document.createElement('div'); messageDiv.className = 'leadbot-message'; let inputHTML = ''; if (field.type === 'textarea') { inputHTML = '
' + prompt + '
'; } else if (field.type === 'select') { const options = field.options?.map(opt => '').join('') || ''; inputHTML = '
' + prompt + '
'; } else if (field.type === 'date') { inputHTML = '
' + prompt + '
'; } else { inputHTML = '
' + prompt + '
'; } inputHTML += ''; messageDiv.innerHTML = inputHTML; body.appendChild(messageDiv); body.scrollTop = body.scrollHeight; const input = document.getElementById(uniqueInputId); const submitBtn = document.getElementById(uniqueButtonId); if (!input || !submitBtn) { console.error('LeadBot: Failed to find input or submit button'); return; } input.focus(); const handleSubmit = (e) => { console.log('LeadBot: handleSubmit for field:', field.id); if (isProcessing) { console.log('LeadBot: Already processing'); return; } const value = input.value.trim(); console.log('LeadBot: Value:', value); if (field.required && !value) { console.log('LeadBot: Required field empty'); input.style.borderColor = '#ef4444'; setTimeout(() => { input.style.borderColor = ''; }, 2000); return; } if (field.type === 'email' && value) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(value)) { console.log('LeadBot: Invalid email'); input.style.borderColor = '#ef4444'; setTimeout(() => { input.style.borderColor = ''; }, 2000); return; } } isProcessing = true; conversationData[field.id] = value; console.log('LeadBot: Data collected:', conversationData); submitBtn.disabled = true; submitBtn.textContent = 'Processing...'; if (value) { const userMessage = document.createElement('div'); userMessage.className = 'leadbot-user-message'; userMessage.textContent = value; body.appendChild(userMessage); body.scrollTop = body.scrollHeight; } currentFieldIndex++; console.log('LeadBot: Moving to index:', currentFieldIndex); setTimeout(() => { isProcessing = false; askNextQuestion(); }, 600); }; submitBtn.addEventListener('click', handleSubmit); input.addEventListener('keydown', (e) => { if (e.key === 'Enter') { if (field.type === 'textarea') { if (e.ctrlKey || e.metaKey) { e.preventDefault(); handleSubmit(e); } } else { e.preventDefault(); handleSubmit(e); } } }); }, 1000); } async function submitConversation() { console.log('LeadBot: Submitting:', conversationData); const typingDiv = document.createElement('div'); typingDiv.className = 'leadbot-message'; typingDiv.innerHTML = '
'; body.appendChild(typingDiv); body.scrollTop = body.scrollHeight; try { const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chatbot_id: chatbotId, formData: conversationData, source_url: window.location.href }) }); typingDiv.remove(); if (response.ok) { console.log('LeadBot: Success!'); body.innerHTML = '
Thank you!
We\'ve received your information and will get back to you soon.
'; setTimeout(() => { chat.classList.remove('open'); setTimeout(() => { location.reload(); }, 500); }, 3000); } else { throw new Error('Failed to submit'); } } catch (error) { console.error('LeadBot: Submit error:', error); typingDiv.remove(); const errorDiv = document.createElement('div'); errorDiv.className = 'leadbot-message'; errorDiv.innerHTML = '
Sorry, something went wrong. Please try again.
'; body.appendChild(errorDiv); } } if (!conversationMode) { const form = document.getElementById('leadbot-form'); form.addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(form); const submitBtn = form.querySelector('.leadbot-submit'); submitBtn.disabled = true; submitBtn.textContent = 'Sending...'; const data = {}; formData.forEach((value, key) => { data[key] = value; }); try { const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chatbot_id: chatbotId, formData: data, source_url: window.location.href }) }); if (response.ok) { body.innerHTML = '
Thank you!
We\'ve received your message and will get back to you soon.
'; setTimeout(() => { chat.classList.remove('open'); setTimeout(() => { location.reload(); }, 500); }, 3000); } else { throw new Error('Failed to submit'); } } catch (error) { alert('Sorry, something went wrong. Please try again.'); submitBtn.disabled = false; submitBtn.textContent = 'Send Message →'; } }); } } })();