@folklore/tracking
Advanced tools
Comparing version 0.0.20 to 0.0.21
143
dist/cjs.js
@@ -5,2 +5,3 @@ 'use strict'; | ||
var uuid = require('uuid'); | ||
var React = require('react'); | ||
@@ -16,3 +17,2 @@ var jsxRuntime = require('react/jsx-runtime'); | ||
/* eslint-disable class-methods-use-this */ | ||
class Tracking { | ||
@@ -59,3 +59,3 @@ constructor() { | ||
if (!paused && this.pending.length > 0) { | ||
this.push(...this.pending); | ||
this.pushNow(...this.pending); | ||
this.pending = []; | ||
@@ -74,19 +74,19 @@ } | ||
push() { | ||
const { | ||
dataLayer = null | ||
} = this.options; | ||
if (dataLayer === null || this.disabled) { | ||
return; | ||
} | ||
if (this.paused) { | ||
if (this.paused && !this.disabled) { | ||
this.pending.push(...arguments); | ||
return; | ||
} | ||
dataLayer.push(...arguments); | ||
this.pushNow(...arguments); | ||
} | ||
pushEvent(eventName, data) { | ||
this.push({ | ||
event: eventName, | ||
eventId: uuid.v4(), | ||
...data | ||
}); | ||
} | ||
trackEvent(category, action) { | ||
let label = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
let value = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; | ||
this.push({ | ||
event: 'eventInteraction', | ||
this.pushEvent('eventInteraction', { | ||
eventCategory: category, | ||
@@ -100,4 +100,3 @@ eventAction: action, | ||
let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
this.push({ | ||
event: 'socialInteraction', | ||
this.pushEvent('socialInteraction', { | ||
socialNetwork: network, | ||
@@ -108,2 +107,26 @@ socialAction: action, | ||
} | ||
trackVideo(action) { | ||
let { | ||
platform = null, | ||
id = null, | ||
url, | ||
title = null, | ||
duration = null, | ||
currentTime = null, | ||
thumbnail = null | ||
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
this.pushEvent('eventInteraction', { | ||
eventCategory: 'Video', | ||
eventAction: action, | ||
eventLabel: `${platform !== null ? `${platform}: ` : ''}${title || document.title}${id !== null ? ` (${id})` : ''}`, | ||
videoPlatform: platform, | ||
videoId: id, | ||
videoUrl: url, | ||
videoTitle: title, | ||
videoDuration: duration, | ||
videoCurrentTime: currentTime !== null ? Math.round(currentTime) : null, | ||
videoProgress: currentTime !== null && duration !== null && duration > 0 ? Math.round(currentTime / duration * 100) : null, | ||
videoThumbnail: thumbnail | ||
}); | ||
} | ||
getSocialTarget() { | ||
@@ -169,2 +192,93 @@ return typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.host}` : null; | ||
function useVideoTracking(player, params) { | ||
if (player === null) { | ||
return; | ||
} | ||
const { | ||
provider, | ||
id, | ||
url, | ||
title = null, | ||
thumbnail = null, | ||
progressSteps = [0.1, 0.25, 0.5, 0.75, 0.9] | ||
} = params || {}; | ||
const tracking = useTracking$1(); | ||
const progressTrackedRef = React.useRef({}); | ||
const { | ||
playing = false, | ||
paused = false, | ||
ended = false, | ||
currentTime = false, | ||
duration = null | ||
} = player; | ||
const getVideoMetadata = React.useCallback(metadata => { | ||
let metadataTitle = null; | ||
try { | ||
metadataTitle = title !== null ? decodeURIComponent(title).replace(/[+]+/gi, ' ') : null; | ||
} catch (e) { | ||
console.log('error decoding title', e); // eslint-disable-line | ||
} | ||
return { | ||
platform: provider, | ||
id, | ||
url, | ||
title: metadataTitle, | ||
duration: duration || 0, | ||
thumbnail, | ||
...metadata | ||
}; | ||
}, [provider, id, title, url, duration, thumbnail]); | ||
React.useEffect(() => { | ||
if (playing) { | ||
tracking.trackVideo('play', getVideoMetadata({ | ||
currentTime | ||
})); | ||
} | ||
}, [playing]); | ||
React.useEffect(() => { | ||
if (paused) { | ||
tracking.trackVideo('pause', getVideoMetadata({ | ||
currentTime | ||
})); | ||
} | ||
}, [paused]); | ||
React.useEffect(() => { | ||
if (ended) { | ||
tracking.trackVideo('end', getVideoMetadata({ | ||
currentTime | ||
})); | ||
} | ||
}, [ended]); | ||
React.useEffect(() => { | ||
if (currentTime === null || currentTime <= 0 || duration === null || duration <= 0 || progressSteps === null || progressSteps.length === 0) { | ||
return; | ||
} | ||
const progress = currentTime / duration; | ||
const stepsToTrack = progressSteps.filter(step => progress > step && (typeof progressTrackedRef.current[id] === 'undefined' || typeof progressTrackedRef.current[id][step] === 'undefined')); | ||
stepsToTrack.forEach(step => { | ||
// console.log( | ||
// Math.round(step * 100, 10), | ||
// getVideoMetadata({ | ||
// currentTime, | ||
// }), | ||
// ); | ||
tracking.trackVideo(`progress ${Math.round(step * 100, 10)}%`, getVideoMetadata({ | ||
currentTime | ||
})); | ||
}); | ||
if (stepsToTrack !== null && stepsToTrack.length > 0) { | ||
progressTrackedRef.current = { | ||
...progressTrackedRef.current, | ||
[id]: { | ||
...progressTrackedRef.current[id], | ||
...stepsToTrack.reduce((stepsMap, step) => ({ | ||
...stepsMap, | ||
[step]: true | ||
}), {}) | ||
} | ||
}; | ||
} | ||
}, [currentTime, progressTrackedRef.current, id]); | ||
} | ||
exports.Tracking = Tracking$1; | ||
@@ -175,2 +289,3 @@ exports.TrackingContainer = TrackingContainer; | ||
exports.useTracking = useTracking$1; | ||
exports.useVideoTracking = useVideoTracking; | ||
exports.withTracking = withTracking$1; |
146
dist/es.js
@@ -1,2 +0,3 @@ | ||
import React, { useContext, useMemo, useEffect } from 'react'; | ||
import { v4 } from 'uuid'; | ||
import React, { useContext, useMemo, useEffect, useRef, useCallback } from 'react'; | ||
import { jsx } from 'react/jsx-runtime'; | ||
@@ -6,3 +7,2 @@ import PropTypes from 'prop-types'; | ||
/* eslint-disable class-methods-use-this */ | ||
class Tracking { | ||
@@ -49,3 +49,3 @@ constructor() { | ||
if (!paused && this.pending.length > 0) { | ||
this.push(...this.pending); | ||
this.pushNow(...this.pending); | ||
this.pending = []; | ||
@@ -64,19 +64,19 @@ } | ||
push() { | ||
const { | ||
dataLayer = null | ||
} = this.options; | ||
if (dataLayer === null || this.disabled) { | ||
return; | ||
} | ||
if (this.paused) { | ||
if (this.paused && !this.disabled) { | ||
this.pending.push(...arguments); | ||
return; | ||
} | ||
dataLayer.push(...arguments); | ||
this.pushNow(...arguments); | ||
} | ||
pushEvent(eventName, data) { | ||
this.push({ | ||
event: eventName, | ||
eventId: v4(), | ||
...data | ||
}); | ||
} | ||
trackEvent(category, action) { | ||
let label = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
let value = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; | ||
this.push({ | ||
event: 'eventInteraction', | ||
this.pushEvent('eventInteraction', { | ||
eventCategory: category, | ||
@@ -90,4 +90,3 @@ eventAction: action, | ||
let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
this.push({ | ||
event: 'socialInteraction', | ||
this.pushEvent('socialInteraction', { | ||
socialNetwork: network, | ||
@@ -98,2 +97,26 @@ socialAction: action, | ||
} | ||
trackVideo(action) { | ||
let { | ||
platform = null, | ||
id = null, | ||
url, | ||
title = null, | ||
duration = null, | ||
currentTime = null, | ||
thumbnail = null | ||
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
this.pushEvent('eventInteraction', { | ||
eventCategory: 'Video', | ||
eventAction: action, | ||
eventLabel: `${platform !== null ? `${platform}: ` : ''}${title || document.title}${id !== null ? ` (${id})` : ''}`, | ||
videoPlatform: platform, | ||
videoId: id, | ||
videoUrl: url, | ||
videoTitle: title, | ||
videoDuration: duration, | ||
videoCurrentTime: currentTime !== null ? Math.round(currentTime) : null, | ||
videoProgress: currentTime !== null && duration !== null && duration > 0 ? Math.round(currentTime / duration * 100) : null, | ||
videoThumbnail: thumbnail | ||
}); | ||
} | ||
getSocialTarget() { | ||
@@ -159,2 +182,93 @@ return typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.host}` : null; | ||
export { Tracking$1 as Tracking, TrackingContainer, TrackingContext$1 as TrackingContext, Tracking$1 as default, useTracking$1 as useTracking, withTracking$1 as withTracking }; | ||
function useVideoTracking(player, params) { | ||
if (player === null) { | ||
return; | ||
} | ||
const { | ||
provider, | ||
id, | ||
url, | ||
title = null, | ||
thumbnail = null, | ||
progressSteps = [0.1, 0.25, 0.5, 0.75, 0.9] | ||
} = params || {}; | ||
const tracking = useTracking$1(); | ||
const progressTrackedRef = useRef({}); | ||
const { | ||
playing = false, | ||
paused = false, | ||
ended = false, | ||
currentTime = false, | ||
duration = null | ||
} = player; | ||
const getVideoMetadata = useCallback(metadata => { | ||
let metadataTitle = null; | ||
try { | ||
metadataTitle = title !== null ? decodeURIComponent(title).replace(/[+]+/gi, ' ') : null; | ||
} catch (e) { | ||
console.log('error decoding title', e); // eslint-disable-line | ||
} | ||
return { | ||
platform: provider, | ||
id, | ||
url, | ||
title: metadataTitle, | ||
duration: duration || 0, | ||
thumbnail, | ||
...metadata | ||
}; | ||
}, [provider, id, title, url, duration, thumbnail]); | ||
useEffect(() => { | ||
if (playing) { | ||
tracking.trackVideo('play', getVideoMetadata({ | ||
currentTime | ||
})); | ||
} | ||
}, [playing]); | ||
useEffect(() => { | ||
if (paused) { | ||
tracking.trackVideo('pause', getVideoMetadata({ | ||
currentTime | ||
})); | ||
} | ||
}, [paused]); | ||
useEffect(() => { | ||
if (ended) { | ||
tracking.trackVideo('end', getVideoMetadata({ | ||
currentTime | ||
})); | ||
} | ||
}, [ended]); | ||
useEffect(() => { | ||
if (currentTime === null || currentTime <= 0 || duration === null || duration <= 0 || progressSteps === null || progressSteps.length === 0) { | ||
return; | ||
} | ||
const progress = currentTime / duration; | ||
const stepsToTrack = progressSteps.filter(step => progress > step && (typeof progressTrackedRef.current[id] === 'undefined' || typeof progressTrackedRef.current[id][step] === 'undefined')); | ||
stepsToTrack.forEach(step => { | ||
// console.log( | ||
// Math.round(step * 100, 10), | ||
// getVideoMetadata({ | ||
// currentTime, | ||
// }), | ||
// ); | ||
tracking.trackVideo(`progress ${Math.round(step * 100, 10)}%`, getVideoMetadata({ | ||
currentTime | ||
})); | ||
}); | ||
if (stepsToTrack !== null && stepsToTrack.length > 0) { | ||
progressTrackedRef.current = { | ||
...progressTrackedRef.current, | ||
[id]: { | ||
...progressTrackedRef.current[id], | ||
...stepsToTrack.reduce((stepsMap, step) => ({ | ||
...stepsMap, | ||
[step]: true | ||
}), {}) | ||
} | ||
}; | ||
} | ||
}, [currentTime, progressTrackedRef.current, id]); | ||
} | ||
export { Tracking$1 as Tracking, TrackingContainer, TrackingContext$1 as TrackingContext, Tracking$1 as default, useTracking$1 as useTracking, useVideoTracking, withTracking$1 as withTracking }; |
{ | ||
"name": "@folklore/tracking", | ||
"version": "0.0.20", | ||
"version": "0.0.21", | ||
"description": "Tracking utilities", | ||
@@ -43,3 +43,4 @@ "keywords": [ | ||
"@babel/runtime": "^7.4.3", | ||
"prop-types": "^15.7.2" | ||
"prop-types": "^15.7.2", | ||
"uuid": "^10.0.0" | ||
}, | ||
@@ -54,3 +55,3 @@ "devDependencies": { | ||
}, | ||
"gitHead": "ee61fcb16d9b0001aabfdf9c241723a9e0bff6b5" | ||
"gitHead": "76f400a041038b006a93161398d46ba0c921c12e" | ||
} |
17225
533
5
+ Addeduuid@^10.0.0
+ Addeduuid@10.0.0(transitive)