PageSourceSearch

https://conda-capital.com/wp-content/plugins/investment-desk/publi…/user-tracking.js?ver=1.0.0.2517-1791569474

js conda-capital.com collected 2026-10-09 18:13:46 UTC 5,815 bytes, 185 lines download raw bytes

1const visitPages = [
2    {
3        path: '/',
4        event: 'visit_homepage',
5    },
6    {
7        path: '/wallet/',
8        event: 'visit_wallet',
9    },
10    {
11        path: '/investorenkonto/',
12        event: 'visit_account_overview',
13    },
14    {
15        path: '/order/',
16        event: 'visit_orders',
17    },
18]
19
20const getUserType = () => {
21    const cookie = document.cookie
22    const user_account = cookie.split('conda_user_profile=')[1].split(';')[0]
23    return user_account
24}
25
26const getUserToken = () => {
27    const cookie = document.cookie
28    const user_token = cookie.split('conda_user_token=')[1].split(';')[0]
29    return user_token
30}
31
32document.addEventListener('DOMContentLoaded', () => {
33    setTimeout(async () => {
34        sendEventOnPageVisit()
35        if (window.location.pathname.includes('/campaign/') && !window.location.pathname.includes('investieren')) {
36            sendReadFullCampaignEvent()
37            sendEventOnCampaignTabChange()
38            sendEventOnContactDetailsClick()
39        }
40    }, 1000)
41})
42
43// Events
44const sendEventOnPageVisit = () => {
45    const requestBody = {
46        event: '',
47        data: {},
48    }
49    const pathname = window.location.pathname
50
51    const campaignMatch = pathname.match(/^\/campaign\/([^/]+)\/?$/)
52    if (campaignMatch) {
53        requestBody.event = 'visit_campaign'
54        requestBody.data = { campaign_id: window.campaign.asset_data.asset_var_uid }
55        sendEvent(requestBody)
56    } else {
57        if (visitPages.find((page) => page.path === pathname)) {
58            const page = visitPages.find((page) => page.path === pathname)
59            requestBody.event = page.event
60            sendEvent(requestBody)
61        }
62    }
63}
64
65const sendEventOnContactDetailsClick = () => {
66    const companyEmail = document.getElementById('company-email')
67    if (companyEmail) {
68        console.log('companyEmail', companyEmail)
69        companyEmail.addEventListener('click', () => {
70            sendEvent({
71                event: 'contact_details_click',
72                data: { campaign_id: window.campaign.asset_data.asset_var_uid, contact_detail: 'email' },
73            })
74        })
75    }
76
77    const companyPhone = document.getElementById('company-phone')
78    if (companyPhone) {
79        console.log('companyPhone', companyPhone)
80        companyPhone.addEventListener('click', () => {
81            sendEvent({
82                event: 'contact_details_click',
83                data: { campaign_id: window.campaign.asset_data.asset_var_uid, contact_detail: 'phone' },
84            })
85        })
86    }
87}
88
89const sendReadFullCampaignEvent = () => {
90    const main = document.querySelector('main')
91    if (!main) return
92
93    const requestBody = {
94        event: 'read_full_campaign',
95        data: { campaign_id: window.campaign.asset_data.asset_var_uid },
96    }
97
98    let fired = false
99    const segmentPx = 120 // pick a value between 100 and 150
100
101    const tryFire = async () => {
102        if (fired) return
103        if (isLastSegmentInView(main, segmentPx)) {
104            fired = true
105            window.removeEventListener('scroll', onScroll, { passive: true })
106            window.removeEventListener('resize', onResize)
107            sendEvent(requestBody)
108        }
109    }
110
111    const onScroll = () => tryFire()
112    const onResize = () => tryFire()
113
114    // Initial check and then listen
115    tryFire()
116    if (!fired) {
117        window.addEventListener('scroll', onScroll, { passive: true })
118        window.addEventListener('resize', onResize)
119    }
120}
121
122const sendEventOnCampaignTabChange = () => {
123    const requestBody = {
124        event: 'campaign_tab_change',
125        data: { campaign_id: window.campaign.asset_data.asset_var_uid, tab: '' },
126    }
127    const campaignTabs = document.querySelectorAll('.single-campaign-tabs > li')
128
129    if (!campaignTabs || campaignTabs.length === 0) return
130
131    const observer = new MutationObserver(async (mutationsList) => {
132        for (const mutation of mutationsList) {
133            if (
134                mutation.type === 'attributes' &&
135                mutation.attributeName === 'class' &&
136                mutation.target.classList.contains('active')
137            ) {
138                requestBody.payload.tab = mutation.target.getAttribute('data-target-tab')
139                sendEvent(requestBody)
140            }
141        }
142    })
143
144    campaignTabs.forEach((tab) => {
145        observer.observe(tab, { attributes: true })
146    })
147}
148
149// Helpers
150const isLastSegmentInView = (element, segmentPx) => {
151    const rect = element.getBoundingClientRect()
152    const viewportHeight = window.innerHeight || document.documentElement.clientHeight
153
154    // Element not in viewport at all
155    if (rect.bottom < 0 || rect.top > viewportHeight) return false
156
157    // Bottom of element lies within the bottom `segmentPx` of viewport
158    const bottomWithinSegment = rect.bottom <= viewportHeight && rect.bottom >= viewportHeight - segmentPx
159
160    // Ensure at least some of that bottom segment is visible
161    const elementHeight = rect.height
162    const segmentTop = rect.bottom - segmentPx
163    const visibleSegmentTop = Math.max(segmentTop, 0)
164    const visibleSegmentHeight = rect.bottom - visibleSegmentTop
165
166    return bottomWithinSegment && visibleSegmentHeight > 0 && elementHeight >= segmentPx
167}
168
169const sendEvent = async (requestBody) => {
170    const body = {
171        ...requestBody,
172        platform_name: window.platformSettings.platform_name,
173        trackable_type: getUserType(),
174    }
175    const baseUrl = window.condaApiEndpoint
176    await fetch(`${baseUrl.replace(/\/?$/, '/')}user-tracking/`, {
177        method: 'POST',
178        headers: {
179            'Content-Type': 'application/json',
180            'Accept': 'application/json',
181            'Authorization': `Bearer ${getUserToken()}`,
182        },
183        body: JSON.stringify(body),
184    })
185}

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.