diff options
Diffstat (limited to 'app/assets/javascripts/tracking/utils.js')
-rw-r--r-- | app/assets/javascripts/tracking/utils.js | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/app/assets/javascripts/tracking/utils.js b/app/assets/javascripts/tracking/utils.js new file mode 100644 index 00000000000..1189b2168ad --- /dev/null +++ b/app/assets/javascripts/tracking/utils.js @@ -0,0 +1,102 @@ +import { omitBy, isUndefined } from 'lodash'; +import { TRACKING_CONTEXT_SCHEMA } from '~/experimentation/constants'; +import { getExperimentData } from '~/experimentation/utils'; +import { + ACTION_ATTR_SELECTOR, + LOAD_ACTION_ATTR_SELECTOR, + DEPRECATED_EVENT_ATTR_SELECTOR, + DEPRECATED_LOAD_EVENT_ATTR_SELECTOR, +} from './constants'; + +export const addExperimentContext = (opts) => { + const { experiment, ...options } = opts; + + if (experiment) { + const data = getExperimentData(experiment); + if (data) { + const context = { schema: TRACKING_CONTEXT_SCHEMA, data }; + return { ...options, context }; + } + } + + return options; +}; + +export const createEventPayload = (el, { suffix = '' } = {}) => { + const { + trackAction, + trackEvent, + trackValue, + trackExtra, + trackExperiment, + trackContext, + trackLabel, + trackProperty, + } = el?.dataset || {}; + + const action = (trackAction || trackEvent) + (suffix || ''); + let value = trackValue || el.value || undefined; + + if (el.type === 'checkbox' && !el.checked) { + value = 0; + } + + let extra = trackExtra; + + if (extra !== undefined) { + try { + extra = JSON.parse(extra); + } catch (e) { + extra = undefined; + } + } + + const context = addExperimentContext({ + experiment: trackExperiment, + context: trackContext, + }); + + const data = { + label: trackLabel, + property: trackProperty, + value, + extra, + ...context, + }; + + return { + action, + data: omitBy(data, isUndefined), + }; +}; + +export const eventHandler = (e, func, opts = {}) => { + const actionSelector = `${ACTION_ATTR_SELECTOR}:not(${LOAD_ACTION_ATTR_SELECTOR})`; + const deprecatedEventSelector = `${DEPRECATED_EVENT_ATTR_SELECTOR}:not(${DEPRECATED_LOAD_EVENT_ATTR_SELECTOR})`; + const el = e.target.closest(`${actionSelector}, ${deprecatedEventSelector}`); + + if (!el) { + return; + } + + const { action, data } = createEventPayload(el, opts); + func(opts.category, action, data); +}; + +export const getEventHandlers = (category, func) => { + const handler = (opts) => (e) => eventHandler(e, func, { ...{ category }, ...opts }); + const handlers = []; + + handlers.push({ name: 'click', func: handler() }); + handlers.push({ name: 'show.bs.dropdown', func: handler({ suffix: '_show' }) }); + handlers.push({ name: 'hide.bs.dropdown', func: handler({ suffix: '_hide' }) }); + + return handlers; +}; + +export const renameKey = (o, oldKey, newKey) => { + const ret = {}; + delete Object.assign(ret, o, { [newKey]: o[oldKey] })[oldKey]; + + return ret; +}; |