(function() { if (window.zipchatWidgetLoaded) { return; // If already loaded, do not load again } // Track the current URL for SPA navigation detection let lastUrl = window.location.href; // Function to handle URL changes in SPAs function handleUrlChange() { const currentUrl = window.location.href; if (currentUrl !== lastUrl) { lastUrl = currentUrl; // Clean up existing widget elements cleanupWidget(); // Reload widget with the new URL loadWidget(); // Re-setup URL change detection setupUrlChangeDetection(); } } // Function to clean up the widget elements function cleanupWidget() { // Remove the iframe if it exists const iframe = document.getElementById('zipchat-iframe'); if (iframe) { iframe.remove(); } // Remove the chat container if it exists const container = document.getElementById('widget-chat-container'); if (container) { container.remove(); } // Clear the URL check interval if it exists if (window.zipchatUrlCheckInterval) { clearInterval(window.zipchatUrlCheckInterval); window.zipchatUrlCheckInterval = null; } // Reset the widget loaded flag window.zipchatWidgetLoaded = false; } // Set up URL change detection using non-invasive polling function setupUrlChangeDetection() { // Method 1: Listen for popstate event (back/forward navigation) window.addEventListener('popstate', handleUrlChange); // Method 2: Simple polling to check for URL changes (1000ms interval is responsive without being resource-intensive) const urlCheckInterval = setInterval(handleUrlChange, 1000); // Store the interval ID for cleanup window.zipchatUrlCheckInterval = urlCheckInterval; } function toggleBodyScroll(enable) { if (enable) { document.body.style.overflow = ''; } else { document.body.style.overflow = 'hidden'; } } function handleIframe(iframe, chatBubbleContainer, chatTrigger, svg, crossSvg) { if (chatBubbleContainer.querySelector("#close-preview-message")) { chatBubbleContainer.querySelector('#close-preview-message').click() if (!!chatTrigger?.conversation_message){ iframe.contentWindow.postMessage( { action: "getConversationMessage", origin: window.location.origin, message: chatTrigger.conversation_message}, "*" ); } } if (iframe.style.opacity == 1) { iframe.style.transform = "scale(0)"; iframe.style.opacity = "0"; iframe.style.pointerEvents = 'none'; if (window.innerWidth <= 768) { toggleBodyScroll(true); } // Swap SVGs svg.style.display = "block"; crossSvg.style.display = "none"; } else { iframe.style.transform = "scale(1)"; iframe.style.opacity = "1"; iframe.style.pointerEvents = 'all'; iframe.contentWindow.postMessage( { action: "scrollToBottom", origin: window.location.origin }, "*" ); if (window.innerWidth <= 768) { toggleBodyScroll(false); document.body.style.position = "static"; document.body.style.inset = "0px"; document.body.style.margin = "0px"; } // Swap SVGs svg.style.display = "none"; crossSvg.style.display = "block"; } } function createLoadingSpinner(chatBubbleIcon) { // Create loading spinner var loaderSpan = document.createElement('span'); loaderSpan.className = 'widget-chat-loader'; // Append loading spinner chatBubbleIcon.appendChild(loaderSpan); // Create style element var style = document.createElement('style'); style.innerHTML = ` .widget-chat-loader { width: 24px; height: 24px; border: 3px solid #FFF; border-bottom-color: transparent; border-radius: 50%; display: inline-block; box-sizing: border-box; animation: rotation 1s linear infinite; } @keyframes rotation { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `; // Append style to the document's head document.head.appendChild(style); return loaderSpan; } // Create chatbot iframe function createChatbotIframe( url, widgetHorizontal, widgetVertical, widgetCorner, widgetZIndex, chatBubbleSizeDifference, chatBubbleContainer, chatTrigger, chatBubbleIcon, svg, crossSvg ) { let chatbotIframe = document.getElementById('zipchat-iframe'); if (!chatbotIframe) { svg.style.display = "none"; // Show loading spinner const loaderSpan = createLoadingSpinner(chatBubbleIcon); chatbotIframe = document.createElement('iframe'); chatbotIframe.setAttribute('id', 'zipchat-iframe'); chatbotIframe.classList.add("zipchat-iframe"); chatbotIframe.src = url; chatbotIframe.style.maxheight = '700px'; chatbotIframe.style.border = 'none'; chatbotIframe.style.opacity = "0" chatbotIframe.style.transform = "scale(0)"; chatbotIframe.style.height = `min(704px, 100% - ${84 + widgetVertical}px - ${chatBubbleSizeDifference}px)`; chatbotIframe.style.position = 'fixed'; chatbotIframe.style.pointerEvents = 'none'; chatbotIframe.style.fontSize = '16px'; chatbotIframe.style.boxShadow = "0 6px 6px 0 rgba(0,0,0,.02),0 8px 24px 0 rgba(0,0,0,.12)"; chatbotIframe.style.transformOrigin = widgetCorner.replace('-',' '); chatbotIframe.style.transition = "transform 0.3s cubic-bezier(0, 1.2, 1, 1), opacity 0.2s ease-out"; if (window.innerWidth <= 768) { chatbotIframe.style.top = '0'; chatbotIframe.style.bottom = '0'; chatbotIframe.style.width = '100%'; chatbotIframe.style.height = '100%'; chatbotIframe.style.zIndex = widgetZIndex; } else { const horizontal = `${widgetHorizontal}px`; if (widgetCorner.includes('right')) { chatbotIframe.style.right = horizontal; } else { chatbotIframe.style.left = horizontal; } const vertical = `${widgetVertical + 60 + chatBubbleSizeDifference}px`; if (widgetCorner.includes('bottom')) { chatbotIframe.style.bottom = vertical; } else { chatbotIframe.style.top = vertical; } chatbotIframe.style.width = '400px'; chatbotIframe.style.zIndex = widgetZIndex; chatbotIframe.style.borderRadius = "0.75rem" } // Hide the spinner when the iframe has finished loading document.body.appendChild(chatbotIframe); chatbotIframe.onload = function() { // Hide loading spinner chatBubbleIcon.removeChild(loaderSpan); handleIframe(chatbotIframe, chatBubbleContainer, chatTrigger, svg, crossSvg) }; } else { handleIframe(chatbotIframe, chatBubbleContainer, chatTrigger, svg, crossSvg) } } // Create modern chat icon svg function modernChatIcon(newSize) { let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); svg.setAttribute('fill', 'none'); svg.setAttribute('viewBox', '0 0 21 25'); svg.setAttribute('width', `${newSize}px`); svg.setAttribute('height', `${newSize}px`); var path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('fill-rule', 'evenodd'); path.setAttribute('clip-rule', 'evenodd'); path.setAttribute('d', 'M3.60412 0H10.466C10.466 5.74692 5.77465 10.4158 0 10.4158V3.58681C0 1.60705 1.61481 0 3.60412 0ZM10.47 0H15.697C18.5843 0 20.932 2.33243 20.932 5.20589C20.932 8.07935 18.5884 10.4118 15.701 10.4118H10.47V0ZM10.466 10.4216V20.726C10.5239 15.0284 15.1888 10.4175 20.9315 10.4175V20.8172H20.9322V25.0012C18.7149 22.0639 17.1702 20.975 11.7682 20.8333H10.466V20.8334H5.235C2.34767 20.8334 0.00398982 18.501 0.00398982 15.6275C0.00398982 12.754 2.34767 10.4216 5.235 10.4216H10.466Z'); path.setAttribute('fill', 'white'); svg.appendChild(path); return svg; } // Create classic chat icon svg function classicChatIcon(newSize) { let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); svg.setAttribute('fill', 'none'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('stroke-width', '1.5'); svg.setAttribute('stroke', '#ffffff'); svg.setAttribute('width', `${newSize}px`); svg.setAttribute('height', `${newSize}px`); svg.setAttribute('style', `width:${newSize}px;height:${newSize}px;fill:none;`); var path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('stroke-linecap', 'round'); path.setAttribute('stroke-linejoin', 'round'); path.setAttribute('d', 'M12 20.25c4.97 0 9-3.694 9-8.25s-4.03-8.25-9-8.25S3 7.444 3 12c0 2.104.859 4.023 2.273 5.48.432.447.74 1.04.586 1.641a4.483 4.483 0 01-.923 1.785A5.969 5.969 0 006 21c1.282 0 2.47-.402 3.445-1.087.81.22 1.668.337 2.555.337'); svg.setAttribute('fill', 'none'); svg.appendChild(path); return svg; } // Create custom chat icon function customChatIcon(bubbleIconUrl, newImageSize) { let img = document.createElement('img'); img.setAttribute('src', bubbleIconUrl); img.setAttribute('alt', 'Custom chat icon'); img.setAttribute('width', `${newImageSize}px`); img.setAttribute('height', `${newImageSize}px`); img.setAttribute('border-radius', '50%'); return img; } // Create chat icon svg function createChatIcon(bubbleIconType, newSize, bubbleIconUrl, newImageSize) { if (bubbleIconType === 'modern') { return modernChatIcon(newSize); } else if (bubbleIconType === 'classic') { return classicChatIcon(newSize); } else if (bubbleIconType === 'custom') { return customChatIcon(bubbleIconUrl, newImageSize); } } function loadWidget() { var scriptTag = document.querySelector('script[src*="zipchat.js"]'); var widgetToken = new URL(scriptTag.src).searchParams.get('id'); let widgetConfigurationUrl, chatbotUrl, baseUrl; const currentUrl = window.location.href; // if current url include params zipchat-preview=true remove the chatPreviewMessageHidden flag if (currentUrl.includes('zipchat-preview=true')) { console.log('zipchat-preview=true'); localStorage.removeItem('chatPreviewMessageHidden'); } // Not running as Shopify theme app extension if (widgetToken) { let baseUrl = scriptTag.src.replace(`/widget/zipchat.js?id=${widgetToken}`, '/widget_data'); // Case when shopify is loading the script tag, we need to remove the &shop parameter const shopParamIndex = baseUrl.indexOf('&shop='); if (shopParamIndex !== -1) { baseUrl = baseUrl.substring(0, shopParamIndex); } widgetConfigurationUrl = new URL(baseUrl); widgetConfigurationUrl.searchParams.append('widget_token', widgetToken); } else { widgetConfigurationUrl = new URL(window.location.origin + '/apps/zipchat/widget/configuration'); } widgetConfigurationUrl.searchParams.append('current_url', currentUrl); fetch(widgetConfigurationUrl.toString(), { method: 'GET', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }) .then(response => response.json()) .then(data => { var widgetData = data; var widgetCorner = widgetData.widget_position_corner; var widgetHorizontal = widgetData.widget_horizontal; var widgetVertical = widgetData.widget_vertical; var widgetSize = widgetData.widget_size; const chatTrigger = widgetData.chat_trigger const widgetZIndex = widgetData.z_index; if (widgetData.widget == false) { return } const sizeMap = { 'small': 0, 'medium': 10, 'large': 20 }; const chatBubbleSizeDifference = sizeMap[widgetSize] || 0; var chatPreviewMessage = document.createElement('div'); chatPreviewMessage.setAttribute('id', 'chat-preview-message'); chatPreviewMessage.style.paddingTop = '10px'; chatPreviewMessage.style.paddingBottom = '10px'; chatPreviewMessage.style.fontFamily = 'sans-serif;' chatPreviewMessage.style.color = 'black' chatPreviewMessage.style.paddingLeft = '16px'; chatPreviewMessage.style.paddingRight = '16px'; chatPreviewMessage.style.boxShadow = 'rgba(0, 0, 0, 0.2) 0px 4px 8px 0px'; const horizontalPreview = `${widgetHorizontal}px`; if (widgetCorner.includes('right')) { chatPreviewMessage.style.right = horizontalPreview; } else { chatPreviewMessage.style.left = horizontalPreview; } const verticalPreview = `${widgetVertical + 55 + chatBubbleSizeDifference}px`; if (widgetCorner.includes('bottom')) { chatPreviewMessage.style.bottom = verticalPreview; } else { chatPreviewMessage.style.top = verticalPreview; } chatPreviewMessage.style.width = '300px'; chatPreviewMessage.style.maxWidth = '300px'; chatPreviewMessage.style.backgroundColor = 'white'; chatPreviewMessage.style.height = 'auto'; chatPreviewMessage.style.position = 'fixed'; chatPreviewMessage.style.zIndex = widgetZIndex; chatPreviewMessage.style.display = "none" chatPreviewMessage.style.borderRadius = "12px" chatPreviewMessage.style.transition = "transform 0.3s cubic-bezier(0, 1.2, 1, 1), opacity 0.2s ease-out"; function linkifyMessage(text) { const urlRegex = /https:\/\/[^\s]+/g; return text.replace(urlRegex, function(url) { return '' + url + ''; }); } const imageElement = widgetData.photo_url ? `
${widgetData.brand_name}
Active