web/satellite/vuetify: added analytics events for currently implemented functionality

Populated already implemented functionality with analytics events.

Issue:
https://github.com/storj/storj/issues/6122

Change-Id: I1e250ca02debc9bedbf78024f74e0dbfa9dfbcb9
This commit is contained in:
Vitalii 2023-08-03 15:06:37 +03:00 committed by Storj Robot
parent e2e437dd95
commit a4f7f0634d
10 changed files with 91 additions and 17 deletions

View File

@ -98,6 +98,8 @@ import { ProjectItemModel, PROJECT_ROLE_COLORS } from '@poc/types/projects';
import { ProjectInvitationResponse } from '@/types/projects';
import { ProjectRole } from '@/types/projectMembers';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import IconProject from '@poc/components/icons/IconProject.vue';
import IconSettings from '@poc/components/icons/IconSettings.vue';
@ -111,6 +113,7 @@ const emit = defineEmits<{
(event: 'joinClick'): void;
}>();
const analyticsStore = useAnalyticsStore();
const projectsStore = useProjectsStore();
const router = useRouter();
@ -123,6 +126,7 @@ function openProject(): void {
if (!props.item) return;
projectsStore.selectProject(props.item.id);
router.push(`/projects/${props.item.id}/dashboard`);
analyticsStore.pageVisit('/projects/dashboard');
}
/**
@ -132,7 +136,11 @@ async function declineInvitation(): Promise<void> {
if (!props.item || isDeclining.value) return;
isDeclining.value = true;
await projectsStore.respondToInvitation(props.item.id, ProjectInvitationResponse.Decline).catch(_ => {});
try {
await projectsStore.respondToInvitation(props.item.id, ProjectInvitationResponse.Decline);
analyticsStore.eventTriggered(AnalyticsEvent.PROJECT_INVITATION_DECLINED);
} catch { /* empty */ }
await projectsStore.getUserInvitations().catch(_ => {});
await projectsStore.getProjects().catch(_ => {});

View File

