From b4c0620f17ab3102e4baf92e8f5f38c7c369220a Mon Sep 17 00:00:00 2001 From: Emily Date: Wed, 6 Nov 2024 17:25:48 +0100 Subject: [PATCH] adjust admin dashboard --- dashboard/pages/admin/index.vue | 182 ++++++++++++------------- dashboard/server/api/admin/projects.ts | 84 +++++++----- 2 files changed, 138 insertions(+), 128 deletions(-) diff --git a/dashboard/pages/admin/index.vue b/dashboard/pages/admin/index.vue index 45db353..b1ab3c7 100644 --- a/dashboard/pages/admin/index.vue +++ b/dashboard/pages/admin/index.vue @@ -4,109 +4,65 @@ import type { AdminProjectsList } from '~/server/api/admin/projects'; definePageMeta({ layout: 'dashboard' }); -const { data: projects } = await useFetch('/api/admin/projects', signHeaders()); +const { data: projectsAggregatedResponseData } = await useFetch('/api/admin/projects', signHeaders()); const { data: counts } = await useFetch('/api/admin/counts', signHeaders()); - -type TProjectsGrouped = { - user: { - name: string, - email: string, - given_name: string, - picture: string, - created_at: Date - }, - projects: { - _id: string, - premium: boolean, - premium_type: number, - created_at: Date, - project_name: string, - total_visits: number, - total_events: number, - total_sessions: number - }[] -} - -const projectsGrouped = computed(() => { - - if (!projects.value) return []; - - const result: TProjectsGrouped[] = []; - - for (const project of projects.value) { - - if (!project.user) continue; - - - const target = result.find(e => e.user.email == project.user.email); - - if (target) { - - target.projects.push({ - _id: project._id, - created_at: project.created_at, - premium_type: project.premium_type, - premium: project.premium, - project_name: project.project_name, - total_events: project.total_events, - total_visits: project.total_visits, - total_sessions: project.total_sessions - }); - - } else { - - const item: TProjectsGrouped = { - user: project.user, - projects: [{ - _id: project._id, - created_at: project.created_at, - premium: project.premium, - premium_type: project.premium_type, - project_name: project.project_name, - total_events: project.total_events, - total_visits: project.total_visits, - total_sessions: project.total_sessions - }] - } - - result.push(item); - - } - - } - - result.sort((sa, sb) => { - const ca = sa.projects.reduce((a, e) => a + (e.total_visits + e.total_events), 0); - const cb = sb.projects.reduce((a, e) => a + (e.total_visits + e.total_events), 0); - return cb - ca; - }) - - return result; - -}); - function onHideClicked() { isAdminHidden.value = true; } + +const projectsAggregated = computed(() => { + return projectsAggregatedResponseData.value?.sort((a, b) => { + const sumVisitsA = a.projects.reduce((pa, pe) => pa + (pe.counts?.visits || 0) + (pe.counts?.events || 0), 0); + const sumVisitsB = b.projects.reduce((pa, pe) => pa + (pe.counts?.visits || 0) + (pe.counts?.events || 0), 0); + return sumVisitsB - sumVisitsA; + }); +}) + const premiumCount = computed(() => { let premiums = 0; - projects.value?.forEach(e => { - if (e.premium) premiums++; + projectsAggregated.value?.forEach(e => { + e.projects.forEach(p => { + if (p.premium) premiums++; + }); + }) return premiums; }) +const activeProjects = computed(() => { + let actives = 0; + + projectsAggregated.value?.forEach(e => { + e.projects.forEach(p => { + if (!p.counts) return; + if (!p.counts.updated_at) return; + const updated_at = new Date(p.counts.updated_at).getTime(); + if (updated_at < Date.now() - 1000 * 60 * 60 * 24) return; + actives++; + }); + }) + return actives; +}); + + const totalVisits = computed(() => { - return projects.value?.reduce((a, e) => a + e.total_visits, 0) || 0; + return projectsAggregated.value?.reduce((a, e) => { + return a + e.projects.reduce((pa, pe) => pa + (pe.counts?.visits || 0), 0); + }, 0) || 0; }); + const totalEvents = computed(() => { - return projects.value?.reduce((a, e) => a + e.total_events, 0) || 0; + return projectsAggregated.value?.reduce((a, e) => { + return a + e.projects.reduce((pa, pe) => pa + (pe.counts?.events || 0), 0); + }, 0) || 0; }); + + const details = ref(); const showDetails = ref(false); async function getProjectDetails(project_id: string) { @@ -118,6 +74,28 @@ async function resetCount(project_id: string) { await $fetch(`/api/admin/reset_count?project_id=${project_id}`, signHeaders()); } + +function dateDiffDays(a: string) { + return (Date.now() - new Date(a).getTime()) / (1000 * 60 * 60 * 24) +} + +function getLogBg(last_logged_at?: string) { + + const day = 1000 * 60 * 60 * 24; + const week = 1000 * 60 * 60 * 24 * 7; + + const lastLoggedAtDate = new Date(last_logged_at || 0); + + if (lastLoggedAtDate.getTime() > Date.now() - day) { + return 'bg-green-500' + } else if (lastLoggedAtDate.getTime() > Date.now() - week) { + return 'bg-yellow-500' + } else { + return 'bg-red-500' + } + +} + @@ -144,7 +122,7 @@ async function resetCount(project_id: string) { -
+
Users: {{ counts?.users }}
@@ -154,6 +132,10 @@ async function resetCount(project_id: string) {
Total visits: {{ formatNumberK(totalVisits) }}
+
+ Active: {{ activeProjects }} | + Dead: {{ (counts?.projects || 0) - activeProjects }} +
Total events: {{ formatNumberK(totalEvents) }}
@@ -162,17 +144,29 @@ async function resetCount(project_id: string) { -
+ + + + +
-
{{ item.user.email }}
-
{{ item.user.name }}
+
{{ item.email }}
+
{{ item.name }}
-
+
+
+ class="flex relative flex-col items-center bg-bg p-6 rounded-xl"> + +
+
+
{{ dateDiffDays(project?.counts?.updated_at || '0').toFixed(0) }} days
+
+
{{ project.premium ? 'PREMIUM' : 'FREE' }}
@@ -181,14 +175,14 @@ async function resetCount(project_id: string) {
-
{{ project.project_name }}
+
{{ project.name }}
Visits:
-
{{ project.total_visits }}
+
{{ formatNumberK(project.counts?.visits || 0) }}
Events:
-
{{ project.total_events }}
+
{{ formatNumberK(project.counts?.events || 0) }}
Sessions:
-
{{ project.total_sessions }}
+
{{ formatNumberK(project.counts?.sessions || 0) }}
diff --git a/dashboard/server/api/admin/projects.ts b/dashboard/server/api/admin/projects.ts index c4f63d5..e4aa918 100644 --- a/dashboard/server/api/admin/projects.ts +++ b/dashboard/server/api/admin/projects.ts @@ -1,21 +1,24 @@ -import { ProjectModel } from "@schema/ProjectSchema"; +import { UserModel } from "@schema/UserSchema"; export type AdminProjectsList = { - premium: boolean, - created_at: Date, - project_name: string, - premium_type: number, _id: string, - user: { + name: string, + given_name: string, + created_at: string, + email: string, + projects: { + _id: string, + owner: string, name: string, - email: string, - given_name: string, - picture: string, - created_at: Date - }, - total_visits: number, - total_events: number, - total_sessions: number + premium: boolean, + premium_type: number, + customer_id: string, + subscription_id: string, + premium_expire_at: string, + created_at: string, + __v: number, + counts: { _id: string, project_id: string, events: number, visits: number, sessions: number, updated_at?: string } + }[], } export default defineEventHandler(async event => { @@ -24,40 +27,53 @@ export default defineEventHandler(async event => { if (!userData?.logged) return; if (!userData.user.roles.includes('ADMIN')) return; - const data: AdminProjectsList[] = await ProjectModel.aggregate([ + const data: AdminProjectsList[] = await UserModel.aggregate([ { $lookup: { - from: "users", - localField: "owner", - foreignField: "_id", - as: "user" + from: "projects", + localField: "_id", + foreignField: "owner", + as: "projects" + } + }, + { + $unwind: { + path: "$projects", + preserveNullAndEmptyArrays: true } }, { $lookup: { from: "project_counts", - localField: "_id", + localField: "projects._id", foreignField: "project_id", - as: "counts" + as: "projects.counts" } }, { - $project: { - project_name: "$name", - premium: 1, - premium_type: 1, - created_at: 1, - user: { - $first: "$user" + $addFields: { + "projects.counts": { + $arrayElemAt: ["$projects.counts", 0] + } + } + }, + { + $group: { + _id: "$_id", + name: { + $first: "$name" }, - total_visits: { - $arrayElemAt: ["$counts.visits", 0] + given_name: { + $first: "$given_name" }, - total_events: { - $arrayElemAt: ["$counts.events", 0] + created_at: { + $first: "$created_at" }, - total_sessions: { - $arrayElemAt: ["$counts.sessions", 0] + email: { + $first: "$email" + }, + projects: { + $push: "$projects" } } }