From 314660d8a362db2b75b22cc0c6b115f848900077 Mon Sep 17 00:00:00 2001 From: Emily Date: Wed, 2 Oct 2024 17:05:34 +0200 Subject: [PATCH] change in progress --- .vscode/settings.json | 5 + dashboard/components/CVerticalNavigation.vue | 57 +------ dashboard/components/ProjectSelector.vue | 62 +++++++ dashboard/components/dashboard/TopCards.vue | 153 ++++++------------ dashboard/components/dashboard/TopSection.vue | 13 +- dashboard/composables/useAccessToken.ts | 33 ++-- dashboard/composables/useCustomFetch.ts | 93 +++-------- dashboard/composables/useLoggedUser.ts | 36 +++-- dashboard/composables/useProject.ts | 53 ++++++ dashboard/composables/useRefreshKey.ts | 8 + dashboard/middleware/01.client_auth.global.ts | 9 +- dashboard/pages/index.vue | 44 +---- dashboard/server/api/data/browsers.ts | 34 ++++ dashboard/server/api/data/count.ts | 49 ++---- dashboard/server/api/data/query.ts | 65 -------- .../api/{data => timeline}/bouncing_rate.ts | 35 ++-- dashboard/server/api/timeline/sessions.ts | 29 ++++ .../server/api/timeline/sessions_duration.ts | 35 ++++ dashboard/server/api/timeline/visits.ts | 29 ++++ dashboard/server/services/DataService.ts | 16 ++ dashboard/server/services/TimelineService.ts | 2 +- dashboard/server/utils/getRequestData.ts | 81 ++++++++++ 22 files changed, 503 insertions(+), 438 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 dashboard/components/ProjectSelector.vue create mode 100644 dashboard/composables/useProject.ts create mode 100644 dashboard/composables/useRefreshKey.ts create mode 100644 dashboard/server/api/data/browsers.ts delete mode 100644 dashboard/server/api/data/query.ts rename dashboard/server/api/{data => timeline}/bouncing_rate.ts (71%) create mode 100644 dashboard/server/api/timeline/sessions.ts create mode 100644 dashboard/server/api/timeline/sessions_duration.ts create mode 100644 dashboard/server/api/timeline/visits.ts create mode 100644 dashboard/server/services/DataService.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..83277f7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.exclude": { + "**/node_modules": true + } +} \ No newline at end of file diff --git a/dashboard/components/CVerticalNavigation.vue b/dashboard/components/CVerticalNavigation.vue index 92e41b1..6bde41b 100644 --- a/dashboard/components/CVerticalNavigation.vue +++ b/dashboard/components/CVerticalNavigation.vue @@ -27,8 +27,7 @@ type Props = { const route = useRoute(); const props = defineProps(); -const { isAdmin } = useUserRoles(); -const loggedUser = useLoggedUser() +const { user, userRoles, setLoggedUser } = useLoggedUser() const debugMode = process.dev; @@ -102,16 +101,8 @@ function onLogout() { } const { projects } = useProjectsList(); -const { data: guestProjects } = useGuestProjectsList() const activeProject = useActiveProject(); -const selectorProjects = computed(() => { - const result: TProject[] = []; - if (projects.value) result.push(...projects.value); - if (guestProjects.value) result.push(...guestProjects.value); - return result; -}); - const { data: maxProjects } = useFetch("/api/user/max_projects", { headers: computed(() => { return { @@ -120,21 +111,10 @@ const { data: maxProjects } = useFetch("/api/user/max_projects", { }) }); -const selected = ref(activeProject.value as TProject); -watch(selected, () => { - setActiveProject(selected.value._id.toString()) -}) - const isPremium = computed(() => { return activeProject.value?.premium; }) -function isProjectMine(owner?: string) { - if (!owner) return false; - if (!loggedUser.value?.logged) return; - return loggedUser.value.id == owner; -} - const pricingDrawer = usePricingDrawer(); @@ -158,36 +138,7 @@ const pricingDrawer = usePricingDrawer();
- - - - - - +
@@ -289,7 +240,7 @@ const pricingDrawer = usePricingDrawer();
-
- diff --git a/dashboard/components/ProjectSelector.vue b/dashboard/components/ProjectSelector.vue new file mode 100644 index 0000000..0ac15af --- /dev/null +++ b/dashboard/components/ProjectSelector.vue @@ -0,0 +1,62 @@ + + + \ No newline at end of file diff --git a/dashboard/components/dashboard/TopCards.vue b/dashboard/components/dashboard/TopCards.vue index bfbf14e..8013ecb 100644 --- a/dashboard/components/dashboard/TopCards.vue +++ b/dashboard/components/dashboard/TopCards.vue @@ -3,15 +3,45 @@ import DateService from '@services/DateService'; import type { Slice } from '@services/DateService'; -const { data: metricsInfo } = useMetricsData(); - const { snapshot, safeSnapshotDates } = useSnapshot() -const snapshotFrom = computed(() => new Date(snapshot.value?.from || '0').getTime()); -const snapshotTo = computed(() => new Date(snapshot.value?.to || Date.now()).getTime()); - const snapshotDays = computed(() => { - return (snapshotTo.value - snapshotFrom.value) / 1000 / 60 / 60 / 24; + const to = new Date(safeSnapshotDates.value.to).getTime(); + const from = new Date(safeSnapshotDates.value.from).getTime(); + return (to - from) / 1000 / 60 / 60 / 24; +}); + +const chartSlice = computed(() => { + const snapshotSizeMs = new Date(snapshot.value.to).getTime() - new Date(snapshot.value.from).getTime(); + if (snapshotSizeMs < 1000 * 60 * 60 * 24 * 6) return 'hour' as Slice; + if (snapshotSizeMs < 1000 * 60 * 60 * 24 * 30) return 'day' as Slice; + if (snapshotSizeMs < 1000 * 60 * 60 * 24 * 90) return 'day' as Slice; + return 'month' as Slice; +}); + + +function transformResponse(input: { _id: string, count: number }[]) { + const data = input.map(e => e.count || 0); + const labels = input.map(e => DateService.getChartLabelFromISO(e._id, navigator.language, chartSlice.value)); + const pool = [...input.map(e => e.count || 0)]; + pool.pop(); + const avg = pool.reduce((a, e) => a + e, 0) / pool.length; + const diffPercent: number = (100 / avg * (input.at(-1)?.count || 0)) - 100; + const trend = Math.max(Math.min(diffPercent, 99), -99); + return { data, labels, trend } +} + +const visitsData = useFetch('/api/timeline/visits', { + headers: useComputedHeaders({ slice: chartSlice.value }), lazy: true, transform: transformResponse +}); +const sessionsData = useFetch('/api/timeline/sessions', { + headers: useComputedHeaders({ slice: chartSlice.value }), lazy: true, transform: transformResponse +}); +const sessionsDurationData = useFetch('/api/timeline/sessions_duration', { + headers: useComputedHeaders({ slice: chartSlice.value }), lazy: true, transform: transformResponse +}); +const bouncingRateData = useFetch('/api/timeline/bouncing_rate', { + headers: useComputedHeaders({ slice: chartSlice.value }), lazy: true, transform: transformResponse }); const avgVisitDay = computed(() => { @@ -21,13 +51,6 @@ const avgVisitDay = computed(() => { return avg.toFixed(2); }); -// const avgEventsDay = computed(() => { -// if (!eventsData.data.value) return '0.00'; -// const counts = eventsData.data.value.data.reduce((a, e) => e + a, 0); -// const avg = counts / Math.max(snapshotDays.value, 1); -// return avg.toFixed(2); -// }); - const avgSessionsDay = computed(() => { if (!sessionsData.data.value) return '0.00'; const counts = sessionsData.data.value.data.reduce((a, e) => e + a, 0); @@ -47,8 +70,14 @@ const avgBouncingRate = computed(() => { }) const avgSessionDuration = computed(() => { - if (!metricsInfo.value) return '0.00'; - const avg = metricsInfo.value.avgSessionDuration; + if (!sessionsDurationData.data.value) return '0.00 %' + + const counts = sessionsDurationData.data.value.data + .filter(e => e > 0) + .reduce((a, e) => e + a, 0); + + const avg = counts / Math.max(sessionsDurationData.data.value.data.filter(e => e > 0).length, 1); + let hours = 0; let minutes = 0; let seconds = 0; @@ -59,91 +88,6 @@ const avgSessionDuration = computed(() => { }); - - -const chartSlice = computed(() => { - const snapshotSizeMs = new Date(snapshot.value.to).getTime() - new Date(snapshot.value.from).getTime(); - if (snapshotSizeMs < 1000 * 60 * 60 * 24 * 6) return 'hour' as Slice; - if (snapshotSizeMs < 1000 * 60 * 60 * 24 * 30) return 'day' as Slice; - if (snapshotSizeMs < 1000 * 60 * 60 * 24 * 90) return 'day' as Slice; - return 'month' as Slice; -}); - - -function transformResponse(input: { _id: string, count: number }[]) { - const data = input.map(e => e.count); - const labels = input.map(e => DateService.getChartLabelFromISO(e._id, navigator.language, chartSlice.value)); - const pool = [...input.map(e => e.count)]; - pool.pop(); - const avg = pool.reduce((a, e) => a + e, 0) / pool.length; - const diffPercent: number = (100 / avg * (input.at(-1)?.count || 0)) - 100; - const trend = Math.max(Math.min(diffPercent, 99), -99); - return { data, labels, trend } -} - -const activeProject = useActiveProject(); - -function getBody() { - return JSON.stringify({ - from: safeSnapshotDates.value.from, - to: safeSnapshotDates.value.to, - slice: chartSlice.value - }); -} - -const computedHeaders = computed(() => { - return { - ...signHeaders().headers, - 'x-pid': activeProject.value?._id.toString() || '', - 'x-from': safeSnapshotDates.value.from, - 'x-to': safeSnapshotDates.value.to, - 'x-slice': chartSlice.value - } -}) - -const visitsData = useFetch(`/api/metrics/${activeProject.value?._id}/timeline/visits`, { - method: 'POST', ...signHeaders({ v2: 'true' }), body: getBody(), transform: transformResponse, - lazy: true, immediate: false -}); - -// const eventsData = useFetch(`/api/metrics/${activeProject.value?._id}/timeline/events`, { -// method: 'POST', ...signHeaders({ v2: 'true' }), body: getBody(), transform: transformResponse, -// lazy: true, immediate: false -// }); - -const sessionsData = useFetch(`/api/metrics/${activeProject.value?._id}/timeline/sessions`, { - method: 'POST', ...signHeaders({ v2: 'true' }), body: getBody(), transform: transformResponse, - lazy: true, immediate: false -}); - -const sessionsDurationData = useFetch(`/api/metrics/${activeProject.value?._id}/timeline/sessions_duration`, { - method: 'POST', ...signHeaders({ v2: 'true' }), body: getBody(), transform: transformResponse, - lazy: true, immediate: false -}); - -const bouncingRateData = useFetch(`/api/data/bouncing_rate`, { - headers: computedHeaders, lazy: true, immediate: false, - transform: (input: { data: string, value: number | null }[]) => { - const data = input.map(e => e.value || 0); - const labels = input.map(e => DateService.getChartLabelFromISO(e.data, navigator.language, chartSlice.value)); - const pool = [...input.map(e => e.value || 0)]; - pool.pop(); - const avg = pool.reduce((a, e) => a + e, 0) / pool.length; - const diffPercent: number = (100 / avg * (input.at(-1)?.value || 0)) - 100; - const trend = Math.max(Math.min(diffPercent, 99), -99); - return { data, labels, trend } - } -}) - - -onMounted(async () => { - visitsData.execute(); - bouncingRateData.execute(); - sessionsData.execute(); - sessionsDurationData.execute() -}); - - @@ -157,8 +101,7 @@ onMounted(async () => { @@ -170,12 +113,12 @@ onMounted(async () => { -
- + \ No newline at end of file diff --git a/dashboard/components/dashboard/TopSection.vue b/dashboard/components/dashboard/TopSection.vue index 2f7f36c..80700d4 100644 --- a/dashboard/components/dashboard/TopSection.vue +++ b/dashboard/components/dashboard/TopSection.vue @@ -1,6 +1,8 @@