Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | 5x 5x 5x 5x 5x 5x 5x 19x 3x 3x 5x 6x 6x 6x 6x 6x 5x 5x 5x 4x 5x 5x 19x 19x 5x 6x 4x 4x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x | import analytics from './segmentWrapper' /** * TCF Api Version to use * @type {number} */ const TCF_API_VERSION = 2 /** * Default properties to send with every TCF tracking event */ const TCF_TRACK_PROPERTIES = { channel: 'GDPR' } /** * List of purpose ids needed to be able to track with all info * @type {Array<number>} */ const NEEDED_PURPOSES = [8, 10] /** * TCF events */ const TCF_EVENTS = { // Event that determines that the tcData has been loaded LOADED: 'tcloaded', // Event that determines that the user has performed an action USER_ACTION_COMPLETE: 'useractioncomplete', // Event that determines that the user is seeing the UI to give consent UI_SHOWN: 'cmpuishown' } /** * State of user according to GDPR regarding tracking */ const USER_GDPR = { ACCEPTED: 'accepted', DECLINED: 'declined', UNKNOWN: 'unknown' } /** * Events info according * @type {{ [event: string]: [eventId: string, gdprValue: string]}} */ const EVENT_INFO = { [USER_GDPR.ACCEPTED]: ['Privacy Accepted', USER_GDPR.ACCEPTED], [USER_GDPR.DECLINED]: ['Privacy Declined', USER_GDPR.DECLINED], [USER_GDPR.UNKNOWN]: ['Privacy Impression', USER_GDPR.UNKNOWN] } /** * Define the user GDPR consents state. This value will be updated with new values * when the consents of the users changes. */ const gdprState = { _onChange: value => {}, value: USER_GDPR.UNKNOWN, onChange: callback => (gdprState._onChange = callback), get: () => gdprState.value, set: value => { gdprState.value = value gdprState._onChange(value) } } /** * Check if we're on client and tcfApi is available on window object * @returns {Boolean} */ const checkTcfIsAvailable = () => { // first check if we're on server, as this doesn't work on server-side const isClient = typeof window !== 'undefined' Iif (!isClient) return false // if we're on client, check if we have the tcfapi available const isTcfApiAvailable = !!window.__tcfapi !isTcfApiAvailable && console.warn( "[tcfTracking] window.__tcfapi is not available on client and TCF won't be tracked." ) return isTcfApiAvailable } /** * Check from a list of consents if user has accepted being tracked * @param {{[purposeId: string]: boolean}} userConsents * @returns {Boolean} */ const checkHasUserConsentedTracking = userConsents => NEEDED_PURPOSES.every(purposeId => userConsents[`${purposeId}`]) /** * Track a specific TCF event * @param {object} params * @param {string} params.eventId Event ID to be sent with the TCF Tracking * @param {string} params.gdprPrivacy Send a string telling if the gdpr has been accepted or reject * @return {Promise} */ const trackTcf = ({eventId, gdprPrivacy}) => analytics.track( 'Event Fired', { ...TCF_TRACK_PROPERTIES, event_id: eventId }, { gdpr_privacy: gdprPrivacy } ) /** * Check if DMP is consented by the user using boros API * @return {Promise<boolean>} */ export const checkIsDMPReady = () => { return new Promise(resolve => { if (typeof window === 'undefined') return resolve() if (window.__borosTcf === undefined) return resolve() window.__borosTcf.push(api => { api('isDmpAccepted', ({success, value}) => { const isDMPReady = success && value return resolve(isDMPReady) }) }) }) } /** * Get if we have user consents * @return {Promise<string>} */ export const getGdprPrivacyValue = () => { // try to get the actual gdprPrivacyValue and just return it const gdprPrivacyValue = gdprState.get() return Promise.resolve(gdprPrivacyValue) // TODO: Disabled for now. It will be added on the next iteration // if (gdprPrivacyValue !== undefined) return Promise.resolve(gdprPrivacyValue) // // if we don't have a gdprPrivacyValue, then subscribe to it until we have a value // return new Promise(resolve => { // gdprPrivacyValueState.onChange = gdprPrivacyValue => // resolve(gdprPrivacyValue) // }) } /** * Check if gdprPrivacyValue is accepted * @return {boolean} */ export const checkGdprIsAccepted = gdprPrivacyValue => gdprPrivacyValue === USER_GDPR.ACCEPTED /** * Init TCF Tracking User Consents with Segment */ export default function initTcfTracking() { checkTcfIsAvailable() && window.__tcfapi( 'addEventListener', TCF_API_VERSION, ({eventStatus, purpose}, success) => { Iif (!success) return Promise.resolve() // if CMP UI is shown then we only have to track that and do nothing more if (eventStatus === TCF_EVENTS.UI_SHOWN) { const [eventId, gdprPrivacy] = EVENT_INFO[USER_GDPR.UNKNOWN] return trackTcf({eventId, gdprPrivacy}) } // if we've already user consents or the user is accepting or declining now // we change the state of the GDPR to use in our tracking Eif ( eventStatus === TCF_EVENTS.USER_ACTION_COMPLETE || eventStatus === TCF_EVENTS.LOADED ) { const {consents} = purpose const hasConsents = checkHasUserConsentedTracking(consents) // get the state key according to the gdprPrivacyValue const gdprStateKey = hasConsents ? USER_GDPR.ACCEPTED : USER_GDPR.DECLINED gdprState.set(gdprStateKey) // if it's an user action, then we will track it Eif (eventStatus === TCF_EVENTS.USER_ACTION_COMPLETE) { // extract the eventId and gdprPrivacy string to send with the track const [eventId, gdprPrivacy] = EVENT_INFO[gdprStateKey] return trackTcf({eventId, gdprPrivacy}) } } } ) } |