UNPKG

activator-oce-exporter

Version:

Extract Activator binder and convert it to valid OCE mono pacakge

451 lines (386 loc) 11 kB
import { FusionLogger } from './services/fusion-logger'; import { analyticsData } from './static/analytics.json'; import { veevaMonitoring } from '../config.json'; import { FusionStore } from './services/fusion-store'; /* StackRunner: input: params = {handler: function(result, id)}, publicMethods: push({method: function(result), id: string}), */ const CONFIG = { types: { slide: 'slide', popup: 'popup', pdf: 'pdf', custom: 'custom', insight: 'insight', }, }; const setConfig = (config, params) => Object.keys(params).map((key) => { config[key] = params[key]; return config[key]; }); const triggerEvent = (name, data) => { const event = new CustomEvent(name, { detail: data }); document.dispatchEvent(event); }; const errorHandler = (errorMessage) => { FusionLogger.error(errorMessage, 'monitoring'); }; class StackRunner { constructor(params = {}) { this.config = { handler: null, }; this.stack = []; this.isStackRunningProceed = false; setConfig(this.config, params); } push(data) { if (data) { this.stack.push(data); } if (!this.isStackRunningProceed) { this.run(); } } checkStack() { const lastIndexItem = this.stack.length - 1; const FIRST_ITEM_INDEX = 0; // if we have stack of the same data, we get only last value if (!!this.stack.length && this.stack[FIRST_ITEM_INDEX].id === this.stack[lastIndexItem].id) { this.stack.splice(0, lastIndexItem); } } resultHandler(result) { if (this.config.handler) { this.config.handler(result, this.stack[0]); } this.stack.shift(); this.run(); } run() { this.isStackRunningProceed = true; this.checkStack(); const method = this.stack.length > 0 ? this.stack[0].method : null; if (method) { method(this.resultHandler.bind(this)); } else { this.isStackRunningProceed = false; } } } class ClickStream { constructor(data) { this.setId(); this.setDefaultFields(data); this.setCustomFields(data); } setDefaultFields(data) { const { trackId, type, description, answer, } = data; this.Track_Element_Id_vod__c = trackId; this.Track_Element_Type_vod__c = type; this.Track_Element_Description_vod__c = description; this.Answer_vod__c = answer; } setCustomFields(data) { const customFieldsConfig = { [CONFIG.types.popup]: 'setDuration', [CONFIG.types.slide]: 'setDuration', [CONFIG.types.insight]: 'setInsight', }; const func = customFieldsConfig[data.type]; if (func) { this.constructor.prototype[func](data); } } setDuration(data) { this.Usage_Duration_vod__c = data.ticks; } setId(value = '') { this.ID = value; } setInsight() { this.CLM_Insight__c = 1; } setAnswer(data) { this.Answer_vod__c = data.answer || ''; } } /* MonitoringItem: input: data = {id, type ....} , params = {isTotalTicks:boolean} publicMethods: enter() - run on view enter exit() - run on view exit presentationExit() - run on presentation exit in veeva(used in 'com.veeva.clm.createRecordsOnExit' func) submit() - used for submitting data */ class MonitoringItem { constructor(data, params = {}) { this.config = { isTotalTicks: false, }; this.CLICKSTREAM_OBJECT_NAME = 'Call_Clickstream_vod__c'; this.TICKS_PER_MS = 10000; this.MIN_VISIT_TIME_MS = 1000; setConfig(this.config, params); this.init(data); } init(data) { this.itemData = MonitoringItem.initData(data); this.clickStream = new ClickStream(this.itemData); } static initData(data) { const { itemId, id, type, description, answer, } = data; return { id: itemId, trackId: id, description, type, answer, startTime: new Date(), endTime: new Date(), duration: new Date(), ticks: 0, totalTicks: 0, }; } createQueryData() { const { id, type, description } = this.itemData; return { id, type, description, method: this.getQueryMethod(), }; } getQueryMethod() { const { ID, ...objToSubmit } = this.clickStream; if (ID) { return result => com.veeva.clm.updateRecord(this.CLICKSTREAM_OBJECT_NAME, ID, objToSubmit, result); } return result => com.veeva.clm.createRecord(this.CLICKSTREAM_OBJECT_NAME, objToSubmit, result); } setStartTime(time = new Date()) { this.itemData.startTime = time; } calcDuration() { return this.itemData.endTime - this.itemData.startTime; } getDurationTime(storedTime = 0) { return this.calcDuration() + storedTime; } calcTicks() { return parseInt(this.itemData.duration * this.TICKS_PER_MS, 10); } setClickStreamId(result) { const { ID } = result[this.CLICKSTREAM_OBJECT_NAME]; if (!this.clickStream.ID) { this.clickStream.setId(ID); } } setSpentTime(time) { this.itemData.endTime = new Date(); this.itemData.duration = this.getDurationTime(time); this.itemData.ticks = this.calcTicks(); this.itemData.totalTicks += this.itemData.ticks; this.clickStream.setDuration(this.getTicks()); } updateDataAnswer(data) { const currentAnswer = data.answer; if (this.itemData.answer !== currentAnswer) { this.itemData.answer = currentAnswer; this.clickStream.setAnswer(this.itemData); } } getTicks() { const { totalTicks, ticks } = this.itemData; const time = this.config.isTotalTicks ? totalTicks : ticks; return { ticks: time }; } isItemVisited() { return this.itemData.duration > this.MIN_VISIT_TIME_MS; } enter(time) { this.setStartTime(time); } exit(time) { this.setSpentTime(time); if (this.isItemVisited()) { this.submit(); } } exitPresentation() { this.setSpentTime(); return this.createQueryOnExit(); } submit() { triggerEvent('monitoring:query-ready', this.createQueryData()); } createQueryOnExit() { const { ID, ...objToSubmit } = this.clickStream; if (this.clickStream.ID) { return com.veeva.clm.formatUpdateRecords([this.CLICKSTREAM_OBJECT_NAME], [ID], [objToSubmit]); } return com.veeva.clm.formatCreateRecords([this.CLICKSTREAM_OBJECT_NAME], [objToSubmit]); } } export class VeevaMonitoring { constructor(params = {}) { this.INPUT_DATA = { id: 'id', type: Object.values(CONFIG.types), description: 'description', answer: 'answer', }; this.config = { isDebugMode: true, }; this.analyticData = analyticsData; this.monitoringItems = {}; this.keyMessageName = ''; this.stack = new StackRunner({ handler: VeevaMonitoring.queryHandler }); setConfig(this.config, params); this.initListeners(); } initListeners() { document.addEventListener('monitoring:query-completed', this.setSubmittedClickStreamId.bind(this)); document.addEventListener('monitoring:query-ready', this.pushToStack.bind(this)); document.addEventListener('VeevaDataReceived', this.trackKeyMessageEnter.bind(this)); } trackKeyMessageEnter() { const { name } = FusionStore.keyMessage; this.keyMessageName = name; this.trackSlideEnter({ id: this.keyMessageName }); this.setVeevaExtends(); } setVeevaExtends() { if (window.com) { window.com.veeva.clm.createRecordsOnExit = () => this.presentationExit({ id: this.keyMessageName }); } } setSubmittedClickStreamId(data) { this.doItemAction(VeevaMonitoring.setItemClickStreamId, data.detail); } trackSlideEnter(data) { this.doItemAction(VeevaMonitoring.trackItemEnter, data); } trackSlideExit(data) { this.doItemAction(VeevaMonitoring.trackItemExit, data); } trackCustomData(data) { this.doItemAction(VeevaMonitoring.trackItemCustomData, data); } static queryHandler(result, item) { const { id, type, description } = item; if (result.success === false) { errorHandler(result.message); } else { triggerEvent('monitoring:query-completed', { id, type, description, result, }); } } getMonitoringItem(data) { const itemData = this.createItemData(data); let result = null; if (itemData) { result = this.monitoringItems[itemData.itemId] || (this.monitoringItems[itemData.itemId] = new MonitoringItem(itemData)); } return result; } doItemAction(action, data) { const item = this.getMonitoringItem(data); if (item) { action.call(this, item, data); } } static setItemClickStreamId(item, data) { item.setClickStreamId(data.result); } static trackItemEnter(item, data, time) { item.enter(time); } static trackItemExit(item) { item.exit(); } static trackItemCustomData(item, data) { item.updateDataAnswer(data); item.submit(); } formatInputData(data) { const obj = {}; Object.keys(data) .filter(key => this.INPUT_DATA[key]) .forEach((key) => { obj[key] = data[key]; return obj; }); return obj; } isTypeExist(type) { return this.INPUT_DATA.type.includes(type); } isValidFields(data) { const { id, type, description } = data; const isValidType = type && this.isTypeExist(type); const isValidFields = id && description; return isValidType && isValidFields; } isWrongInputData(data) { const errorMessage = `wrong monitoring data: ${JSON.stringify(data)}`; const isWrongData = !data || !this.isValidFields(data); if (isWrongData) { errorHandler(errorMessage); } return isWrongData; } createItemData(data) { const fileData = this.getFileItem(data); let inputData = null; if (!this.isWrongInputData(fileData)) { inputData = this.formatInputData(fileData); inputData.itemId = data.id; } return inputData; } static filterCondition(itemId, keyId) { return itemId === keyId; } getFileItem(data) { const item = Object.keys(this.analyticData) .find(key => VeevaMonitoring.filterCondition(data.id, key)); return this.analyticData[item]; } isExcluded(id) { return veevaMonitoring.excludedTypes.includes(this.monitoringItems[id].itemData.type); } isSubmitEnable(slideId) { return window.com && !this.isExcluded(slideId); } pushToStack(queryData) { const data = queryData.detail; if (this.config.isDebugMode) { FusionLogger.log(`ClickStream to submit: ${this.monitoringItems[data.id].clickStream}`, 'monitoring'); } if (this.isSubmitEnable(data.id)) { this.stack.push(data); } } presentationExit(data) { const monitoringItem = this.getMonitoringItem(data); const slideId = monitoringItem.itemData.id; if (this.isSubmitEnable(slideId)) { return monitoringItem.exitPresentation(); } return null; } } const monitoring = new VeevaMonitoring(); export { monitoring };