function loadConversation(window) { const pageSrc = 'https://converse.microcast.ai/b5956616-c979-4549-8992-02ce92857069/ef47b32e-1e8f-42a4-a079-9c112e1412b4/converse'; const buttonEnabled = false; const popupConfig = {"paddingX":11,"minHeight":401,"widthPercent":41,"borderRadius":0,"shadow":{"thickness":0,"position":"full"},"maxHeight":901,"minWidth":301,"position":"bottom-right","paddingY":41,"maxWidth":901,"heightPercent":61}; const mobilePopupConfig = {"paddingX":11,"minHeight":401,"widthPercent":41,"shadow":{"thickness":0,"position":"full"},"maxHeight":901,"minWidth":301,"position":"bottom-center","paddingY":41,"maxWidth":901,"heightPercent":61}; const minimizedConfig = {"paddingX":11,"width":180,"position":"bottom-right","paddingY":11,"height":68}; const initialWindowState = 'MINIMIZED'; const document = window.document; console.log('Microcasting Conversation Embed'); document.head.insertAdjacentHTML("beforeend", ` `) const clamp = (val, min, max) => Math.min(Math.max(val, min), max); const setPosition = (element, position) => { // console.log('setPosition', position); element.style.top = `${position.top}px`; element.style.right = `${position.right}px`; element.style.bottom = `${position.bottom}px`; element.style.left = `${position.left}px`; } const setStyle = (element, props) => { Object.assign(element.style, props); } const calcPosition = (windowSize, popupConfig, popupSize) => { // console.log('calcPosition', { windowSize, popupConfig, popupSize }); if (!popupSize) { popupSize = { height: clamp(windowSize.height * popupConfig.heightPercent / 100, popupConfig.minHeight, popupConfig.maxHeight), width: clamp(windowSize.width * popupConfig.widthPercent / 100, popupConfig.minWidth, popupConfig.maxWidth), }; }; // console.log('popupSize', popupSize); let calculatedPosition = undefined; switch (popupConfig.position) { case 'top-left': calculatedPosition = { top: popupConfig.paddingX, bottom: windowSize.height - popupConfig.paddingY - popupSize.height, left: popupConfig.paddingY, right: windowSize.width - popupConfig.paddingX - popupSize.width, }; break; case 'top-center': calculatedPosition = { top: popupConfig.paddingY, bottom: windowSize.height - popupConfig.paddingY - popupSize.height, left: (windowSize.width - popupSize.width) / 2, right: (windowSize.width - popupSize.width) / 2, }; break; case 'top-right': calculatedPosition = { top: popupConfig.paddingY, bottom: windowSize.height - popupConfig.paddingY - popupSize.height, left: windowSize.width - popupConfig.paddingX - popupSize.width, right: popupConfig.paddingX, }; break; case 'bottom-left': calculatedPosition = { top: windowSize.height - popupConfig.paddingY - popupSize.height, bottom: popupConfig.paddingY, left: popupConfig.paddingX, right: windowSize.width - popupConfig.paddingX - popupSize.width, }; break; case 'bottom-center': calculatedPosition = { top: windowSize.height - popupConfig.paddingY - popupSize.height, bottom: popupConfig.paddingY, left: (windowSize.width - popupSize.width) / 2, right: (windowSize.width - popupSize.width) / 2, }; break; case 'bottom-right': calculatedPosition = { top: windowSize.height - popupConfig.paddingY - popupSize.height, bottom: popupConfig.paddingY, right: popupConfig.paddingX, left: windowSize.width - popupConfig.paddingX - popupSize.width, }; break; default: calculatedPosition = undefined; break; }; // console.log('calculatedPosition', calculatedPosition); const width = calculatedPosition.right - calculatedPosition.left; const height = calculatedPosition.bottom - calculatedPosition.top; // make sure its bigger than minWidth and minHeight calculatedPosition.width = Math.max(width, popupConfig.minWidth); calculatedPosition.height = Math.max(height, popupConfig.minHeight); // make sure its smaller than maxWidth and maxHeight calculatedPosition.width = Math.min(width, popupConfig.maxWidth); calculatedPosition.height = Math.min(height, popupConfig.maxHeight); // make sure its not outside the window calculatedPosition.left = Math.max(calculatedPosition.left, 0); calculatedPosition.top = Math.max(calculatedPosition.top, 0); calculatedPosition.right = Math.min(calculatedPosition.right, windowSize.width); calculatedPosition.bottom = Math.min(calculatedPosition.bottom, windowSize.height); // console.log('final calculatedPosition', calculatedPosition); return calculatedPosition; }; const div = document.createElement('div'); div.className = "microcastingAi-div"; div.id = "microcastingAi-div"; document.body.appendChild(div); const iframeCover = document.createElement('div'); iframeCover.className = "microcastingAi-iframe-cover"; div.appendChild(iframeCover); let startMouseX, startMouseY, startPosition, popupPosition; let startTransition = div.style.transition; const resize = (e) => { const diffX = e.clientX - startMouseX; const diffY = e.clientY - startMouseY; // handle vertical resize if (resizeFrom.startsWith('top')) { const newTop = startPosition.top + diffY; popupPosition.top = windowSize.height - newTop - startPosition.bottom > popupConfig.minHeight ? newTop : windowSize.height - popupConfig.minHeight - startPosition.bottom; } else if (resizeFrom.startsWith('bottom')) { const newBottom = startPosition.bottom - diffY; popupPosition.bottom = windowSize.height - newBottom - startPosition.top > popupConfig.minHeight ? newBottom : windowSize.height - popupConfig.minHeight - startPosition.top; } // handle horizontal resize if (resizeFrom.endsWith('left')) { const newLeft = startPosition.left + diffX; popupPosition.left = windowSize.width - newLeft - startPosition.right > popupConfig.minWidth ? newLeft : windowSize.width - startPosition.right - popupConfig.minWidth; } else if (resizeFrom.endsWith('right')) { const newRight = startPosition.right - diffX; popupPosition.right = windowSize.width - newRight - startPosition.left > popupConfig.minWidth ? newRight : windowSize.width - startPosition.left - popupConfig.minWidth; } setPosition(div, popupPosition); }; // popupPosition.right = windowSize.width - newRight - startPosition.left > popupConfig.minWidth // ? newRight : windowSize.width - popupConfig.minWidth - startPosition.left; // const newTop = startPosition.top + diffY; // popupPosition.top = windowSize.height - newTop - startPosition.bottom > popupConfig.minHeight // ? newTop : windowSize.height - popupConfig.minHeight - startPosition.bottom; // break; // case 'top-left': // popupPosition.left = startPosition.left + diffX; // popupPosition.top = startPosition.top + diffY; // break; // case 'bottom-right': // popupPosition.right = startPosition.right - diffX; // popupPosition.bottom = startPosition.bottom - diffY; // break; // case 'bottom-left': // popupPosition.left = startPosition.left + diffX; // popupPosition.bottom = startPosition.bottom - diffY; // break; // } // setPosition(div, popupPosition); // }; const stopResize = () => { div.style.transition = startTransition; iframeCover.style.display = 'none'; // localStorage.setItem('microcastingAi.position', JSON.stringify(popupPosition)); window.removeEventListener('mousemove', resize) } const startResize = (e, from) => { if(e.stopPropagation) e.stopPropagation(); if(e.preventDefault) e.preventDefault(); e.cancelBubble=true; e.returnValue=false; div.style.transition = 'none'; iframeCover.style.display = 'block'; console.log('Drag start', e); startMouseX = e.clientX; startMouseY = e.clientY; startPosition = { ...popupPosition }; resizeFrom = from; window.addEventListener('mousemove', resize); window.addEventListener('mouseup', stopResize); return false; } const addResizeHandle = (from) => { const resizeHandle = document.createElement('div'); resizeHandle.classList.add("microcastingAi-resize-handle", `microcastingAi-resize-handle-${from}`); resizeHandle.id = `microcastingAi-resize-handle-${from}`; resizeHandle.onmousedown = (e) =>{ return startResize(e, from); }; div.appendChild(resizeHandle); } addResizeHandle('top-right'); addResizeHandle('top-left'); addResizeHandle('bottom-right'); addResizeHandle('bottom-left'); // create an iframe const iframe = document.createElement('iframe'); iframe.className = "microcastingAi-iframe"; iframe.id = "microcastingAi-iframe"; // Allow microphone access inside the embedded conversation iframe.setAttribute('allow', 'microphone'); setStyle(iframe, { border: 'none', width: '100%', height: '100%', }); iframe.src = pageSrc; // put the iframe in the div div.appendChild(iframe); const postMessage = (type, details) => { iframe.contentWindow.postMessage( { source: 'microcastingAIClient', type, details, }, '*', ); }; const closeWindow = () => { windowState = 'CLOSED'; div.style.visibility = 'hidden'; div.style.opacity = 0; localStorage.removeItem("microcastingAi.windowOpen"); } const expandWindow = () => { windowState = 'OPEN'; div.classList.remove('minimized'); div.style.visibility = 'visible'; div.style.opacity = 1; postMessage('setOpen'); updatePosition(false); localStorage.setItem('microcastingAi.windowOpen', Date.now()); localStorage.removeItem('microcastingAi.windowMinimized'); } const openWindow = expandWindow; const minimizeWindow = () => { windowState = 'MINIMIZED'; div.classList.add('minimized'); div.style.visibility = 'visible'; div.style.opacity = 1; updatePosition(false); postMessage('setMinimized'); localStorage.setItem('microcastingAi.windowMinimized', Date.now()); localStorage.removeItem('microcastingAi.windowOpen'); } const toggleWindow = () => { if (div.style.visibility === 'visible') { closeWindow(); } else { expandWindow(); } } if (buttonEnabled) { // add a button to the page that floats in the lower right corner // create a button const button = document.createElement('image' === 'svg' ? 'button' : 'input'); if ('image' === 'svg') { button.innerHTML = '' || ` `; } else { // image button button.type = 'image'; button.src = 'https://mcn-library-huwdev-enn.s3.amazonaws.com/4d770227-a5c0-48b8-b49d-37a50ecd69df/original' || 'https://via.placeholder.com/48'; } button.className = "microcastingAiTriggerButton"; button.id = "microcastingAiTriggerButton"; if ('none' === 'beforeID') { // inject the button into a div before element with id // find element with id recentlyViewed-default const target = document.getElementById('recentlyViewed-default'); // append putton after the target target.parentNode.insertBefore(button, target); } else { // default is floating // add the button to the page document.body.appendChild(button); } // add an event listener to the button to show/hide the div button.addEventListener('click', toggleWindow); } let windowSize = { width: document.body.clientWidth, height: window.innerHeight, }; const storedPosition = undefined; // localStorage.getItem('microcastingAi.position'); let desktopPosition = storedPosition ? JSON.parse(storedPosition) : calcPosition(windowSize, popupConfig); if (initialWindowState === 'MINIMIZED') { div.classList.add('minimized'); } let windowState = initialWindowState; const updatePosition = (noTransitions = true) => { console.log('updatePosition', { windowState, noTransitions }); const windowSize = { width: document.body.clientWidth, height: window.innerHeight, }; const isMobile = windowSize.width < 480; if (windowState === 'CLOSED') { return; } if (windowState === 'MINIMIZED') { popupPosition = calcPosition( windowSize, minimizedConfig, { height: minimizedConfig.height, width: minimizedConfig.width }, ); } else if (isMobile) { popupPosition = calcPosition(windowSize, mobilePopupConfig); } else { popupPosition = desktopPosition; } // suppress transition if resizing div.style.transition = noTransitions ? 'none': startTransition; setPosition(div, popupPosition); // div.style.transition = startTransition; } const handleWindowResize = () => { const newSize = { width: document.body.clientWidth, height: window.innerHeight, }; const delta = { x: newSize.width - windowSize.width, y: newSize.height - windowSize.height, }; console.log('handleWindowResize', { delta, popupConfig }); if (popupConfig.position.startsWith('top-')) { console.log('top-', delta.y); desktopPosition.bottom = desktopPosition.bottom + delta.y; } else if (popupConfig.position.startsWith('bottom-')) { console.log('bottom-', delta.y); desktopPosition.top = desktopPosition.top + delta.y; } if (popupConfig.position.endsWith('-left')) { desktopPosition.right = desktopPosition.right + delta.x; } else if (popupConfig.position.endsWith('-right')) { desktopPosition.left = desktopPosition.left + delta.x; } else if (popupConfig.position.endsWith('-center')) { desktopPosition.left = desktopPosition.left + delta.x / 2; desktopPosition.right = desktopPosition.right + delta.x / 2; } if (windowState === 'OPEN') { popupPosition = desktopPosition; } else if (windowState === 'MINIMIZED') { minimizedPosition = calcPosition(newSize, minimizedConfig, { height: minimizedConfig.height, width: minimizedConfig.width }); popupPosition = minimizedPosition; } else if (windowState === 'CLOSED') { return; } windowSize = newSize; updatePosition(true); } window.addEventListener('resize', handleWindowResize); const setWindowState = () => { // if (localStorage.getItem("microcastingAi.windowOpen") // && localStorage.getItem("microcastingAi.windowOpen") > Date.now() - 20000 // ) { // expandWindow(); // } else if (localStorage.getItem("microcastingAi.windowMinimized") // && localStorage.getItem("microcastingAi.windowMinimized") > Date.now() - 20000 // ) { // minimizeWindow(); // } else { if (initialWindowState === 'MINIMIZED') { console.log('Setting minimized'); minimizeWindow(); } else if (initialWindowState === 'OPEN') { expandWindow(); } // } } updatePosition(false); // setWindowState(); const handlers = { tracking: (data) => { console.log('tracking', data); // if its the start event, open the window if (data.trackData.event === 'conversationAI_ready') { // wait 2 seconds before opening the window setTimeout(() => { setWindowState(); const pathnameSegments = window.location.pathname.toLowerCase().split('/').filter(Boolean); const isProductPage = pathnameSegments.some(segment => ['products', 'product'].includes(segment)) && pathnameSegments.length >= 2; const productID = isProductPage ? pathnameSegments[pathnameSegments.length - 1] || pathnameSegments[pathnameSegments.length - 2] : undefined; postMessage( 'customerContext', { currentPage: { url: window.location.href, title: document.title, description: document.description, isProduct: isProductPage, product: productID ? { id: productID, name: '' } : undefined, }, }, ); }, 100); } if (window.gtag || window.dataLayer) { const event = data.trackData.event; const gaData = { ...data.trackData }; delete gaData.event; if (window.gtag) { window.gtag('event', event, gaData); } if (window.dataLayer) { window.dataLayer.push({ event, ...gaData, }); } } }, closeWindow: () => { closeWindow(); }, expandWindow: () => { console.log('expandWindow'); expandWindow(); }, minimizeWindow: () => { console.log('minimizeWindow'); minimizeWindow(); }, }; const eventListener = (event) => { if (event.data.source === 'microcastingAI') { if (handlers && handlers[event.data.type]) { handlers[event.data.type](event.data); } } }; window.addEventListener('message', eventListener); try { } catch (e) { console.error('Error in custom init logic', e); } try { const result = { toggleWindow, openWindow, closeWindow, expandWindow, minimizeWindow, postMessage, handlers, }; window.microcastingAi = result; return result; } catch (e) { console.error('Error setting up microcastingAi', e); return undefined; } }; window.microcastingAi = loadConversation(window); console.log('microcastingAi', window.microcastingAi);