Skip to content

Commit

Permalink
Add matomo event tracking (#246)
Browse files Browse the repository at this point in the history
* feat: 📈 better matomo download tracking

* feat: 📈 add analytics

* feat: 📈 add tracking

* feat: 📈 add tracker move to hash
  • Loading branch information
nicolaskempf57 committed May 16, 2023
1 parent e7d18a9 commit 90f279b
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,7 @@
- Handle previous format of link to discussions, e.g. from e-mails [#241](https://github.com/etalab/udata-front/pull/241)
- Add `last_update` sort in datasets page [#242](https://github.com/etalab/udata-front/pull/242)
- Fix `.fr-btn` in `.markdown` [#243](https://github.com/etalab/udata-front/pull/243)
- Add Matomo event tracking [#246](https://github.com/etalab/udata-front/pull/246)
- New scope for Captchetat piste OAuth [#250](https://github.com/etalab/udata-front/pull/250)

## 3.2.2 (2023-04-18)
Expand Down
Expand Up @@ -79,7 +79,7 @@
:href="resource.latest"
:title="$t('Download resource')"
download
class="fr-btn fr-btn--secondary fr-btn--secondary-grey-500 fr-icon-download-line fr-icon--sm"
class="fr-btn fr-btn--secondary fr-btn--secondary-grey-500 fr-icon-download-line fr-icon--sm matomo_download"
>
</a>
</p>
Expand All @@ -103,14 +103,44 @@
<ul class="fr-tabs__list" role="tablist" :aria-label="$t('Resource menu')">
<template v-if="hasExplore">
<li role="presentation">
<button :id="resourcePreviewButtonId" class="fr-tabs__tab" tabindex="0" role="tab" aria-selected="true" :aria-controls="resourcePreviewTabId">{{$t('Preview')}}</button>
<button
:id="resourcePreviewButtonId"
class="fr-tabs__tab"
tabindex="0"
role="tab"
aria-selected="true"
:aria-controls="resourcePreviewTabId"
@click="registerEvent(resourcePreviewButtonId)"
>
{{$t('Preview')}}
</button>
</li>
<li role="presentation">
<button :id="resourceStructureButtonId" class="fr-tabs__tab" tabindex="0" role="tab" aria-selected="false" :aria-controls="resourceStructureTabId">{{$t('Data structure')}}</button>
<button
:id="resourceStructureButtonId"
class="fr-tabs__tab"
tabindex="0"
role="tab"
aria-selected="false"
:aria-controls="resourceStructureTabId"
@click="registerEvent(resourceStructureButtonId)"
>
{{$t('Data structure')}}
</button>
</li>
</template>
<li role="presentation">
<button :id="resourceInformationButtonId" class="fr-tabs__tab" :tabindex="resourceInformationTabIndex" role="tab" :aria-selected="resourceInformationSelectedTab" :aria-controls="resourceInformationTabId">{{$t('Metadata')}}</button>
<button
:id="resourceInformationButtonId"
class="fr-tabs__tab"
:tabindex="resourceInformationTabIndex"
role="tab"
:aria-selected="resourceInformationSelectedTab"
:aria-controls="resourceInformationTabId"
@click="registerEvent(resourceInformationButtonId)"
>
{{$t('Metadata')}}
</button>
</li>
</ul>
<div
Expand Down Expand Up @@ -260,7 +290,7 @@
</template>

<script>
import { inject, defineComponent, ref, computed } from "vue";
import { defineComponent, ref, computed, unref } from "vue";
import SchemaLoader from "./schema-loader.vue";
import useOwnerName from "../../../composables/useOwnerName";
import useResourceImage from "../../../composables/useResourceImage";
Expand Down Expand Up @@ -306,15 +336,44 @@ export default defineComponent({
const owner = useOwnerName(props.resource);
const resourceImage = useResourceImage(props.resource);
const { getComponentsForHook } = useComponentsForHook();

/** @type {import("vue").Ref<HTMLElement | undefined>} */
const content = ref();

const expanded = ref(false);
const expand = () => {
if(expanded.value) {
globalThis._paq?.push(['trackEvent', 'Close resource', props.resource.id]);
} else {
globalThis._paq?.push(['trackEvent', 'Open resource', props.resource.id]);
if(hasExplore.value) {
registerEvent(resourcePreviewButtonId);
} else if (hasSchema.value) {
registerEvent(resourceStructureButtonId);
} else {
registerEvent(resourceInformationButtonId);
}
}
expanded.value = !expanded.value;
if(content.value) {
toggleAccordion(content.value, expanded.value);
}
}

/**
*
* @param {import("vue").ComputedRef<string> | string} tab Tab name
*/
const registerEvent = (tab) => {
const tabName = unref(tab);
globalThis._paq?.push(['trackEvent', 'View resource tab', props.resource.id, tab]);
if(tabName === resourcePreviewButtonId.value) {
globalThis._paq?.push(['trackEvent', 'Show preview', props.resource.id]);
} else if (tabName === resourceStructureButtonId.value) {
globalThis._paq?.push(['trackEvent', 'Show data structure', props.resource.id]);
}
}

const availabilityChecked = computed(() => props.resource.extras && props.resource.extras['check:status']);
const lastUpdate = computed(() => props.resource.last_modified);
const unavailable = computed(() => availabilityChecked.value && availabilityChecked.value >= 400);
Expand All @@ -337,6 +396,7 @@ export default defineComponent({
const resourceInformationTabIndex = computed(() => hasExplore.value ? -1 : 0);

return {
registerEvent,
owner,
resourceImage,
filesize,
Expand Down
Expand Up @@ -97,7 +97,7 @@
{{$t('Reset filters')}}
</button>
<a
class="fr-btn fr-btn--secondary fr-btn--secondary-grey-500 fr-icon-download-line fr-btn--icon-left justify-center w-100"
class="fr-btn fr-btn--secondary fr-btn--secondary-grey-500 fr-icon-download-line fr-btn--icon-left justify-center w-100 matomo_download"
:href="downloadLink"
v-else-if="downloadLink"
>
Expand Down
Expand Up @@ -19,6 +19,7 @@ selects.forEach((select) => {
select.disabled = true;
}
select.form?.submit();
globalThis._paq?.push(['trackEvent', 'Search', 'Sort', select.value]);
});
}
});
14 changes: 9 additions & 5 deletions udata_front/theme/gouvfr/assets/js/components/vanilla/tabs.js
Expand Up @@ -30,21 +30,25 @@ tabs.forEach((tab) => {
tabsButtons.forEach((tabButton) => {
tabButton.addEventListener("click", (el) => {
el.preventDefault();
const target = /** @type {HTMLElement} */ (el.target);

const previouslyActive = Array.from(tabsButtons).find((tab) =>
tab.getAttribute("aria-selected") === "true"
);
if (previouslyActive) {
previouslyActive.setAttribute("aria-selected", "false");
const previousAriaControls = previouslyActive.getAttribute("aria-controls") || "";
document
.getElementById(previouslyActive.getAttribute("aria-controls"))
.classList.remove("fr-unhidden");
.getElementById(previousAriaControls)
?.classList.remove("fr-unhidden");
}

el.target.setAttribute("aria-selected", "true");
const ariaControls = target.getAttribute("aria-controls") || "";
target.setAttribute("aria-selected", "true");
document
.getElementById(el.target.getAttribute("aria-controls"))
.classList.add("fr-unhidden");
.getElementById(ariaControls)
?.classList.add("fr-unhidden");
globalThis._paq?.push(['trackEvent', 'Move page to tab', window.location.pathname, tabButton.textContent]);
});
});
});
Expand Up @@ -35,13 +35,16 @@ function tryPreviousHashes(target) {
}

/**
* Update UI to match hash
* Update UI to match hash.
* This is done on page launch with hash and when the hash is updated with a link or manual edition.
* It isn't triggered on hash update from `handleUpdateUrlButtons` below.
*/
function moveToHash() {
const hash = window.location.hash;
if(!hash) {
return;
}
globalThis._paq?.push(['trackEvent', 'Move page to hash', window.location.pathname, hash]);
if(hash.startsWith("#/")) {
moveToCurrentHash(hash.slice(2));
} else {
Expand All @@ -68,6 +71,7 @@ export default function handleUpdateUrlButtons() {
if(!url.hash.includes(targetHash)) {
url.hash = targetHash;
window.history.pushState(null, "", url);
globalThis._paq?.push(['trackEvent', 'Move page to hash', window.location.pathname, targetHash]);
}
});
});
Expand Down
Expand Up @@ -62,7 +62,7 @@
href="{{ resource.latest }}"
title="{{ _('Download resource') }}"
download
class="fr-btn fr-btn--sm fr-icon-download-line"
class="fr-btn fr-btn--sm fr-icon-download-line matomo_download"
></a>
</li>
{% endif %}
Expand Down

0 comments on commit 90f279b

Please sign in to comment.