@ -130,6 +130,8 @@ import { ProjectInvitationResponse } from '@/types/projects';
import { ProjectRole } from '@/types/projectMembers';
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import IconSettings from '@poc/components/icons/IconSettings.vue';
import IconTeam from '@poc/components/icons/IconTeam.vue';
@ -145,6 +147,7 @@ const emit = defineEmits<{
const search = ref<string>('');
const decliningIds = ref(new Set<string>());
const analyticsStore = useAnalyticsStore();
const projectsStore = useProjectsStore();
const router = useRouter();
@ -170,6 +173,7 @@ function getFormattedDate(date: Date): string {
function openProject(item: ProjectItemModel): void {
projectsStore.selectProject(item.id);
router.push(`/projects/${item.id}/dashboard`);
analyticsStore.pageVisit('/projects/dashboard');
}
/**
@ -179,7 +183,11 @@ async function declineInvitation(item: ProjectItemModel): Promise<void> {
if (decliningIds.value.has(item.id)) return;
decliningIds.value.add(item.id);
await projectsStore.respondToInvitation(item.id, ProjectInvitationResponse.Decline).catch(_ => {});
try {
await projectsStore.respondToInvitation(item.id, ProjectInvitationResponse.Decline);
analyticsStore.eventTriggered(AnalyticsEvent.PROJECT_INVITATION_DECLINED);
} catch { /* empty */ }
await projectsStore.getUserInvitations().catch(_ => {});
await projectsStore.getProjects().catch(_ => {});

View File

@ -93,11 +93,14 @@ import {
import { useLoading } from '@/composables/useLoading';
import { useUsersStore } from '@/store/modules/usersStore';
import { UpdatedUser } from '@/types/users';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
const rules = [
(value: string) => (!!value || 'Can\'t be empty'),
];
const analyticsStore = useAnalyticsStore();
const userStore = useUsersStore();
const { isLoading, withLoading } = useLoading();
@ -125,6 +128,8 @@ async function onChangeName(): Promise<void> {
await withLoading(async () => {
try {
await userStore.updateUser(new UpdatedUser(name.value, name.value));
analyticsStore.eventTriggered(AnalyticsEvent.PROFILE_UPDATED);
} catch (error) {
return;
}

View File

@ -119,6 +119,8 @@ import { useLoading } from '@/composables/useLoading';
import { useConfigStore } from '@/store/modules/configStore';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/types/router';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
const DELAY_BEFORE_REDIRECT = 2000; // 2 sec
const auth: AuthHttpApi = new AuthHttpApi();
@ -134,6 +136,7 @@ const repeatRules = [
(value: string) => (value && value === newPassword.value || 'Passwords are not the same.'),
];
const analyticsStore = useAnalyticsStore();
const { config } = useConfigStore().state;
const { isLoading, withLoading } = useLoading();
const router = useRouter();
@ -163,6 +166,8 @@ async function onChangePassword(): Promise<void> {
await withLoading(async () => {
try {
await auth.changePassword(oldPassword.value, newPassword.value);
analyticsStore.eventTriggered(AnalyticsEvent.PASSWORD_CHANGED);
} catch (error) {
return;
}

View File

@ -162,6 +162,8 @@ import QRCode from 'qrcode';
import { useLoading } from '@/composables/useLoading';
import { useConfigStore } from '@/store/modules/configStore';
import { useUsersStore } from '@/store/modules/usersStore';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
const rules = [
(value: string) => (!!value || 'Can\'t be empty'),
@ -170,6 +172,7 @@ const rules = [
(value: string) => (value.length === 6 || 'Can only be 6 numbers long'),
];
const analyticsStore = useAnalyticsStore();
const { config } = useConfigStore().state;
const usersStore = useUsersStore();
const { isLoading, withLoading } = useLoading();
@ -234,6 +237,8 @@ function enable(): void {
await usersStore.enableUserMFA(confirmPasscode.value);
await usersStore.getUser();
await showCodes();
analyticsStore.eventTriggered(AnalyticsEvent.MFA_ENABLED);
} catch (error) {
isError.value = true;
}

View File

@ -77,6 +77,9 @@ import {
import { ProjectInvitationResponse } from '@/types/projects';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import { RouteConfig } from '@/types/router';
const props = defineProps<{
modelValue: boolean,
@ -93,6 +96,7 @@ const emit = defineEmits<{
(event: 'update:modelValue', value: boolean): void,
}>();
const analyticsStore = useAnalyticsStore();
const projectsStore = useProjectsStore();
const router = useRouter();
@ -105,6 +109,7 @@ const isDeclining = ref<boolean>(false);
function openProject(): void {
projectsStore.selectProject(props.id);
router.push(`/projects/${props.id}/dashboard`);
analyticsStore.pageVisit('/projects/dashboard');
}
/**
@ -117,7 +122,16 @@ async function respondToInvitation(response: ProjectInvitationResponse): Promise
isLoading.value = true;
let success = false;
await projectsStore.respondToInvitation(props.id, response).then(() => { success = true; }).catch(_ => {});
try {
await projectsStore.respondToInvitation(props.id, response);
success = true;
analyticsStore.eventTriggered(
response === ProjectInvitationResponse.Accept ?
AnalyticsEvent.PROJECT_INVITATION_ACCEPTED :
AnalyticsEvent.PROJECT_INVITATION_DECLINED,
);
} catch { /* empty */ }
await projectsStore.getUserInvitations().catch(_ => {});
await projectsStore.getProjects().catch(_ => { success = false; });

View File

@ -6,7 +6,7 @@
<v-sheet>
<v-list class="px-2" color="default" variant="flat">
<template v-if="pathBeforeAccountPage">
<v-list-item class="pa-4 rounded-lg" link router-link :to="pathBeforeAccountPage">
<v-list-item class="pa-4 rounded-lg" link router-link :to="pathBeforeAccountPage" @click="() => trackPageVisitEvent(pathBeforeAccountPage)">
<template #prepend>
<img src="@poc/assets/icon-back-tonal.svg" alt="Project">
<!-- <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -22,7 +22,7 @@
</template>
<!-- All Projects -->
<v-list-item class="pa-4 rounded-lg" link router-link to="/projects">
<v-list-item class="pa-4 rounded-lg" link router-link to="/projects" @click="() => trackPageVisitEvent('/projects')">
<template #prepend>
<!-- <img src="@poc/assets/icon-prosject.svg" alt="Project" class="mr-3"> -->
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -40,7 +40,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link to="settings" class="my-1 py-3" rounded="lg">
<v-list-item link router-link to="settings" class="my-1 py-3" rounded="lg" @click="() => trackPageVisitEvent('/settings')">
<template #prepend>
<!-- <img src="@poc/assets/icon-settings.svg" alt="Account Settings" class="mr-3"> -->
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -52,7 +52,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link to="billing" class="my-1" rounded="lg">
<v-list-item link router-link to="billing" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/billing')">
<template #prepend>
<!-- <img src="@poc/assets/icon-card.svg" alt="Billing" class="mr-3"> -->
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -82,7 +82,9 @@ import {
} from 'vuetify/components';
import { useAppStore } from '@poc/store/appStore';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
const analyticsStore = useAnalyticsStore();
const appStore = useAppStore();
/**
@ -93,4 +95,11 @@ const pathBeforeAccountPage = computed((): string | null => {
if (!path || path === '/projects') return null;
return path;
});
/**
* Sends "Page Visit" event to segment and opens link.
*/
function trackPageVisitEvent(page: string | null): void {
if (page) analyticsStore.pageVisit(page);
}
</script>

View File

@ -30,10 +30,12 @@ import { useUsersStore } from '@/store/modules/usersStore';
import { useABTestingStore } from '@/store/modules/abTestingStore';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { useAppStore } from '@poc/store/appStore';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
const router = useRouter();
const route = useRoute();
const analyticsStore = useAnalyticsStore();
const billingStore = useBillingStore();
const usersStore = useUsersStore();
const abTestingStore = useABTestingStore();
@ -53,11 +55,15 @@ async function selectProject(projectId: string): Promise<void> {
try {
projects = await projectsStore.getProjects();
} catch (_) {
router.push('/projects');
const path = '/projects';
router.push(path);
analyticsStore.pageVisit(path);
return;
}
if (!projects.some(p => p.id === projectId)) {
router.push('/projects');
const path = '/projects';
router.push(path);
analyticsStore.pageVisit(path);
return;
}
projectsStore.selectProject(projectId);

View File

@ -11,7 +11,7 @@
<!-- Project Menu -->
<v-list class="pa-2">
<!-- My Projects -->
<v-list-item rounded="lg" link router-link to="/projects">
<v-list-item rounded="lg" link router-link to="/projects" @click="() => trackPageVisitEvent('/projects')">
<template #prepend>
<!-- <img src="@poc/assets/icon-project.svg" alt="Projects"> -->
<IconProject />
@ -36,7 +36,7 @@
<v-divider class="my-2" />
<!-- Shared With Me -->
<v-list-item rounded="lg" link router-link to="/projects">
<v-list-item rounded="lg" link router-link to="/projects" @click="() => trackPageVisitEvent('/projects')">
<template #prepend>
<IconProject />
</template>
@ -69,7 +69,7 @@
<!-- <v-divider class="my-2"></v-divider> -->
<!-- View All Projects -->
<v-list-item link rounded="lg" router-link to="/projects">
<v-list-item link rounded="lg" router-link to="/projects" @click="() => trackPageVisitEvent('/projects')">
<template #prepend>
<IconAllProjects />
</template>
@ -117,7 +117,7 @@
<v-divider class="my-2" />
<v-list-item link router-link to="dashboard" class="my-1 py-3" rounded="lg">
<v-list-item link router-link to="dashboard" class="my-1 py-3" rounded="lg" @click="() => trackPageVisitEvent('/dashboard')">
<template #prepend>
<IconDashboard />
</template>
@ -126,7 +126,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link to="buckets" class="my-1" rounded="lg">
<v-list-item link router-link to="buckets" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/buckets')">
<template #prepend>
<IconBucket />
</template>
@ -135,7 +135,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link to="bucket" class="my-1" rounded="lg">
<v-list-item link router-link to="bucket" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/bucket')">
<template #prepend>
<IconBrowse />
</template>
@ -144,7 +144,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link to="access" class="my-1" rounded="lg">
<v-list-item link router-link to="access" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/access')">
<template #prepend>
<IconAccess />
</template>
@ -153,7 +153,7 @@
</v-list-item-title>
</v-list-item>
<v-list-item link router-link to="team" class="my-1" rounded="lg">
<v-list-item link router-link to="team" class="my-1" rounded="lg" @click="() => trackPageVisitEvent('/team')">
<template #prepend>
<IconTeam />
</template>
@ -249,6 +249,7 @@ import {
import { Project } from '@/types/projects';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import IconProject from '@poc/components/icons/IconProject.vue';
import IconSettings from '@poc/components/icons/IconSettings.vue';
@ -265,6 +266,7 @@ import IconForum from '@poc/components/icons/IconForum.vue';
import IconSupport from '@poc/components/icons/IconSupport.vue';
import IconResources from '@poc/components/icons/IconResources.vue';
const analyticsStore = useAnalyticsStore();
const projectsStore = useProjectsStore();
/**
@ -273,4 +275,11 @@ const projectsStore = useProjectsStore();
const selectedProject = computed((): Project => {
return projectsStore.state.selectedProject;
});
/**
* Sends "Page Visit" event to segment and opens link.
*/
function trackPageVisitEvent(page: string): void {
analyticsStore.pageVisit(page);
}
</script>

View File

@ -134,11 +134,14 @@ import {
import { useProjectMembersStore } from '@/store/modules/projectMembersStore';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import PageTitleComponent from '@poc/components/PageTitleComponent.vue';
import PageSubtitleComponent from '@poc/components/PageSubtitleComponent.vue';
import TeamTableComponent from '@poc/components/TeamTableComponent.vue';
const analyticsStore = useAnalyticsStore();
const pmStore = useProjectMembersStore();
const projectsStore = useProjectsStore();
@ -169,6 +172,8 @@ async function onAddUsersClick(): Promise<void> {
return;
}
analyticsStore.eventTriggered(AnalyticsEvent.PROJECT_MEMBERS_INVITE_SENT);
try {
await pmStore.getProjectMembers(1, selectedProjectID.value);
} catch (error) { /* empty */ }