ENCOA-314 :

- Implemented Async Select
- Changed Stats Page User fetching to use Async Select and only fetch the User data when it needs
- Changed Record Filter to use Async Select
- Changed useTicketListener to only fetch needed data
- Added Sort/Projection to remove unnecessary data processing.
- Removed some unnecessary data processing.
This commit is contained in:
José Marques Lima
2025-01-20 02:52:39 +00:00
parent 205449e1ae
commit ae9a49681e
17 changed files with 1856 additions and 1043 deletions

View File

@@ -26,7 +26,7 @@ async function get(req: NextApiRequest, res: NextApiResponse) {
const q = user ? { user: user } : {};
const sessions = await db.collection("sessions").find<Session>({
...q,
}).limit(12).toArray();
}).limit(12).sort({ date: -1 }).toArray();
console.log(sessions)
res.status(200).json(

View File

@@ -15,7 +15,10 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
}
const {user} = req.query;
const snapshot = await db.collection("stats").find({ user: user }).toArray();
const snapshot = await db.collection("stats").aggregate([
{ $match: { user: user } },
{ $sort: { "date": 1 } }
]).toArray();
res.status(200).json(snapshot);
}

View File

@@ -0,0 +1,39 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { Ticket, TicketWithCorporate } from "@/interfaces/ticket";
import { sessionOptions } from "@/lib/session";
import client from "@/lib/mongodb";
import { withIronSessionApiRoute } from "iron-session/next";
import type { NextApiRequest, NextApiResponse } from "next";
import { Group, CorporateUser } from "@/interfaces/user";
const db = client.db(process.env.MONGODB_DB);
export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) {
// specific logic for the preflight request
if (req.method === "OPTIONS") {
res.status(200).end();
return;
}
if (!req.session.user) {
res.status(401).json({ ok: false });
return;
}
if (req.method === "GET") {
await get(req, res);
}
}
async function get(req: NextApiRequest, res: NextApiResponse) {
if (!req.session.user) {
res.status(401).json({ ok: false });
return;
}
const docs = await db.collection("tickets").find<Ticket>({ assignedTo: req.session.user.id }).toArray();
res.status(200).json(docs);
}

View File

@@ -0,0 +1,39 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { withIronSessionApiRoute } from "iron-session/next";
import { sessionOptions } from "@/lib/session";
import { searchUsers } from "@/utils/users.be";
import { Type } from "@/interfaces/user";
export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!req.session.user && !req.headers["page"] && req.headers["page"] !== "register") {
res.status(401).json({ ok: false });
return;
}
const {
value,
size,
page,
orderBy = "name",
direction = "asc",
type,
entities
} = req.query as { value?: string, size?: string; type?: Type; page?: string; orderBy?: string; direction?: "asc" | "desc", entities?: string };
const { users, total } = await searchUsers(
value,
size !== undefined ? parseInt(size) : undefined,
page !== undefined ? parseInt(page) : undefined,
{
[orderBy]: direction === "asc" ? 1 : -1,
},
{},
{
...(type ? { "type": type } : {}),
...(entities ? { "entities.id": entities.split(',') } : {})
}
);
res.status(200).json({ users, total });
}

View File

@@ -21,11 +21,9 @@ import useTrainingContentStore from "@/stores/trainingContentStore";
import { Assignment } from "@/interfaces/results";
import { getEntitiesUsers, getUsers } from "@/utils/users.be";
import { getAssignments, getEntitiesAssignments } from "@/utils/assignments.be";
import useGradingSystem from "@/hooks/useGrading";
import { findBy, mapBy, redirect, serialize } from "@/utils";
import { getEntitiesWithRoles } from "@/utils/entities.be";
import { checkAccess } from "@/utils/permissions";
import { getGroups, getGroupsByEntities } from "@/utils/groups.be";
import { getGradingSystemByEntities, getGradingSystemByEntity } from "@/utils/grading.be";
import { Grading } from "@/interfaces";
import { EntityWithRoles } from "@/interfaces/entity";
@@ -40,14 +38,16 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
if (shouldRedirectHome(user)) return redirect("/")
const entityIDs = mapBy(user.entities, 'id')
const isAdmin = checkAccess(user, ["admin", "developer"])
const entities = await getEntitiesWithRoles(checkAccess(user, ["admin", "developer"]) ? undefined : entityIDs)
const users = await (checkAccess(user, ["admin", "developer"]) ? getUsers() : getEntitiesUsers(mapBy(entities, 'id')))
const assignments = await (checkAccess(user, ["admin", "developer"]) ? getAssignments() : getEntitiesAssignments(mapBy(entities, 'id')))
const gradingSystems = await getGradingSystemByEntities(mapBy(entities, 'id'))
const entitiesIds = mapBy(entities, 'id')
const users = await (isAdmin ? getUsers() : getEntitiesUsers(entitiesIds))
const assignments = await (isAdmin ? getAssignments() : getEntitiesAssignments(entitiesIds))
const gradingSystems = await getGradingSystemByEntities(entitiesIds)
return {
props: serialize({ user, users, assignments, entities, gradingSystems }),
props: serialize({ user, users, assignments, entities, gradingSystems,isAdmin }),
};
}, sessionOptions);
@@ -59,11 +59,12 @@ interface Props {
assignments: Assignment[];
entities: EntityWithRoles[]
gradingSystems: Grading[]
isAdmin:boolean
}
const MAX_TRAINING_EXAMS = 10;
export default function History({ user, users, assignments, entities, gradingSystems }: Props) {
export default function History({ user, users, assignments, entities, gradingSystems,isAdmin }: Props) {
const router = useRouter();
const [statsUserId, setStatsUserId, training, setTraining] = useRecordStore((state) => [
state.selectedUser,
@@ -193,7 +194,7 @@ export default function History({ user, users, assignments, entities, gradingSys
<ToastContainer />
{user && (
<Layout user={user}>
<RecordFilter user={user} users={users} entities={entities} filterState={{ filter: filter, setFilter: setFilter }}>
<RecordFilter user={user} isAdmin={isAdmin} entities={entities} filterState={{ filter: filter, setFilter: setFilter }}>
{training && (
<div className="flex flex-row">
<div className="font-semibold text-2xl mr-4">

File diff suppressed because it is too large Load Diff

View File

@@ -189,7 +189,7 @@ const Training: React.FC<{user: User, entities: EntityWithRoles[], users: User[]
</div>
) : (
<>
<RecordFilter users={users} entities={entities} user={user} filterState={{filter: filter, setFilter: setFilter}} assignments={false}>
<RecordFilter entities={entities} user={user} filterState={{filter: filter, setFilter: setFilter}} assignments={false}>
{user.type === "student" && (
<>
<div className="flex items-center">