diff --git a/src/router.test.ts b/src/router.test.ts index cf68ad7158..1d65a01376 100644 --- a/src/router.test.ts +++ b/src/router.test.ts @@ -1,11 +1,18 @@ import Vue from 'vue'; import VueCompositionAPI from '@vue/composition-api'; import { Route } from 'vue-router'; -import { onBeforeEach, onBeforeEnterProjectChooser, replaceRoutes, defaultRoutes } from './router'; +import { + onBeforeEach, + onAfterEach, + onBeforeEnterProjectChooser, + replaceRoutes, + defaultRoutes +} from './router'; import api from '@/api'; import * as auth from '@/auth'; import { useProjectsStore } from '@/stores/projects'; import { hydrate } from '@/hydrate'; +import useUserStore from '@/stores/user'; jest.mock('@/auth'); jest.mock('@/hydrate'); @@ -257,4 +264,46 @@ describe('Router', () => { expect(handler).toHaveBeenCalledWith(defaultRoutes); }); }); + + describe('onAfterEach', () => { + it('Calls the userStore trackPage method after some time', () => { + jest.useFakeTimers(); + const userStore = useUserStore({}); + + jest.spyOn(userStore, 'trackPage'); + + const to = { + fullPath: '/test', + meta: { + public: false + } + } as any; + + onAfterEach(to); + + jest.runAllTimers(); + + expect(userStore.trackPage).toHaveBeenCalledWith('/test'); + }); + + it('Does not track the page for public pages', () => { + jest.useFakeTimers(); + const userStore = useUserStore({}); + + jest.spyOn(userStore, 'trackPage'); + + const to = { + fullPath: '/test', + meta: { + public: true + } + } as any; + + onAfterEach(to); + + jest.runAllTimers(); + + expect(userStore.trackPage).not.toHaveBeenCalledWith('/test'); + }); + }); }); diff --git a/src/router.ts b/src/router.ts index 37debedfb5..7a0c18e00d 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -import VueRouter, { NavigationGuard, RouteConfig } from 'vue-router'; +import VueRouter, { NavigationGuard, RouteConfig, Route } from 'vue-router'; import Debug from '@/routes/debug.vue'; import { useProjectsStore } from '@/stores/projects'; import LoginRoute from '@/routes/login'; @@ -7,6 +7,7 @@ import ProjectChooserRoute from '@/routes/project-chooser'; import { checkAuth } from '@/auth'; import { hydrate, dehydrate } from '@/hydrate'; import useAppStore from '@/stores/app'; +import useUserStore from '@/stores/user'; export const onBeforeEnterProjectChooser: NavigationGuard = (to, from, next) => { const projectsStore = useProjectsStore(); @@ -133,7 +134,20 @@ export const onBeforeEach: NavigationGuard = async (to, from, next) => { return next(); }; +export const onAfterEach = (to: Route) => { + const userStore = useUserStore(); + + if (to.meta.public !== true) { + // The timeout gives the page some breathing room to load. No need to clog up the thread with + // this call while more important things are loading + setTimeout(() => { + userStore.trackPage(to.fullPath); + }, 2500); + } +}; + router.beforeEach(onBeforeEach); +router.afterEach(onAfterEach); export default router; diff --git a/src/stores/user/user.test.ts b/src/stores/user/user.test.ts index 4be701dc4f..68112168e1 100644 --- a/src/stores/user/user.test.ts +++ b/src/stores/user/user.test.ts @@ -54,4 +54,40 @@ describe('Stores / User', () => { expect(userStore.reset).toHaveBeenCalled(); }); }); + + describe('Track Page', () => { + it('Calls the right endpoint on tracking', async () => { + const userStore = useUserStore(req); + const projectsStore = useProjectsStore(req); + + userStore.state.currentUser = { + id: 5, + last_page: 'test' + } as any; + + projectsStore.state.currentProjectKey = 'my-project'; + + await userStore.trackPage('/example'); + + expect(api.patch).toHaveBeenCalledWith('/my-project/users/me/tracking/page', { + last_page: '/example' + }); + }); + + it('Updates the store with the new last page', async () => { + const userStore = useUserStore(req); + const projectsStore = useProjectsStore(req); + + userStore.state.currentUser = { + id: 5, + last_page: 'test' + } as any; + + projectsStore.state.currentProjectKey = 'my-project'; + + await userStore.trackPage('/example'); + + expect(userStore.state.currentUser!.last_page).toBe('/example'); + }); + }); }); diff --git a/src/stores/user/user.ts b/src/stores/user/user.ts index 4bdb2ce8e5..2423cb425e 100644 --- a/src/stores/user/user.ts +++ b/src/stores/user/user.ts @@ -30,6 +30,18 @@ export const useUserStore = createStore({ }, async dehydrate() { this.reset(); + }, + async trackPage(page: string) { + const projectsStore = useProjectsStore(); + const currentProjectKey = projectsStore.state.currentProjectKey; + + await api.patch(`/${currentProjectKey}/users/me/tracking/page`, { + last_page: page + }); + + if (this.state.currentUser) { + this.state.currentUser.last_page = page; + } } } });