Skip to content

Commit b4c0620

Browse files
committed
adjust admin dashboard
1 parent b8c2e40 commit b4c0620

File tree

2 files changed

+137
-127
lines changed

2 files changed

+137
-127
lines changed

dashboard/pages/admin/index.vue

Lines changed: 87 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -4,109 +4,65 @@ import type { AdminProjectsList } from '~/server/api/admin/projects';
44
55
definePageMeta({ layout: 'dashboard' });
66
7-
const { data: projects } = await useFetch<AdminProjectsList[]>('/api/admin/projects', signHeaders());
7+
const { data: projectsAggregatedResponseData } = await useFetch<AdminProjectsList[]>('/api/admin/projects', signHeaders());
88
const { data: counts } = await useFetch('/api/admin/counts', signHeaders());
99
10-
11-
type TProjectsGrouped = {
12-
user: {
13-
name: string,
14-
email: string,
15-
given_name: string,
16-
picture: string,
17-
created_at: Date
18-
},
19-
projects: {
20-
_id: string,
21-
premium: boolean,
22-
premium_type: number,
23-
created_at: Date,
24-
project_name: string,
25-
total_visits: number,
26-
total_events: number,
27-
total_sessions: number
28-
}[]
10+
function onHideClicked() {
11+
isAdminHidden.value = true;
2912
}
3013
31-
const projectsGrouped = computed(() => {
32-
33-
if (!projects.value) return [];
34-
35-
const result: TProjectsGrouped[] = [];
36-
37-
for (const project of projects.value) {
38-
39-
if (!project.user) continue;
40-
41-
42-
const target = result.find(e => e.user.email == project.user.email);
43-
44-
if (target) {
45-
46-
target.projects.push({
47-
_id: project._id,
48-
created_at: project.created_at,
49-
premium_type: project.premium_type,
50-
premium: project.premium,
51-
project_name: project.project_name,
52-
total_events: project.total_events,
53-
total_visits: project.total_visits,
54-
total_sessions: project.total_sessions
55-
});
56-
57-
} else {
58-
59-
const item: TProjectsGrouped = {
60-
user: project.user,
61-
projects: [{
62-
_id: project._id,
63-
created_at: project.created_at,
64-
premium: project.premium,
65-
premium_type: project.premium_type,
66-
project_name: project.project_name,
67-
total_events: project.total_events,
68-
total_visits: project.total_visits,
69-
total_sessions: project.total_sessions
70-
}]
71-
}
7214
73-
result.push(item);
74-
75-
}
15+
const projectsAggregated = computed(() => {
16+
return projectsAggregatedResponseData.value?.sort((a, b) => {
17+
const sumVisitsA = a.projects.reduce((pa, pe) => pa + (pe.counts?.visits || 0) + (pe.counts?.events || 0), 0);
18+
const sumVisitsB = b.projects.reduce((pa, pe) => pa + (pe.counts?.visits || 0) + (pe.counts?.events || 0), 0);
19+
return sumVisitsB - sumVisitsA;
20+
});
21+
})
7622
77-
}
23+
const premiumCount = computed(() => {
24+
let premiums = 0;
25+
projectsAggregated.value?.forEach(e => {
26+
e.projects.forEach(p => {
27+
if (p.premium) premiums++;
28+
});
7829
79-
result.sort((sa, sb) => {
80-
const ca = sa.projects.reduce((a, e) => a + (e.total_visits + e.total_events), 0);
81-
const cb = sb.projects.reduce((a, e) => a + (e.total_visits + e.total_events), 0);
82-
return cb - ca;
8330
})
31+
return premiums;
32+
})
8433
85-
return result;
86-
87-
});
8834
89-
function onHideClicked() {
90-
isAdminHidden.value = true;
91-
}
35+
const activeProjects = computed(() => {
36+
let actives = 0;
9237
93-
const premiumCount = computed(() => {
94-
let premiums = 0;
95-
projects.value?.forEach(e => {
96-
if (e.premium) premiums++;
38+
projectsAggregated.value?.forEach(e => {
39+
e.projects.forEach(p => {
40+
if (!p.counts) return;
41+
if (!p.counts.updated_at) return;
42+
const updated_at = new Date(p.counts.updated_at).getTime();
43+
if (updated_at < Date.now() - 1000 * 60 * 60 * 24) return;
44+
actives++;
45+
});
9746
})
98-
return premiums;
99-
})
47+
return actives;
48+
});
10049
10150
10251
10352
const totalVisits = computed(() => {
104-
return projects.value?.reduce((a, e) => a + e.total_visits, 0) || 0;
53+
return projectsAggregated.value?.reduce((a, e) => {
54+
return a + e.projects.reduce((pa, pe) => pa + (pe.counts?.visits || 0), 0);
55+
}, 0) || 0;
10556
});
57+
10658
const totalEvents = computed(() => {
107-
return projects.value?.reduce((a, e) => a + e.total_events, 0) || 0;
59+
return projectsAggregated.value?.reduce((a, e) => {
60+
return a + e.projects.reduce((pa, pe) => pa + (pe.counts?.events || 0), 0);
61+
}, 0) || 0;
10862
});
10963
64+
65+
11066
const details = ref<any>();
11167
const showDetails = ref<boolean>(false);
11268
async function getProjectDetails(project_id: string) {
@@ -118,6 +74,28 @@ async function resetCount(project_id: string) {
11874
await $fetch(`/api/admin/reset_count?project_id=${project_id}`, signHeaders());
11975
}
12076
77+
78+
function dateDiffDays(a: string) {
79+
return (Date.now() - new Date(a).getTime()) / (1000 * 60 * 60 * 24)
80+
}
81+
82+
function getLogBg(last_logged_at?: string) {
83+
84+
const day = 1000 * 60 * 60 * 24;
85+
const week = 1000 * 60 * 60 * 24 * 7;
86+
87+
const lastLoggedAtDate = new Date(last_logged_at || 0);
88+
89+
if (lastLoggedAtDate.getTime() > Date.now() - day) {
90+
return 'bg-green-500'
91+
} else if (lastLoggedAtDate.getTime() > Date.now() - week) {
92+
return 'bg-yellow-500'
93+
} else {
94+
return 'bg-red-500'
95+
}
96+
97+
}
98+
12199
</script>
122100

123101

@@ -144,7 +122,7 @@ async function resetCount(project_id: string) {
144122

145123
<Card class="p-4">
146124

147-
<div class="grid grid-cols-2">
125+
<div class="grid grid-cols-2 gap-1">
148126
<div>
149127
Users: {{ counts?.users }}
150128
</div>
@@ -154,6 +132,10 @@ async function resetCount(project_id: string) {
154132
<div>
155133
Total visits: {{ formatNumberK(totalVisits) }}
156134
</div>
135+
<div>
136+
Active: {{ activeProjects }} |
137+
Dead: {{ (counts?.projects || 0) - activeProjects }}
138+
</div>
157139
<div>
158140
Total events: {{ formatNumberK(totalEvents) }}
159141
</div>
@@ -162,17 +144,29 @@ async function resetCount(project_id: string) {
162144
</Card>
163145

164146

165-
<div v-for="item of projectsGrouped" class="bg-menu p-4 rounded-xl flex flex-col gap-2 w-full relative">
147+
<Card>
148+
<!-- <USelectMenu></USelectMenu> -->
149+
</Card>
150+
151+
<div v-for="item of projectsAggregated || []"
152+
class="bg-menu p-4 rounded-xl flex flex-col gap-2 w-full relative">
166153
<div class="flex flex-col gap-6">
167154

168155
<div class="flex flex-col gap-1">
169-
<div> {{ item.user.email }} </div>
170-
<div> {{ item.user.name }} </div>
156+
<div> {{ item.email }} </div>
157+
<div> {{ item.name }} </div>
171158
</div>
172159

173-
<div class="flex justify-evenly flex-col lg:flex-row gap-2 lg:gap-0">
160+
<div class="flex justify-evenly flex-col lg:grid lg:grid-cols-3 gap-2 lg:gap-4">
161+
174162
<div v-for="project of item.projects"
175-
class="lg:w-[30%] flex flex-col items-center bg-bg p-6 rounded-xl">
163+
class="flex relative flex-col items-center bg-bg p-6 rounded-xl">
164+
165+
<div class="absolute left-2 top-2 flex items-center gap-2">
166+
<div :class="getLogBg(project?.counts?.updated_at)" class="h-3 w-3 rounded-full"> </div>
167+
<div> {{ dateDiffDays(project?.counts?.updated_at || '0').toFixed(0) }} days </div>
168+
</div>
169+
176170
<div class="flex gap-4">
177171
<div class="font-bold"> {{ project.premium ? 'PREMIUM' : 'FREE' }} </div>
178172
<div class="text-text-sub/90">
@@ -181,14 +175,14 @@ async function resetCount(project_id: string) {
181175
</div>
182176

183177

184-
<div class="text-ellipsis line-clamp-1"> {{ project.project_name }} </div>
178+
<div class="text-ellipsis line-clamp-1"> {{ project.name }} </div>
185179
<div class="flex gap-2">
186180
<div> Visits: </div>
187-
<div> {{ project.total_visits }} </div>
181+
<div> {{ formatNumberK(project.counts?.visits || 0) }} </div>
188182
<div> Events: </div>
189-
<div> {{ project.total_events }} </div>
183+
<div> {{ formatNumberK(project.counts?.events || 0) }} </div>
190184
<div> Sessions: </div>
191-
<div> {{ project.total_sessions }} </div>
185+
<div> {{ formatNumberK(project.counts?.sessions || 0) }} </div>
192186
</div>
193187

194188
<div class="flex gap-4 items-center mt-4">

dashboard/server/api/admin/projects.ts

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1-
import { ProjectModel } from "@schema/ProjectSchema";
1+
import { UserModel } from "@schema/UserSchema";
22

33
export type AdminProjectsList = {
4-
premium: boolean,
5-
created_at: Date,
6-
project_name: string,
7-
premium_type: number,
84
_id: string,
9-
user: {
5+
name: string,
6+
given_name: string,
7+
created_at: string,
8+
email: string,
9+
projects: {
10+
_id: string,
11+
owner: string,
1012
name: string,
11-
email: string,
12-
given_name: string,
13-
picture: string,
14-
created_at: Date
15-
},
16-
total_visits: number,
17-
total_events: number,
18-
total_sessions: number
13+
premium: boolean,
14+
premium_type: number,
15+
customer_id: string,
16+
subscription_id: string,
17+
premium_expire_at: string,
18+
created_at: string,
19+
__v: number,
20+
counts: { _id: string, project_id: string, events: number, visits: number, sessions: number, updated_at?: string }
21+
}[],
1922
}
2023

2124
export default defineEventHandler(async event => {
@@ -24,40 +27,53 @@ export default defineEventHandler(async event => {
2427
if (!userData?.logged) return;
2528
if (!userData.user.roles.includes('ADMIN')) return;
2629

27-
const data: AdminProjectsList[] = await ProjectModel.aggregate([
30+
const data: AdminProjectsList[] = await UserModel.aggregate([
2831
{
2932
$lookup: {
30-
from: "users",
31-
localField: "owner",
32-
foreignField: "_id",
33-
as: "user"
33+
from: "projects",
34+
localField: "_id",
35+
foreignField: "owner",
36+
as: "projects"
37+
}
38+
},
39+
{
40+
$unwind: {
41+
path: "$projects",
42+
preserveNullAndEmptyArrays: true
3443
}
3544
},
3645
{
3746
$lookup: {
3847
from: "project_counts",
39-
localField: "_id",
48+
localField: "projects._id",
4049
foreignField: "project_id",
41-
as: "counts"
50+
as: "projects.counts"
4251
}
4352
},
4453
{
45-
$project: {
46-
project_name: "$name",
47-
premium: 1,
48-
premium_type: 1,
49-
created_at: 1,
50-
user: {
51-
$first: "$user"
54+
$addFields: {
55+
"projects.counts": {
56+
$arrayElemAt: ["$projects.counts", 0]
57+
}
58+
}
59+
},
60+
{
61+
$group: {
62+
_id: "$_id",
63+
name: {
64+
$first: "$name"
65+
},
66+
given_name: {
67+
$first: "$given_name"
5268
},
53-
total_visits: {
54-
$arrayElemAt: ["$counts.visits", 0]
69+
created_at: {
70+
$first: "$created_at"
5571
},
56-
total_events: {
57-
$arrayElemAt: ["$counts.events", 0]
72+
email: {
73+
$first: "$email"
5874
},
59-
total_sessions: {
60-
$arrayElemAt: ["$counts.sessions", 0]
75+
projects: {
76+
$push: "$projects"
6177
}
6278
}
6379
}

0 commit comments

Comments
 (0)