PageSourceSearch

https://www.myboost.co.nz/wp-content/themes/boost/assets/js/boost.js?v=1790257333

js myboost.co.nz collected 2026-09-24 13:42:30 UTC 16,672 bytes, 485 lines download raw bytes

1/* var $zoho=$zoho || {};
2$zoho.salesiq = $zoho.salesiq || {widgetcode:"013cd641be142742b2e56300a053cd36d2fcbb2f2e0660142780e5a1b9a70066", values:{},ready:function(){}}; */
3/* s.type="text/javascript";s.id="zsiqscript";s.defer=true;s.src="https://salesiq.zoho.com/widget";t.parentNode.insertBefore(s,t);d.write("<div id='zsiqwidget'></div>"); */
4let API_ENV = ''
5
6let boostSubDomain = ''
7switch (window.location.host.split('.')[0]) {
8    case 'myboost':
9    case 'www':
10    case '20221117-staging':
11        API_ENV = '/master/'
12        boostSubDomain = 'boost'
13        break
14    case 'test':
15        boostSubDomain = 'staging'
16        API_ENV = '/develop/'
17        break
18}
19
20const boostBaseUrl = 'https://' + boostSubDomain + '.myboost.co.nz'
21
22const dashboardUrl = boostBaseUrl + '/profile/dashboard'
23const profileUrl = boostBaseUrl + '/profile'
24const offersUrl = boostBaseUrl + '/offers'
25const changePasswordUrl = boostBaseUrl + '/profile/change-password'
26const preferencesUrl = boostBaseUrl + '/profile/preferences'
27
28// eslint-disable-next-line no-unused-vars
29const exports = {}
30const apiScript = document.createElement('script')
31apiScript.src = 'https://boost-js-lib.s3-ap-southeast-2.amazonaws.com' + API_ENV + 'api.js'
32const firstScriptNode = document.getElementsByTagName('script')[0]
33firstScriptNode.parentNode.insertBefore(apiScript, firstScriptNode)
34
35let userIsLoggedIn = false
36
37// eslint-disable-next-line no-unused-vars
38function consoleLog(info) {
39    if (API_ENV === '/develop/') {
40        if (typeof info === 'object') {
41            info.forEach(function (a) {
42                console.log(a)
43            })
44        } else {
45            console.log('Log: ' + info)
46        }
47    } else {
48        return false
49    }
50}
51
52(function () {
53    const currUrl = window.location.href
54    // eslint-disable-next-line no-undef
55    let boostApi = null
56
57    const setBoostCookie = cookie => {
58        document.cookie = 'boost=' + JSON.stringify(cookie) + ';path=/;domain=myboost.co.nz'
59    }
60
61    const getBoostCookie =  _ => {
62        const cookieVal = document.cookie.match('(^|[^;]+)\\s*boost\\s*=\\s*([^;]+)')
63        return cookieVal ? cookieVal.pop() : ''
64    }
65
66    const deleteLocalStorage = function () { // Delete cookie when logging out
67        document.cookie = 'boost= ; expires = Thu, 01 Jan 1970 00:00:00 GMT;path =/;domain=.myboost.co.nz;'
68        localStorage.removeItem('boost')
69    }
70
71    const handleLoginFail = function () {
72
73    }
74
75    const getUserRoles = function (roles) {
76        // roles is an array of roles which will contain 'myboost.co.nz BP' and/or 'myboost.co.nz BP' (or be empty)
77        if (!Array.isArray(roles)) {
78            roles = []
79        }
80
81        return {
82            bp: roles.indexOf('myboost.co.nz BP') !== -1,
83            su: roles.indexOf('myboost.co.nz SU') !== -1
84        }
85    }
86
87    const dropdownCheckRole = function (roles) {
88        const roleMap = getUserRoles(roles)
89
90        if (!roleMap.bp) { // if np BP role, hide dashboard
91            document.querySelectorAll('.user-menu-dashboard').forEach(el => {
92                const menuContainer = el.parentNode.parentNode
93                menuContainer.removeChild(el.parentNode)
94
95                // the next link now gets the dashboard style
96                const newFirstLink = menuContainer.querySelector('a')
97                newFirstLink.parentNode.classList.add('dashboard-container')
98                newFirstLink.classList.add('btn')
99                newFirstLink.classList.add('btn-primary')
100                newFirstLink.classList.add('btn-sm')
101            })
102        }
103        if (!roleMap.su) { // if no su rule, hide offers
104            document.querySelectorAll('.user-menu-offers').forEach(el => {
105                el.parentNode.parentNode.removeChild(el.parentNode)
106            })
107        }
108    }
109
110    const handleRedirect = function (profile) {
111        const roles = profile.roles
112        const isSignIn = currUrl.indexOf('/sign-in') !== -1
113        const isReferrer = currUrl.indexOf('referrer=') !== -1
114
115        if (isSignIn && isReferrer) {
116            const ref = currUrl.split('?referrer=/')[1]
117            const redirect = 'https://' + boostSubDomain + '.myboost.co.nz/' + ref
118            window.location.replace(redirect)
119        } else {
120            const roleMap = getUserRoles(roles)
121
122            if (roleMap.bp) {
123                window.location.replace(dashboardUrl)
124            } else {
125                window.location.replace(offersUrl)
126            }
127        }
128    }
129
130    const updateApiVersionDisplay = version => {
131        document.getElementById('boost-api-code-display').textContent = version
132    }
133
134    const activateCardContainers = [
135        document.getElementById('nav-activate-container')
136    ]
137
138    const anonymousNavPanels = [
139        document.getElementById('nav-user-anonymous-panel'),
140    ]
141
142    const mobileNavUserPanelId = 'mobile-nav-user-authenticated-panel'
143
144    const mobileNavUserPanel = document.getElementById(mobileNavUserPanelId)
145
146    const authenticatedNavPanels = [
147        document.getElementById('nav-user-authenticated-panel'),
148        mobileNavUserPanel
149    ]
150
151    const firstNameContainers = [
152        document.getElementById('nav-user-name'),
153        document.getElementById('mobile-nav-user-name')
154    ]
155
156    const nameDisplays = firstNameContainers.map(c => c.querySelector('.name-display'))
157
158    const hideElement = el => el.style.display = 'none'
159    const showElement = el => el.style.display = 'block'
160
161    const hideElements = els =>
161 els.forEach(hideElement)
162    const showElements = els => els.forEach(showElement)
163
164    const disableUserPanels = panelEls => {
165        panelEls.forEach(panelEl => {
166            panelEl.classList.remove('nav-user-panel')
167            panelEl.style.display = 'none'
168        })
169    }
170
171    const enableUserPanels = panelEls => {
172        panelEls.forEach(panelEl => {
173            if(panelEl.id !== mobileNavUserPanelId) {
174                panelEl.classList.add('nav-user-panel')
175            }
176        })
177    }
178
179    // shortcuts to generate the right CSS display style for showing/hiding for roles
180    const showForBp = roleMap => roleMap.bp ? 'block' : 'none'
181    const showForSu = roleMap => roleMap.su ? 'block' : 'none'
182
183    const setUpAuthenticatedNavPanelForRole = roleMap => {
184        showElements([mobileNavUserPanel])
185        // hide and show links based on the user role, and update their hrefs to the right domain
186        authenticatedNavPanels.forEach(authenticatedNavPanel => {
187            const dashboardLink = authenticatedNavPanel.querySelector('.user-menu-dashboard')
188            dashboardLink.parentElement.style.display = showForBp(roleMap)
189            dashboardLink.setAttribute('href', dashboardUrl)
190
191            const profileLink = authenticatedNavPanel.querySelector('.user-menu-profile')
192            profileLink.setAttribute('href', profileUrl)
193
194            const offersLink = authenticatedNavPanel.querySelector('.user-menu-offers')
195            offersLink.parentElement.style.display = showForSu(roleMap)
196            offersLink.setAttribute('href', offersUrl)
197
198            const changePasswordLink = authenticatedNavPanel.querySelector('.user-menu-change-password')
199            changePasswordLink.setAttribute('href', changePasswordLink)
200
201            const preferencesLink = authenticatedNavPanel.querySelector('.user-menu-preferences')
202            preferencesLink.setAttribute('href', preferencesUrl)
203        })
204    }
205
206    const setUpLoggedInState = (userFirstName, roleMap) => {
207        hideElements(activateCardContainers)
208        disableUserPanels(anonymousNavPanels)
209        enableUserPanels(authenticatedNavPanels)
210
211        document.querySelectorAll('.signed-in-hidden').forEach(hideElement)
212
213        showElements(firstNameContainers)
214
215        let nameContent
216
217        if (userFirstName !== '' && userFirstName != null) {
218            // 'Hi' is already in the element, so this will make 'Hi, <name>'
219            nameContent = ', ' + userFirstName
220        } else {
221            nameContent = ''
222        }
223
224        nameDisplays.forEach(nameDisplay => {
225            nameDisplay.textContent = nameContent
226        })
227
228        setUpAuthenticatedNavPanelForRole(roleMap)
229
230        const desktopNavMenu = document.querySelector('.nav-menu')
231        const mobileNavMenu = document.querySelector('.mobile-nav-menu')
232
233        const menus = [desktopNavMenu, mobileNavMenu]
234
235        menus.forEach(menu => {
236            const offersLink = menu.querySelector('a[href*="/offers"]')
237            offersLink.setAttribute('href', offersUrl)
238            if (roleMap.bp) {
239                offersLink.parentNode.parentNode.removeChild(offersLink.parentNode)
240            }
241        })
242
243        userIsLoggedIn = true
244    }
245
246    const getToken = _ => {
247        const serializedToken = getBoostCookie().split(',path')[0] // Check if user is logged in
248        if (serializedToken == null || serializedToken === '' || serializedToken === ' ') {
249            return null
250        }
251
252        return JSON.parse(serializedToken)
253    }
254
255    const fetchProfileAndSetUpLoggedInState = (accessToken, doRedirect) => {
256        document.querySelector('.nav-menu a[href*="/offers"]').setAttribute('href', offersUrl) // point offers link to logged in offers
257
258        boostApi.profile.get(accessToken).then(profile => {
259            const roles = profile.roles
260            const firstName = profile.firstName
261
262            setUpLoggedInState(firstName, getUserRoles(roles))
263
264            dropdownCheckRole(roles)
265            if (currUrl.indexOf('myboost.co.nz/sign-in') !== -1 || doRedirect)
266                handleRedirect(profile)
267        })
268    }
269
270    const handleValidate = function () {
271        const token = getToken()
272        if (token == null || token.access_token == null) {
273            handleLoginFail()
274            return false
275        }
276
277        const accessToken = token.access_token
278        const expiresIn = token.expires_in
279        const refreshToken = token.refresh_token
280        const tokenTime = token.time
281        const currentTime = Math.floor(Date.now() / 1000)
282        boostApi.auth.validate(accessToken).then(function (res) {
283            updateApiVersionDisplay(!res.apiVersion || res.apiVersion === '' ? 'none' : res.apiVersion)
284            if (currentTime - tokenTime >
284 expiresIn) { // if current time minus time is greater than expiry then request refreshToken
285                boostApi.auth.refresh({
286                    token: ''.concat(refreshToken),
287                    scope: 'website',
288                    device: ''
289                }).then(function (res) { // get new accessToken and refreshToken
290                    if (res && res.access_token) {
291                        const newToken = token
292
293                        newToken.access_token = res.access_token
294                        newToken.refresh_token = res.refresh_token
295                        setBoostCookie(newToken)
296                        fetchProfileAndSetUpLoggedInState(newToken.access_token, false)
297                    } else {
298                        handleLoginFail()
299                        deleteLocalStorage()
300                    }
301                })
302            } else {
303                if (res && res.data.email) {
304                    fetchProfileAndSetUpLoggedInState(accessToken, false)
305
306                } else {
307                    handleLoginFail()
308                    deleteLocalStorage()
309                }
310            }
311        })
312    }
313
314    const doLogin = (form, failureCallback) => {
315        if(userIsLoggedIn) {
316            // password managers (like DashLane?) might be submitting the login form when the user is already logged in
317            return;
318        }
319        const emailField = form.querySelector("input[type='text']")
320        const passwordField = form.querySelector("input[type='password']")
321
322        const email = emailField.value
323
324        if (email === '' || email === null) {
325            alert('Please enter your email address.')
326            return
327        }
328
329        const password = passwordField.value
330
331        if (password === '' || password == null) {
332            alert('Please enter your password.')
333            return
334        }
335
336        const credentials = {
337            Username: email,
338            Password: password,
339            Scope: 'website'
340        }
341
342        boostApi.auth.login(credentials).then(res => {
343            if (!res || res.code || !res.access_token || !res.refresh_token) {
344                alert('Login failed. ' + res.message)
345                if (failureCallback) {
346                    failureCallback()
347                }
348                return
349            }
350
351            res.time = Math.floor(Date.now() / 1000)
352            setBoostCookie(res)
353
354            fetchProfileAndSetUpLoggedInState(res.access_token, true);
355        })
356    }
357
358    const doLogout = _ => {
359        if (!confirm('Are you sure you want to sign out?')) {
360            return
361        }
362
363        boostApi.auth.logout(token).then(function (res) {
364            deleteLocalStorage()
365            userIsLoggedIn = false
366            location.reload()
367        })
368    }
369
370    const setUpListeners = function () {
371        // set up the javascript event handlers that override default functionality
372        const signInForms = document.querySelectorAll('.nav-sign-in-form')
373        signInForms.forEach(signInForm => {
374            signInForm.addEventListener('submit', e => {
375                e.preventDefault()
376                doLogin(signInForm)
377                return false
378            })
379        })
380
381        authenticatedNavPanels.forEach(authenticatedNavPanel => {
382            const signOutButton = authenticatedNavPanel.querySelector('.user-menu-signout')
383            signOutButton.addEventListener('click', e => {
384                e.preventDefault()
385                doLogout()
386                return false;
387            })
388        })
389
390        try {
391            let ci = 0;
392            let kc = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65, 13];
393
394            document.addEventListener('keyup', e => {
395                if (e.which === kc[ci++]) {
396                    if (ci === kc.length) {
397                        document.querySelectorAll('.nav-logo img').forEach(logo => logo.style.transform = 'rotate(180deg)')
398                        ci = 0
399                    }
400                } else {
401                    ci = 0
402                }
403            });
404        } catch (e) {}
405    }
406
407    const setUp = () => {
408        setUpListeners()
409        handleValidate()
410    }
411
412    let apiCheckCount = 0
413
414    const apiCheck = setInterval(() => {
415        // The Boost API client is included in a different JS file which loads at the same time as this file, so
416        // window.api might not be ready in time. This loops until it's loaded (or errors if it takes too long).
417        if (window.api) {
418            boostApi = window.api
419            clearInterval(apiCheck)
420            setUp()
421            return
422        }
423
424        if (apiCheckCount++ === 100) {
425            clearInterval(apiCheck)
426            console.error('Loading API timed out')
427        }
428
429    }, 100)
430
431    window.doBoostLogin = doLogin
432})()
433
434const regexCount = (expression, s) => {
435    return ((s || '').match(expression) || []).length
436}
437
438
439window.boostValidatePassword = password => {
440    password = password || ''
441    const lowerCaseCount = regexCount(/[a-z]/g, password)
442    const upperCaseCount = regexCount(/[A-Z]/g, password)
443    const numberCount = regexCount(/[0-9]/g, password)
444
445    // all other characters must be symbols
446    const symbolCount = password.length - lowerCaseCount - upperCaseCount - numberCount
447
448    const score = (lowerCaseCount >= 1) + (upperCaseCount >= 1)  + (numberCount >= 1) + (symbolCount >= 1)
449
450    const valid = score >= 2 && password.length >= 8
451
452    if (!valid)
453        alert(
454            'Passwords must have at least 8 characters and contain at least two of each of the following: ' +
455            'uppercase letters, lowercase letters, numbers, and symbols.'
456        );
457
458    return valid
459}
460
461window.setFullscreenSpinnerVisible = isVisible => {
462    if (window.boostOverlay) {
463        if (isVisible) {
464            // should already be visible so do nothing
465            return
466        }
467
468        // remove it
469        window.boostOverlay.parentNode.removeChild(window.boostOverlay);
470        window.boostOverlay = null
471        return
472    }
473
474    if (!isVisible) {
475        return // no window.boostOverlay and we don't want it visible so return
476    }
477
478    const overlay = document.createElement('div');
479    overlay.classList.add('spinner-overlay')
480
481    overlay.innerHTML = '<div class="lds-ripple"><div></div><div></div></div>'
482
483    document.body.appendChild(overlay);
484    window.boostOverlay = overlay
485}

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.