|
|
|
|
@@ -1,7 +1,7 @@
|
|
|
|
|
import "server-only"
|
|
|
|
|
|
|
|
|
|
import { cache } from "react"
|
|
|
|
|
import { count, desc, eq, gt } from "drizzle-orm"
|
|
|
|
|
import { count, desc, eq, gt, inArray } from "drizzle-orm"
|
|
|
|
|
|
|
|
|
|
import { db } from "@/shared/db"
|
|
|
|
|
import {
|
|
|
|
|
@@ -11,9 +11,11 @@ import {
|
|
|
|
|
homeworkAssignments,
|
|
|
|
|
homeworkSubmissions,
|
|
|
|
|
questions,
|
|
|
|
|
roles,
|
|
|
|
|
sessions,
|
|
|
|
|
textbooks,
|
|
|
|
|
users,
|
|
|
|
|
usersToRoles,
|
|
|
|
|
} from "@/shared/db/schema"
|
|
|
|
|
import type { AdminDashboardData } from "./types"
|
|
|
|
|
|
|
|
|
|
@@ -23,7 +25,7 @@ export const getAdminDashboardData = cache(async (): Promise<AdminDashboardData>
|
|
|
|
|
const [
|
|
|
|
|
activeSessionsRow,
|
|
|
|
|
userCountRow,
|
|
|
|
|
userRoleRows,
|
|
|
|
|
userRoleCountRows,
|
|
|
|
|
classCountRow,
|
|
|
|
|
textbookCountRow,
|
|
|
|
|
chapterCountRow,
|
|
|
|
|
@@ -37,7 +39,11 @@ export const getAdminDashboardData = cache(async (): Promise<AdminDashboardData>
|
|
|
|
|
] = await Promise.all([
|
|
|
|
|
db.select({ value: count() }).from(sessions).where(gt(sessions.expires, now)),
|
|
|
|
|
db.select({ value: count() }).from(users),
|
|
|
|
|
db.select({ role: users.role, value: count() }).from(users).groupBy(users.role),
|
|
|
|
|
db
|
|
|
|
|
.select({ role: roles.name, value: count() })
|
|
|
|
|
.from(usersToRoles)
|
|
|
|
|
.innerJoin(roles, eq(usersToRoles.roleId, roles.id))
|
|
|
|
|
.groupBy(roles.name),
|
|
|
|
|
db.select({ value: count() }).from(classes),
|
|
|
|
|
db.select({ value: count() }).from(textbooks),
|
|
|
|
|
db.select({ value: count() }).from(chapters),
|
|
|
|
|
@@ -52,7 +58,6 @@ export const getAdminDashboardData = cache(async (): Promise<AdminDashboardData>
|
|
|
|
|
id: users.id,
|
|
|
|
|
name: users.name,
|
|
|
|
|
email: users.email,
|
|
|
|
|
role: users.role,
|
|
|
|
|
createdAt: users.createdAt,
|
|
|
|
|
})
|
|
|
|
|
.from(users)
|
|
|
|
|
@@ -72,17 +77,55 @@ export const getAdminDashboardData = cache(async (): Promise<AdminDashboardData>
|
|
|
|
|
const homeworkSubmissionCount = Number(homeworkSubmissionCountRow[0]?.value ?? 0)
|
|
|
|
|
const homeworkSubmissionToGradeCount = Number(homeworkSubmissionToGradeCountRow[0]?.value ?? 0)
|
|
|
|
|
|
|
|
|
|
const userRoleCounts = userRoleRows
|
|
|
|
|
const userRoleCounts = userRoleCountRows
|
|
|
|
|
.map((r) => ({ role: r.role ?? "unknown", count: Number(r.value ?? 0) }))
|
|
|
|
|
.sort((a, b) => b.count - a.count)
|
|
|
|
|
|
|
|
|
|
const recentUsers = recentUserRows.map((u) => ({
|
|
|
|
|
id: u.id,
|
|
|
|
|
name: u.name,
|
|
|
|
|
email: u.email,
|
|
|
|
|
role: u.role,
|
|
|
|
|
createdAt: u.createdAt.toISOString(),
|
|
|
|
|
}))
|
|
|
|
|
const normalizeRole = (value: string) => {
|
|
|
|
|
const role = value.trim().toLowerCase()
|
|
|
|
|
if (role === "grade_head" || role === "teaching_head") return "teacher"
|
|
|
|
|
if (role === "admin" || role === "student" || role === "teacher" || role === "parent") return role
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const recentUserIds = recentUserRows.map((u) => u.id)
|
|
|
|
|
const recentRoleRows = recentUserIds.length
|
|
|
|
|
? await db
|
|
|
|
|
.select({
|
|
|
|
|
userId: usersToRoles.userId,
|
|
|
|
|
roleName: roles.name,
|
|
|
|
|
})
|
|
|
|
|
.from(usersToRoles)
|
|
|
|
|
.innerJoin(roles, eq(usersToRoles.roleId, roles.id))
|
|
|
|
|
.where(inArray(usersToRoles.userId, recentUserIds))
|
|
|
|
|
: []
|
|
|
|
|
|
|
|
|
|
const rolesByUserId = new Map<string, string[]>()
|
|
|
|
|
for (const row of recentRoleRows) {
|
|
|
|
|
const list = rolesByUserId.get(row.userId) ?? []
|
|
|
|
|
list.push(row.roleName)
|
|
|
|
|
rolesByUserId.set(row.userId, list)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const resolvePrimaryRole = (roleNames: string[]) => {
|
|
|
|
|
const mapped = roleNames.map(normalizeRole).filter(Boolean)
|
|
|
|
|
if (mapped.includes("admin")) return "admin"
|
|
|
|
|
if (mapped.includes("teacher")) return "teacher"
|
|
|
|
|
if (mapped.includes("parent")) return "parent"
|
|
|
|
|
if (mapped.includes("student")) return "student"
|
|
|
|
|
return "student"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const recentUsers = recentUserRows.map((u) => {
|
|
|
|
|
const roleNames = rolesByUserId.get(u.id) ?? []
|
|
|
|
|
return {
|
|
|
|
|
id: u.id,
|
|
|
|
|
name: u.name,
|
|
|
|
|
email: u.email,
|
|
|
|
|
role: resolvePrimaryRole(roleNames),
|
|
|
|
|
createdAt: u.createdAt.toISOString(),
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
activeSessionsCount,
|
|
|
|
|
|