Improved part of the performance of the dashboards
This commit is contained in:
@@ -28,6 +28,7 @@ export interface BasicUser {
|
||||
export interface StudentUser extends BasicUser {
|
||||
type: "student";
|
||||
studentID?: string;
|
||||
averageLevel?: number
|
||||
preferredGender?: InstructorGender;
|
||||
demographicInformation?: DemographicInformation;
|
||||
preferredTopics?: string[];
|
||||
|
||||
@@ -60,7 +60,6 @@ export default function ExamPage({ page, user, destination = "/", hideSidebar =
|
||||
setFlags,
|
||||
setShuffles,
|
||||
evaluated,
|
||||
setEvaluated,
|
||||
} = useExamStore();
|
||||
|
||||
const [isFetchingExams, setIsFetchingExams] = useState(false);
|
||||
|
||||
@@ -3,7 +3,7 @@ import {app} from "@/firebase";
|
||||
import { Module } from "@/interfaces";
|
||||
import { Stat, User } from "@/interfaces/user";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import {calculateBandScore} from "@/utils/score";
|
||||
import { calculateAverageLevel, calculateBandScore } from "@/utils/score";
|
||||
import { groupByModule, groupBySession } from "@/utils/stats";
|
||||
import { MODULE_ARRAY } from "@/utils/moduleUtils";
|
||||
import client from "@/lib/mongodb";
|
||||
@@ -100,9 +100,11 @@ async function update(req: NextApiRequest, res: NextApiResponse) {
|
||||
level: calculateBandScore(levelLevel.correct, levelLevel.total, "level", user.focus),
|
||||
};
|
||||
|
||||
const averageLevel = calculateAverageLevel(levels)
|
||||
|
||||
await db.collection("users").updateOne(
|
||||
{ id: user.id },
|
||||
{ $set: {levels} }
|
||||
{ $set: { levels, averageLevel } }
|
||||
);
|
||||
|
||||
res.status(200).json({ ok: true });
|
||||
|
||||
@@ -3,18 +3,18 @@ import Layout from "@/components/High/Layout";
|
||||
import UserDisplayList from "@/components/UserDisplayList";
|
||||
import IconCard from "@/components/IconCard";
|
||||
import { EntityWithRoles } from "@/interfaces/entity";
|
||||
import { Stat, Type, User } from "@/interfaces/user";
|
||||
import { Stat, StudentUser, Type, User } from "@/interfaces/user";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { dateSorter, filterBy, mapBy, redirect, serialize } from "@/utils";
|
||||
import { requestUser } from "@/utils/api";
|
||||
import { countEntitiesAssignments } from "@/utils/assignments.be";
|
||||
import { getEntitiesWithRoles } from "@/utils/entities.be";
|
||||
import { countGroupsByEntities } from "@/utils/groups.be";
|
||||
import { checkAccess } from "@/utils/permissions";
|
||||
import { checkAccess, findAllowedEntities } from "@/utils/permissions";
|
||||
import { calculateAverageLevel } from "@/utils/score";
|
||||
import { groupByExam } from "@/utils/stats";
|
||||
import { getStatsByUsers } from "@/utils/stats.be";
|
||||
import { countAllowedUsers, filterAllowedUsers } from "@/utils/users.be";
|
||||
import { countAllowedUsers, filterAllowedUsers, getUsers } from "@/utils/users.be";
|
||||
import { withIronSessionSsr } from "iron-session/next";
|
||||
import { uniqBy } from "lodash";
|
||||
import moment from "moment";
|
||||
@@ -37,7 +37,9 @@ import { isAdmin } from "@/utils/users";
|
||||
|
||||
interface Props {
|
||||
user: User;
|
||||
users: User[];
|
||||
students: StudentUser[]
|
||||
latestStudents: User[]
|
||||
latestTeachers: User[]
|
||||
userCounts: { [key in Type]: number }
|
||||
entities: EntityWithRoles[];
|
||||
assignmentsCount: number;
|
||||
@@ -53,21 +55,25 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
|
||||
const entityIDS = mapBy(user.entities, "id") || [];
|
||||
const entities = await getEntitiesWithRoles(isAdmin(user) ? undefined : entityIDS);
|
||||
const users = await filterAllowedUsers(user, entities)
|
||||
|
||||
const allowedStudentEntities = findAllowedEntities(user, entities, "view_students")
|
||||
const allowedTeacherEntities = findAllowedEntities(user, entities, "view_teachers")
|
||||
|
||||
const students =
|
||||
await getUsers({ type: 'student', "entities.id": { $in: mapBy(allowedStudentEntities, 'id') } }, 10, { averageLevel: -1 });
|
||||
const latestStudents =
|
||||
await getUsers({ type: 'student', "entities.id": { $in: mapBy(allowedStudentEntities, 'id') } }, 10, { registrationDate: -1 })
|
||||
const latestTeachers =
|
||||
await getUsers({ type: 'teacher', "entities.id": { $in: mapBy(allowedTeacherEntities, 'id') } }, 10, { registrationDate: -1 })
|
||||
|
||||
const userCounts = await countAllowedUsers(user, entities)
|
||||
const assignmentsCount = await countEntitiesAssignments(mapBy(entities, "id"), { archived: { $ne: true } });
|
||||
const groupsCount = await countGroupsByEntities(mapBy(entities, "id"));
|
||||
|
||||
const stats = await getStatsByUsers(users.map((u) => u.id));
|
||||
|
||||
return { props: serialize({ user, users, userCounts, entities, assignmentsCount, stats, groupsCount }) };
|
||||
return { props: serialize({ user, students, latestStudents, latestTeachers, userCounts, entities, assignmentsCount, groupsCount }) };
|
||||
}, sessionOptions);
|
||||
|
||||
export default function Dashboard({ user, users, userCounts, entities, assignmentsCount, stats, groupsCount }: Props) {
|
||||
const students = useMemo(() => users.filter((u) => u.type === "student"), [users]);
|
||||
const teachers = useMemo(() => users.filter((u) => u.type === "teacher"), [users]);
|
||||
|
||||
export default function Dashboard({ user, students, latestStudents, latestTeachers, userCounts, entities, assignmentsCount, stats = [], groupsCount }: Props) {
|
||||
const totalCount = useMemo(() =>
|
||||
userCounts.corporate + userCounts.mastercorporate + userCounts.student + userCounts.teacher, [userCounts])
|
||||
const totalLicenses = useMemo(() => entities.reduce((acc, curr) => acc + parseInt(curr.licenses.toString()), 0), [entities])
|
||||
@@ -159,15 +165,15 @@ export default function Dashboard({ user, users, userCounts, entities, assignmen
|
||||
|
||||
<section className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-between">
|
||||
<UserDisplayList
|
||||
users={students.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))}
|
||||
users={latestStudents}
|
||||
title="Latest Students"
|
||||
/>
|
||||
<UserDisplayList
|
||||
users={teachers.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))}
|
||||
users={latestTeachers}
|
||||
title="Latest Teachers"
|
||||
/>
|
||||
<UserDisplayList
|
||||
users={students.sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels))}
|
||||
users={students}
|
||||
title="Highest level students"
|
||||
/>
|
||||
<UserDisplayList
|
||||
|
||||
@@ -4,7 +4,7 @@ import UserDisplayList from "@/components/UserDisplayList";
|
||||
import IconCard from "@/components/IconCard";
|
||||
import { EntityWithRoles } from "@/interfaces/entity";
|
||||
import { Assignment } from "@/interfaces/results";
|
||||
import { Group, Stat, Type, User } from "@/interfaces/user";
|
||||
import { Group, Stat, StudentUser, Type, User } from "@/interfaces/user";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { dateSorter, filterBy, mapBy, redirect, serialize } from "@/utils";
|
||||
import { requestUser } from "@/utils/api";
|
||||
@@ -51,7 +51,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
|
||||
if (!checkAccess(user, ["admin", "developer"])) return redirect("/")
|
||||
|
||||
const students = await getUsers({ type: 'student' });
|
||||
const students = await getUsers({ type: 'student' }, 10, { averageLevel: -1 });
|
||||
const usersCount = {
|
||||
student: await countUsers({ type: "student" }),
|
||||
teacher: await countUsers({ type: "teacher" }),
|
||||
@@ -66,20 +66,18 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
const assignmentsCount = await countEntitiesAssignments(mapBy(entities, 'id'), { archived: { $ne: true } });
|
||||
const groupsCount = await countGroups();
|
||||
|
||||
const stats = await getStatsByUsers(mapBy(students, 'id'));
|
||||
|
||||
return { props: serialize({ user, students, latestStudents, latestTeachers, usersCount, entities, assignmentsCount, stats, groupsCount }) };
|
||||
return { props: serialize({ user, students, latestStudents, latestTeachers, usersCount, entities, assignmentsCount, groupsCount }) };
|
||||
}, sessionOptions);
|
||||
|
||||
export default function Dashboard({
|
||||
user,
|
||||
students,
|
||||
students = [],
|
||||
latestStudents,
|
||||
latestTeachers,
|
||||
usersCount,
|
||||
entities,
|
||||
assignmentsCount,
|
||||
stats,
|
||||
stats = [],
|
||||
groupsCount
|
||||
}: Props) {
|
||||
const router = useRouter();
|
||||
@@ -170,7 +168,7 @@ export default function Dashboard({
|
||||
title="Latest Teachers"
|
||||
/>
|
||||
<UserDisplayList
|
||||
users={students.sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels))}
|
||||
users={students}
|
||||
title="Highest level students"
|
||||
/>
|
||||
<UserDisplayList
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useAllowedEntities } from "@/hooks/useEntityPermissions";
|
||||
import { Module } from "@/interfaces";
|
||||
import { EntityWithRoles } from "@/interfaces/entity";
|
||||
import { Assignment } from "@/interfaces/results";
|
||||
import { Group, Stat, Type, User } from "@/interfaces/user";
|
||||
import { Group, Stat, StudentUser, Type, User } from "@/interfaces/user";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { dateSorter, filterBy, mapBy, redirect, serialize } from "@/utils";
|
||||
import { requestUser } from "@/utils/api";
|
||||
@@ -17,7 +17,7 @@ import { checkAccess, findAllowedEntities } from "@/utils/permissions";
|
||||
import { calculateAverageLevel, calculateBandScore } from "@/utils/score";
|
||||
import { groupByExam } from "@/utils/stats";
|
||||
import { getStatsByUsers } from "@/utils/stats.be";
|
||||
import { countAllowedUsers, filterAllowedUsers } from "@/utils/users.be";
|
||||
import { countAllowedUsers, filterAllowedUsers, getUsers } from "@/utils/users.be";
|
||||
import { getEntitiesUsers } from "@/utils/users.be";
|
||||
import { clsx } from "clsx";
|
||||
import { withIronSessionSsr } from "iron-session/next";
|
||||
@@ -44,7 +44,9 @@ import { isAdmin } from "@/utils/users";
|
||||
|
||||
interface Props {
|
||||
user: User;
|
||||
users: User[];
|
||||
students: StudentUser[]
|
||||
latestStudents: User[]
|
||||
latestTeachers: User[]
|
||||
userCounts: { [key in Type]: number }
|
||||
entities: EntityWithRoles[];
|
||||
assignmentsCount: number;
|
||||
@@ -56,25 +58,29 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
const user = await requestUser(req, res)
|
||||
if (!user || !user.isVerified) return redirect("/login")
|
||||
|
||||
if (!checkAccess(user, ["admin", "developer", "mastercorporate"]))
|
||||
return redirect("/")
|
||||
if (!checkAccess(user, ["admin", "developer", "corporate"])) return redirect("/")
|
||||
|
||||
const entityIDS = mapBy(user.entities, "id") || [];
|
||||
const entities = await getEntitiesWithRoles(isAdmin(user) ? undefined : entityIDS);
|
||||
const users = await filterAllowedUsers(user, entities)
|
||||
|
||||
const allowedStudentEntities = findAllowedEntities(user, entities, "view_students")
|
||||
const allowedTeacherEntities = findAllowedEntities(user, entities, "view_teachers")
|
||||
|
||||
const students =
|
||||
await getUsers({ type: 'student', "entities.id": { $in: mapBy(allowedStudentEntities, 'id') } }, 10, { averageLevel: -1 });
|
||||
const latestStudents =
|
||||
await getUsers({ type: 'student', "entities.id": { $in: mapBy(allowedStudentEntities, 'id') } }, 10, { registrationDate: -1 })
|
||||
const latestTeachers =
|
||||
await getUsers({ type: 'teacher', "entities.id": { $in: mapBy(allowedTeacherEntities, 'id') } }, 10, { registrationDate: -1 })
|
||||
|
||||
const userCounts = await countAllowedUsers(user, entities)
|
||||
const assignmentsCount = await countEntitiesAssignments(mapBy(entities, "id"), { archived: { $ne: true } });
|
||||
const groupsCount = await countGroupsByEntities(mapBy(entities, "id"));
|
||||
|
||||
const stats = await getStatsByUsers(users.map((u) => u.id));
|
||||
|
||||
return { props: serialize({ user, users, userCounts, entities, assignmentsCount, stats, groupsCount }) };
|
||||
return { props: serialize({ user, students, latestStudents, latestTeachers, userCounts, entities, assignmentsCount, groupsCount }) };
|
||||
}, sessionOptions);
|
||||
|
||||
export default function Dashboard({ user, users, userCounts, entities, assignmentsCount, stats, groupsCount }: Props) {
|
||||
const students = useMemo(() => users.filter((u) => u.type === "student"), [users]);
|
||||
const teachers = useMemo(() => users.filter((u) => u.type === "teacher"), [users]);
|
||||
export default function Dashboard({ user, students, latestStudents, latestTeachers, userCounts, entities, assignmentsCount, stats = [], groupsCount }: Props) {
|
||||
|
||||
const totalCount = useMemo(() =>
|
||||
userCounts.corporate + userCounts.mastercorporate + userCounts.student + userCounts.teacher, [userCounts])
|
||||
@@ -168,15 +174,15 @@ export default function Dashboard({ user, users, userCounts, entities, assignmen
|
||||
|
||||
<section className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-between">
|
||||
<UserDisplayList
|
||||
users={students.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))}
|
||||
users={latestStudents}
|
||||
title="Latest Students"
|
||||
/>
|
||||
<UserDisplayList
|
||||
users={teachers.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))}
|
||||
users={latestTeachers}
|
||||
title="Latest Teachers"
|
||||
/>
|
||||
<UserDisplayList
|
||||
users={students.sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels))}
|
||||
users={students}
|
||||
title="Highest level students"
|
||||
/>
|
||||
<UserDisplayList
|
||||
|
||||
@@ -32,7 +32,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res, query })
|
||||
const { assignment: assignmentID, destination } = query as { assignment?: string, destination?: string }
|
||||
const destinationURL = !!destination ? Buffer.from(destination, 'base64').toString() : undefined
|
||||
|
||||
if (assignmentID) {
|
||||
if (!!assignmentID) {
|
||||
const assignment = await getAssignment(assignmentID)
|
||||
|
||||
if (!assignment) return redirect(destinationURL || "/exam")
|
||||
|
||||
@@ -82,6 +82,17 @@ export const addUsersToEntity = async (users: string[], entity: string, role: st
|
||||
},
|
||||
);
|
||||
|
||||
export const removeUsersFromEntity = async (users: string[], entity: string) =>
|
||||
await db.collection("users").updateMany(
|
||||
{ id: { $in: users } },
|
||||
{
|
||||
// @ts-expect-error
|
||||
$pull: {
|
||||
entities: { id: entity },
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export const deleteEntity = async (entity: Entity) => {
|
||||
await db.collection("entities").deleteOne({ id: entity.id })
|
||||
await db.collection("roles").deleteMany({ entityID: entity.id })
|
||||
|
||||
@@ -14,6 +14,8 @@ export const getRolesByEntity = async (entityID: string) => await db.collection(
|
||||
export const getRoles = async (ids?: string[]) => await db.collection("roles").find<Role>(!ids ? {} : { id: { $in: ids } }).toArray();
|
||||
export const getRole = async (id: string) => (await db.collection("roles").findOne<Role>({ id })) ?? undefined;
|
||||
|
||||
export const getDefaultRole = async (entityID: string) => await db.collection("roles").findOne<Role>({ isDefault: true, entityID })
|
||||
|
||||
export const createRole = async (role: Role) => await db.collection("roles").insertOne(role)
|
||||
export const deleteRole = async (id: string) => await db.collection("roles").deleteOne({ id })
|
||||
|
||||
|
||||
Reference in New Issue
Block a user