1/* global themeple_global, CookieControl */ 2 3const chatSupport = () => { 4 const publicMethods = {}; 5 const firstScriptDom = document.getElementsByTagName('script')[0]; 6 7 const getConvertUserStatus = async () => { 8 // eslint-disable-next-line camelcase 9 const isUserLoggedIn = await fetch(themeple_global.ajaxurl, { 10 method: 'POST', 11 headers: { 12 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 13 }, 14 body: 'action=get_convert_user_status', 15 }); 16 17 return isUserLoggedIn.json(); 18 }; 19 20 const loadIntercomScript = () => { 21 const ic = document.createElement('script'); 22 ic.type = 'text/javascript'; 23 ic.src = '/wp-content/themes/olympus/js/intercom.js'; 24 firstScriptDom.parentNode.insertBefore(ic, firstScriptDom); 25 }; 26 27 /** 28 * Set and load the intercom script for existing customers. 29 * @returns {Object} Return a list of public methods. 30 */ 31 const intercomChat = () => { 32 return { 33 load: () => { 34 window.intercomSettings = { 35 app_id: '59ce49521a05735d313f192d2afd0c3976ab26f6', 36 alignment: 'right', 37 }; 38 39 loadIntercomScript(); 40 }, 41 }; 42 }; 43 44 /** 45 * Set and load the intercom script for website prospects (non-customers). 46 * ChatKit is retired; this replaces the old prospectChat()/disabledProspectChat() 47 * pair. The `audience: 'website_prospect'` custom attribute is the contract 48 * with the Convert Assistant backend (assistant2/agent): any Intercom 49 * conversation whose contact carries this attribute is routed to the AI 50 * prospect agent instead of normal support triage. Conversations without it 51 * (i.e. customers, via intercomChat() above) keep going through Intercom's 52 * usual routing. 53 * 54 * Consent note: this reuses whatever gate (or lack of one) already applies 55 * to the caller today - see loadInPage()/loadInPage404() below - so 56 * prospects get neither more nor less consent gating than the ChatKit 57 * widget they replace. Flagged for legal review since an AI agent chatting 58 * with a prospect is a new capability even though the load-timing behavior 59 * itself is unchanged by this swap. 60 * @returns {Object} Return a list of public methods. 61 */ 62 const prospectIntercomChat = () => { 63 return { 64 load: () => { 65 window.intercomSettings = { 66 app_id: '59ce49521a05735d313f192d2afd0c3976ab26f6', 67 alignment: 'right', 68 audience: 'website_prospect', 69 }; 70 71 loadIntercomScript(); 72 }, 73 }; 74 }; 75 76 /** 77 * Set and load the Chatwood script. 78 * @returns {Object} Return a list of public methods. 79 */ 80 const chatWoot = () => { 81 const BASE_URL = 'https://app.chatwoot.com'; 82 return { 83 load: (customerStatus) => { 84 const g = document.createElement('script'); 85 const s = document.getElementsByTagName('script')[0]; 86 g.src = `${BASE_URL}/packs/js/sdk.js`; 87 g.defer = true; 88 g.async = true; 89 s.parentNode.insertBefore(g, s); 90 g.onload = () => { 91 window.chatwootSDK.run({ 92 websiteToken: 'yoo5yRWejZoDx81bdp9tMzBa', 93 baseUrl: BASE_URL, 94 }); 95 96 const chatStatus = setInterval(() => { 97 if (window.$chatwoot.hasLoaded) { 98 if (customerStatus === 'Customer') { 99 window.$chatwoot.setCustomAttributes({ 100 customer_status: customerStatus, 101 }); 102 } 103 clearInterval(chatStatus); 104 } 105 }, 1000); 106 }; 107 }, 108 }; 109 }; 110 111 /** 112 * Load a chat support when user scrolls down. 113 * @param {function} chat - The chat to be loaded. 114 * @param {number} [delay] - Value in ms to delay the chat. 115 */ 116 const loadChatInScroll = (chat, delay = null) => { 117 const onScroll = (event) => { 118 const loadChat = () => { 119 chat().load(); 120 event.currentTarget.removeEventListener(event.type, onScroll); 121 }; 122 123 if (window.pageYOffset > window.innerHeight) { 124 delay 125 ? setTimeout(() => { 126 loadChat(); 127 }, delay) 128 : loadChat(); 129 } 130 }; 131 132 window.addEventListener('scroll', onScroll); 133 }; 134 135 /** 136 * Delay the Loading of the chat support 137 * @param {function} chat - The chat to be loaded. 138 * @param {number} [delay] - Value in ms to delay the chat. 139 */ 140 const delayLoadChat = (chat, delay = null) => { 141 setTimeout(() => { 142 chat().load(); 143 }, delay); 144 }; 145 146 /** 147 * Use the IntersectionObserver API to perform an action when 148 * the user reaches to the target element. 149 * @param {object} element - The DOM element used as a target 150 * @param {requestCallback} callbackfn - Run when user reaches the target element 151 */ 152 const setIntersectionObserver = (element, callbackfn) => { 153 const io = new IntersectionObserver((entries, observer) => {
154 entries.forEach((entry) => { 155 if (entry.isIntersecting) { 156 callbackfn(); 157 observer.disconnect(); 158 } 159 }); 160 }); 161 162 io.observe(element); 163 }; 164 165 /** 166 * 167 * @param {object} target - DOM Element used as a target 168 * @param {function} chat - The chat to be loaded 169 */ 170 const loadChatInIntersectionObserver = (target, chat) => { 171 setIntersectionObserver(target, chat().load); 172 }; 173 174 // 175 // Public Methods 176 // 177 178 publicMethods.isCookieControlCompliant = () => { 179 const status = typeof CookieControl !== 'undefined'; 180 return status ? CookieControl.getCookie('CookieControl') : false; 181 }; 182 183 publicMethods.isChatAllowedOnThePage = () => { 184 const dataLivechatStatus = document.querySelector('[data-livechat-status]'); 185 return dataLivechatStatus ? dataLivechatStatus.dataset.livechatStatus : true; 186 }; 187 188 /** 189 * 190 * Set how the chat support will be load in particular URLs 191 * @returns {function} Function to be executed depending on the URL 192 */ 193 publicMethods.loadInPage = () => { 194 const pathName = window.location.pathname; 195 const removeSlashFromPathName = pathName.slice(1, -1); 196 const urlWithUnderscore = removeSlashFromPathName.replace(/-/gi, '_'); 197 const pages = { 198 thank_you_convert_ab_testing_tools_comparison() { 199 getConvertUserStatus().then((response) => { 200 response.status === 'Customer' 201 ? loadChatInScroll(intercomChat, 60000) 202 : loadChatInScroll(prospectIntercomChat, 60000); 203 }); 204 }, 205 demo_on_demand_thank_you() { 206 getConvertUserStatus().then((response) => { 207 const ctaLiveChat = document.getElementById('openLiveChat'); 208 response.status === 'Customer' 209 ? loadChatInIntersectionObserver(ctaLiveChat, intercomChat) 210 : loadChatInIntersectionObserver(ctaLiveChat, prospectIntercomChat); 211 }); 212 }, 213 compare_convert_monthly_plans() { 214 getConvertUserStatus().then((response) => { 215 response.status === 'Customer' 216 ? delayLoadChat(intercomChat, 25000) 217 : delayLoadChat(prospectIntercomChat, 25000); 218 }); 219 }, 220 hypothesis_generator() { 221 getConvertUserStatus().then((response) => { 222 chatWoot().load(response.status); 223 }); 224 }, 225 default() { 226 getConvertUserStatus().then((response) => { 227 response.status === 'Customer' ? intercomChat().load() : prospectIntercomChat().load(); 228 }); 229 }, 230 }; 231 232 return pages[urlWithUnderscore] || pages.default; 233 }; 234 235 publicMethods.loadInPage404 = () => { 236 getConvertUserStatus().then((user) => { 237 user.status === 'Customer' ? intercomChat().load() : prospectIntercomChat().load(); 238 }); 239 }; 240 241 /** 242 * Return the value of a query string specified from the current URL visited by the user. 243 * @param {string} queryString - Name of the query string to search 244 */ 245 publicMethods.getQueryString = (queryString) => { 246 const formatQueryString = new URLSearchParams(window.location.search); 247 return formatQueryString.get(queryString); 248 }; 249 250 return publicMethods; 251}; 252 253const ischatAllowed = chatSupport().isChatAllowedOnThePage(); 254const chat = chatSupport().loadInPage(); 255 256if (ischatAllowed === true) { 257 const initScriptOnScroll = (event) => { 258 if (chatSupport().isCookieControlCompliant()) { 259 chat(); 260 event.currentTarget.removeEventListener(event.type, initScriptOnScroll); 261 } 262 }; 263 264 document.addEventListener('scroll', initScriptOnScroll); 265}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.