All files tcf.js

72.5% Statements 29/40
50% Branches 10/20
60% Functions 6/10
80% Lines 28/35

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            1x           1x           1x           1x           1x   4x 4x     4x 4x       4x               1x 3x         1x                   1x                         1x 3x                   1x                                   4x         3x   3x 1x 1x     2x 2x   2x   2x       2x 2x          
import analytics from './index'
 
/**
 * TCF Api Version to use
 * @type {number}
 */
const TCF_API_VERSION = 2
 
/**
 * List of purpose ids needed to be able to track with all info
 * @type {Array<number>}
 */
const NEEDED_PURPOSES = [8, 10]
 
/**
 * Event that determines that the user has performed an action
 * @type {string}
 */
const TCF_EVENT_USER_ACTION_COMPLETE = 'useractioncomplete'
 
/**
 * Event that determines that the user is seeing the UI to give consent
 * @type {string}
 */
const TCF_EVENT_SHOW_UI = 'cmpuishown'
 
/**
 * 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 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}`])
 
/**
 * State of user according to GDPR regarding tracking
 */
const USER_GDPR = {
  ACCEPTED: 'ACCEPTED',
  DECLINED: 'DECLINED',
  UNKNOWN: 'UNKNOWN'
}
 
/**
 * Events info according
 * @type {{ [event: string]: [gdprValue: string, eventId: string]}}
 */
const EVENT_INFO = {
  [USER_GDPR.ACCEPTED]: ['Privacy Accepted', 'accepted'],
  [USER_GDPR.DECLINED]: ['Privacy Declined', 'declined'],
  [USER_GDPR.UNKNOWN]: ['Privacy Impression', 'declined']
}
 
/**
 * Track a specific TCF event
 * @param {object} params
 * @param {string} params.eventId
 * @param {string} params.gdprValue
 * @return {Promise}
 */
const trackTcf = ({eventId, gdprValue}) =>
  analytics.track('Event Fired', {
    channel: 'GDPR',
    event_id: eventId,
    gdpr_privacy: gdprValue
  })
 
/**
 * 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)
      })
    })
  })
}
 
/**
 * 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 (eventStatus === TCF_EVENT_SHOW_UI) {
          const [eventId, gdprValue] = EVENT_INFO.UNKNOWN
          return trackTcf({eventId, gdprValue})
        }
 
        Eif (eventStatus === TCF_EVENT_USER_ACTION_COMPLETE) {
          const {consents} = purpose
 
          const hasConsents = checkHasUserConsentedTracking(consents)
 
          const userGdprState = hasConsents
            ? USER_GDPR.ACCEPTED
            : USER_GDPR.DECLINED
 
          const [eventId, gdprValue] = EVENT_INFO[userGdprState]
          return trackTcf({eventId, gdprValue})
        }
      }
    )
}