PageSourceSearch

https://www.convert.com/wp-content/themes/olympus/js/chat-support.js?ver=1790788470

js convert.com collected 2026-10-01 08:32:34 UTC 8,435 bytes, 265 lines download raw bytes

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.