(function() { // Load Supabase client const supabaseScript = document.createElement('script'); supabaseScript.src = 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2'; document.head.appendChild(supabaseScript); // Generate a unique session ID function generateSessionId() { return Date.now().toString(36) + Math.random().toString(36).substr(2); } // Extract domain from script src function getCRMDomain(src) { try { const scriptTag = document.currentScript || document.querySelector('#crm-chatbot'); const fallbackDomain = scriptTag?.getAttribute('data-fallback-domain'); if (!src) return fallbackDomain; const url = new URL(src); return url.origin; } catch (e) { console.error('Error parsing script URL:', e); const scriptTag = document.currentScript || document.querySelector('#crm-chatbot'); return scriptTag?.getAttribute('data-fallback-domain'); } } // Initialize Supabase client function createSupabaseClient(crmDomain) { const supabaseAnonKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZqbGhwb3drcWhrcmJpeHBpbmp3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzU5MTE3MzYsImV4cCI6MjA1MTQ4NzczNn0.xVLprAwCkxeBvMiCh19mdFHdIW8fHlWM60k4JjGdHTE'; return window.supabase.createClient( 'https://vjlhpowkqhkrbixpinjw.supabase.co', supabaseAnonKey ); } // Handle chatbot configuration class ConfigManager { constructor(supabaseClient) { this.supabase = supabaseClient; } async loadConfig(organizationId) { try { console.log('Loading chatbot config for organization:', organizationId); const response = await this.supabase.functions.invoke('get-chatbot-config', { body: { organizationId } }); if (response.error) throw response.error; console.log('Chatbot config loaded:', response.data); return response.data; } catch (error) { console.error('Error loading chatbot config:', error); return { primaryColor: '#0ea5e9', title: 'Sales Assistant', welcomeMessage: 'Hi there! How can I help you today?', position: 'bottom-right' }; } } } // Handle visitor tracking class VisitorTracker { constructor(supabaseClient) { this.supabase = supabaseClient; } async trackVisitor(organizationId, sessionId, pageInfo) { try { console.log('Tracking visitor for organization:', organizationId); const response = await this.supabase.functions.invoke('track-visitor', { body: { organizationId, sessionId, ...pageInfo } }); if (response.error) { console.error('Error tracking visitor:', response.error); return; } console.log('Visitor tracked successfully'); } catch (error) { console.error('Error tracking visitor:', error); } } async trackExit(organizationId, sessionId, pageUrl) { if (this.supabase) { try { await this.supabase.functions.invoke('track-exit', { body: { organizationId, sessionId, pageUrl, exitAt: new Date().toISOString() } }); } catch (error) { console.error('Error tracking exit:', error); } } } } // Handle UI elements and interactions class UIManager { constructor(config) { this.config = config; this.container = null; this.button = null; this.iframe = null; } createContainer() { const container = document.createElement('div'); container.id = 'crm-chatbot-container'; container.style.position = 'fixed'; container.style.zIndex = '2147483647'; container.style.bottom = '20px'; container.style.right = '20px'; container.style.width = '400px'; container.style.height = '600px'; container.style.maxHeight = '80vh'; container.style.maxWidth = '90vw'; container.style.display = 'none'; document.body.appendChild(container); this.container = container; } createButton() { const button = document.createElement('button'); button.id = 'crm-chatbot-button'; button.style.position = 'fixed'; button.style.zIndex = '2147483647'; button.style.bottom = '20px'; button.style.right = '20px'; button.style.width = '60px'; button.style.height = '60px'; button.style.borderRadius = '50%'; button.style.backgroundColor = this.config.primaryColor; button.style.color = 'white'; button.style.border = 'none'; button.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.2)'; button.style.cursor = 'pointer'; button.innerHTML = ''; button.style.display = 'flex'; button.style.alignItems = 'center'; button.style.justifyContent = 'center'; document.body.appendChild(button); this.button = button; } createIframe(url) { const iframe = document.createElement('iframe'); iframe.id = 'crm-chatbot-iframe'; iframe.style.border = 'none'; iframe.style.width = '100%'; iframe.style.height = '100%'; iframe.style.background = 'white'; iframe.style.borderRadius = '10px'; iframe.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.15)'; iframe.src = url; this.container.appendChild(iframe); this.iframe = iframe; } setupEventListeners(onToggle) { this.button.addEventListener('click', () => { const isVisible = this.container.style.display === 'block'; this.container.style.display = isVisible ? 'none' : 'block'; onToggle?.(!isVisible); }); window.addEventListener('message', (event) => { if (event.data?.type === 'close') { this.container.style.display = 'none'; } }); } updateButtonColor(color) { if (this.button) { this.button.style.backgroundColor = color; } } } // Main initialization function once Supabase is loaded supabaseScript.onload = async function() { try { const scriptTag = document.currentScript || document.querySelector('#crm-chatbot'); const crmDomain = getCRMDomain(scriptTag?.src || ''); if (!crmDomain) { console.error('Could not determine CRM domain. Please set data-fallback-domain attribute.'); return; } console.log('CRM domain determined as:', crmDomain); const supabase = createSupabaseClient(crmDomain); const sessionId = generateSessionId(); console.log('Generated session ID:', sessionId); // Get organization ID based on the current domain const { data, error } = await supabase.functions.invoke('get-organization-by-domain', { body: { domain: window.location.hostname } }); if (error || !data?.organizationId) { console.error('Error getting organization:', error || 'No organization found'); return; } const organizationId = data.organizationId; console.log('Organization ID:', organizationId); // Initialize managers const configManager = new ConfigManager(supabase); const visitorTracker = new VisitorTracker(supabase); // Load initial configuration const config = await configManager.loadConfig(organizationId); const uiManager = new UIManager(config); // Setup UI uiManager.createContainer(); uiManager.createButton(); // Track visitor await visitorTracker.trackVisitor(organizationId, sessionId, { pageUrl: window.location.href, pageTitle: document.title, referrer: document.referrer }); // Setup visibility tracking document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') { visitorTracker.trackExit(organizationId, sessionId, window.location.href); } }); // Setup chat toggle behavior uiManager.setupEventListeners((isVisible) => { if (isVisible && !uiManager.iframe) { const widgetUrl = new URL(`${crmDomain}/chatbot-widget`); widgetUrl.searchParams.set('organizationId', organizationId); widgetUrl.searchParams.set('sessionId', sessionId); widgetUrl.searchParams.set('t', new Date().getTime().toString()); console.log('Loading widget from URL:', widgetUrl.toString()); uiManager.createIframe(widgetUrl.toString()); } }); } catch (error) { console.error('Fatal error in chat widget:', error); } }; })();