diff --git a/src/components/Chat.vue b/src/components/Chat.vue index e67dad1..74cc531 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -1429,8 +1429,8 @@ export default { this.sendAttachment(text); this.showRecorder = false; - // Log event to Clean Insights - this.$ci.event("Audio", "Voice message sent"); + // Log event + this.$analytics.event("Audio", "Voice message sent"); }, closeCreateRoomWelcomeHeader() { diff --git a/src/main.js b/src/main.js index 2019b78..07853c9 100644 --- a/src/main.js +++ b/src/main.js @@ -7,7 +7,7 @@ import router from './router' import matrix from './services/matrix.service' import navigation from './services/navigation.service' import config from './services/config.service' -import cleaninsights from './services/cleaninsights.service' +import analytics from './services/analytics.service' import 'roboto-fontface/css/roboto/roboto-fontface.css' import 'material-design-icons-iconfont/dist/material-design-icons.css' import VEmojiPicker from 'v-emoji-picker'; @@ -27,7 +27,7 @@ Vue.use(VueResize); Vue.use(VEmojiPicker); Vue.use(matrix, { store: store, i18n: i18n }); Vue.use(config); // Use this before cleaninsights below, it depends on config! -Vue.use(cleaninsights); +Vue.use(analytics); Vue.use(VueClipboard); // Add bubble functionality to custom events. @@ -159,6 +159,6 @@ new Vue({ router, matrix, config, - cleaninsights, + analytics, render: h => h(App) }).$mount('#app'); \ No newline at end of file diff --git a/src/services/analytics.service.js b/src/services/analytics.service.js new file mode 100644 index 0000000..3fd7cd1 --- /dev/null +++ b/src/services/analytics.service.js @@ -0,0 +1,65 @@ +import cleaninsights from './cleaninsights.service' +import matomo from './matomo.service' + +export default { + install(Vue) { + const analyticsService = new Vue({ + data() { + return { + engines: [], + cachedEvents: [], + initialized: false + } + }, + created() { + this.$config.promise.then((config) => { + var analytics = config.analytics || {}; + if (!Array.isArray(analytics)) { + analytics = [analytics]; + } + for (const engineConfig of analytics) { + if (engineConfig.enabled) { + let type = engineConfig.type || "ci"; + switch (type) { + case "ci": + { + let engine = cleaninsights.install(Vue, engineConfig.config); + this.engines.push(engine); + } + break; + case "matomo": + { + let engine = matomo.install(Vue, engineConfig.config); + this.engines.push(engine); + } + break; + } + } + } + + this.initialized = true; + + // Handle cached events + this.cachedEvents.forEach(([category, action]) => { + this.event(category, action); + }) + this.cachedEvents = []; + }); + }, + methods: { + event(category, action) { + if (!this.initialized) { + this.cachedEvents.push([category, action]); + return + } + + // Send the event to each configured analytics engine. + this.engines.forEach((engine) => { + engine.event(category, action); + }); + } + } + }); + Vue.prototype.$analytics = analyticsService; + } +} diff --git a/src/services/cleaninsights.service.js b/src/services/cleaninsights.service.js index accfb7b..ba0fe60 100644 --- a/src/services/cleaninsights.service.js +++ b/src/services/cleaninsights.service.js @@ -1,7 +1,7 @@ import { CleanInsights, ConsentRequestUi } from 'clean-insights-sdk'; export default { - install(Vue) { + install(Vue, config) { class RequestUi extends ConsentRequestUi { showForCampaign(campaignId, campaign, complete) { @@ -18,6 +18,7 @@ export default { } const cleanInsightsService = new Vue({ + config: config, data() { return { ci: null, @@ -26,17 +27,14 @@ export default { } }, created() { - const self = this; - this.$config.promise.then(function (config) { - const analytics = config.analytics || {}; - if (analytics.enabled && analytics.config) { - self.ci = new CleanInsights(analytics.config); + if (this.$options.config) { + const config = this.$options.config; + this.ci = new CleanInsights(config); - // Get name of first campaign in the config. - self.campaignId = Object.keys(analytics.config.campaigns || { invalid: {} })[0]; - } + // Get name of first campaign in the config. + this.campaignId = Object.keys(config.campaigns || { invalid: {} })[0]; - }); + } }, methods: { event(category, action) { @@ -55,6 +53,6 @@ export default { } } }); - Vue.prototype.$ci = cleanInsightsService; + return cleanInsightsService; } } diff --git a/src/services/matomo.service.js b/src/services/matomo.service.js new file mode 100644 index 0000000..70ded8b --- /dev/null +++ b/src/services/matomo.service.js @@ -0,0 +1,51 @@ + +export default { + install(Vue, config) { + + const matomoService = new Vue({ + config: config, + data() { + return { + initialized: false + } + }, + created() { + if (this.$options.config) { + const config = this.$options.config; + let server = config.server; + let siteId = config.siteId; + if (server && siteId) { + if (!server.endsWith("/")) { + server = server + "/"; + } + let script = ` + var _paq = window._paq = window._paq || []; + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="${server}"; + _paq.push(['setTrackerUrl', u+'matomo.php']); + _paq.push(['setSiteId', '${siteId}']); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); + })(); + `; + var s = document.createElement('script'); + s.innerHTML = script; + document.body.appendChild(s); + this.initialized = true; + } + } + }, + methods: { + event(category, action) { + if (this.initialized) { + window._paq.push(['trackEvent', category, action]); + } + } + } + }); + return matomoService; + } +}