diff --git a/src/dashboards/MasterCorporate/MasterStatistical.tsx b/src/dashboards/MasterCorporate/MasterStatistical.tsx
index 8978395a..8d3fb70b 100644
--- a/src/dashboards/MasterCorporate/MasterStatistical.tsx
+++ b/src/dashboards/MasterCorporate/MasterStatistical.tsx
@@ -343,7 +343,7 @@ const MasterStatistical = (props: Props) => {
{renderSearch()}
-
diff --git a/src/pages/api/assignments/statistical/excel.ts b/src/pages/api/assignments/statistical/excel.ts
index 7eed838d..43345e88 100644
--- a/src/pages/api/assignments/statistical/excel.ts
+++ b/src/pages/api/assignments/statistical/excel.ts
@@ -1,254 +1,229 @@
-import type { NextApiRequest, NextApiResponse } from "next";
-import { storage } from "@/firebase";
-import { withIronSessionApiRoute } from "iron-session/next";
-import { sessionOptions } from "@/lib/session";
-import { ref, uploadBytes, getDownloadURL } from "firebase/storage";
-import { AssignmentWithCorporateId } from "@/interfaces/results";
+import type {NextApiRequest, NextApiResponse} from "next";
+import {storage} from "@/firebase";
+import {withIronSessionApiRoute} from "iron-session/next";
+import {sessionOptions} from "@/lib/session";
+import {ref, uploadBytes, getDownloadURL} from "firebase/storage";
+import {AssignmentWithCorporateId} from "@/interfaces/results";
import moment from "moment-timezone";
import ExcelJS from "exceljs";
-import { getSpecificUsers } from "@/utils/users.be";
-import { checkAccess } from "@/utils/permissions";
-import { getAssignmentsForCorporates } from "@/utils/assignments.be";
-import { search } from "@/utils/search";
-import { getGradingSystem } from "@/utils/grading.be";
-import { User } from "@/interfaces/user";
-import { calculateBandScore, getGradingLabel } from "@/utils/score";
-import { Module } from "@/interfaces";
+import {getSpecificUsers} from "@/utils/users.be";
+import {checkAccess} from "@/utils/permissions";
+import {getAssignmentsForCorporates} from "@/utils/assignments.be";
+import {search} from "@/utils/search";
+import {getGradingSystem} from "@/utils/grading.be";
+import {User} from "@/interfaces/user";
+import {calculateBandScore, getGradingLabel} from "@/utils/score";
+import {Module} from "@/interfaces";
export default withIronSessionApiRoute(handler, sessionOptions);
interface TableData {
- user: string;
- email: string;
- correct: number;
- corporate: string;
- submitted: boolean;
- date: moment.Moment;
- assignment: string;
- corporateId: string;
- score: number;
- level: string;
- part1?: string;
- part2?: string;
- part3?: string;
- part4?: string;
- part5?: string;
+ user: string;
+ email: string;
+ correct: number;
+ corporate: string;
+ submitted: boolean;
+ date: moment.Moment;
+ assignment: string;
+ corporateId: string;
+ score: number;
+ level: string;
+ part1?: string;
+ part2?: string;
+ part3?: string;
+ part4?: string;
+ part5?: string;
}
async function handler(req: NextApiRequest, res: NextApiResponse) {
- // if (req.method === "GET") return get(req, res);
- if (req.method === "POST") return await post(req, res);
+ // if (req.method === "GET") return get(req, res);
+ if (req.method === "POST") return await post(req, res);
}
const searchFilters = [["email"], ["user"], ["userId"]];
async function post(req: NextApiRequest, res: NextApiResponse) {
- // verify if it's a logged user that is trying to export
- if (req.session.user) {
- if (
- !checkAccess(req.session.user, ["mastercorporate", "corporate", "developer", "admin"])
- ) {
- return res.status(403).json({ error: "Unauthorized" });
- }
- const {
- ids,
- startDate,
- endDate,
- searchText,
- displaySelection = true,
- } = req.body as {
- ids: string[];
- startDate?: string;
- endDate?: string;
- searchText: string;
- displaySelection?: boolean;
- };
- const startDateParsed = startDate ? new Date(startDate) : undefined;
- const endDateParsed = endDate ? new Date(endDate) : undefined;
- const assignments = await getAssignmentsForCorporates(
- ids,
- startDateParsed,
- endDateParsed
- );
+ // verify if it's a logged user that is trying to export
+ if (req.session.user) {
+ if (!checkAccess(req.session.user, ["mastercorporate", "corporate", "developer", "admin"])) {
+ return res.status(403).json({error: "Unauthorized"});
+ }
+ const {
+ ids,
+ startDate,
+ endDate,
+ searchText,
+ displaySelection = true,
+ } = req.body as {
+ ids: string[];
+ startDate?: string;
+ endDate?: string;
+ searchText: string;
+ displaySelection?: boolean;
+ };
+ const startDateParsed = startDate ? new Date(startDate) : undefined;
+ const endDateParsed = endDate ? new Date(endDate) : undefined;
+ const assignments = await getAssignmentsForCorporates(ids, startDateParsed, endDateParsed);
- const assignmentUsers = [
- ...new Set(assignments.flatMap((a) => a.assignees)),
- ];
- const assigners = [...new Set(assignments.map((a) => a.assigner))];
- const users = await getSpecificUsers(assignmentUsers);
- const assignerUsers = await getSpecificUsers(assigners);
+ const assignmentUsers = [...new Set(assignments.flatMap((a) => a.assignees))];
+ const assigners = [...new Set(assignments.map((a) => a.assigner))];
+ const users = await getSpecificUsers(assignmentUsers);
+ const assignerUsers = await getSpecificUsers(assigners);
- const assignerUsersGradingSystems = await Promise.all(
- assignerUsers.map(async (user: User) => {
- const data = await getGradingSystem(user);
- // in this context I need to override as I'll have to match to the assigner
- return { ...data, user: user.id };
- })
- );
+ const assignerUsersGradingSystems = await Promise.all(
+ assignerUsers.map(async (user: User) => {
+ const data = await getGradingSystem(user);
+ // in this context I need to override as I'll have to match to the assigner
+ return {...data, user: user.id};
+ }),
+ );
- const getGradingSystemHelper = (
- exams: { id: string; module: Module; assignee: string }[],
- assigner: string,
- user: User,
- correct: number,
- total: number
- ) => {
- if (exams.some((e) => e.module === "level")) {
- const gradingSystem = assignerUsersGradingSystems.find(
- (gs) => gs.user === assigner
- );
- if (gradingSystem) {
- const bandScore = calculateBandScore(
- correct,
- total,
- "level",
- user.focus
- );
- return {
- label: getGradingLabel(bandScore, gradingSystem?.steps || []),
- score: bandScore,
- };
- }
- }
+ const getGradingSystemHelper = (
+ exams: {id: string; module: Module; assignee: string}[],
+ assigner: string,
+ user: User,
+ correct: number,
+ total: number,
+ ) => {
+ if (exams.some((e) => e.module === "level")) {
+ const gradingSystem = assignerUsersGradingSystems.find((gs) => gs.user === assigner);
+ if (gradingSystem) {
+ const bandScore = calculateBandScore(correct, total, "level", user?.focus || "academic");
+ return {
+ label: getGradingLabel(bandScore, gradingSystem?.steps || []),
+ score: bandScore,
+ };
+ }
+ }
- return { score: -1, label: "N/A" };
- };
+ return {score: -1, label: "N/A"};
+ };
- const tableResults = assignments
- .reduce((accmA: TableData[], a: AssignmentWithCorporateId) => {
- const userResults = a.assignees.map((assignee) => {
- const userStats =
- a.results.find((r) => r.user === assignee)?.stats || [];
- const userData = users.find((u) => u.id === assignee);
- const corporateUser = users.find((u) => u.id === a.assigner);
- const correct = userStats.reduce((n, e) => n + e.score.correct, 0);
- const total = userStats.reduce((n, e) => n + e.score.total, 0);
- const { label: level, score } = getGradingSystemHelper(
- a.exams,
- a.assigner,
- userData!,
- correct,
- total
- );
+ const tableResults = assignments
+ .reduce((accmA: TableData[], a: AssignmentWithCorporateId) => {
+ const userResults = a.assignees.map((assignee) => {
+ const userStats = a.results.find((r) => r.user === assignee)?.stats || [];
+ const userData = users.find((u) => u.id === assignee);
+ const corporateUser = users.find((u) => u.id === a.assigner);
+ const correct = userStats.reduce((n, e) => n + e.score.correct, 0);
+ const total = userStats.reduce((n, e) => n + e.score.total, 0);
+ const {label: level, score} = getGradingSystemHelper(a.exams, a.assigner, userData!, correct, total);
- console.log("Level", level);
- const commonData = {
- user: userData?.name || "",
- email: userData?.email || "",
- userId: assignee,
- corporateId: a.corporateId,
- corporate: corporateUser?.name || "",
- assignment: a.name,
- level,
- score,
- };
- if (userStats.length === 0) {
- return {
- ...commonData,
- correct: 0,
- submitted: false,
- // date: moment(),
- };
- }
+ console.log("Level", level);
+ const commonData = {
+ user: userData?.name || "",
+ email: userData?.email || "",
+ userId: assignee,
+ corporateId: a.corporateId,
+ corporate: corporateUser?.name || "",
+ assignment: a.name,
+ level,
+ score,
+ };
+ if (userStats.length === 0) {
+ return {
+ ...commonData,
+ correct: 0,
+ submitted: false,
+ // date: moment(),
+ };
+ }
- const partsData = userStats.every((e) => e.module === "level")
- ? userStats.reduce((acc, e, index) => {
- return {
- ...acc,
- [`part${index}`]: `${e.score.correct}/${e.score.total}`,
- };
- }, {})
- : {};
+ const partsData = userStats.every((e) => e.module === "level")
+ ? userStats.reduce((acc, e, index) => {
+ return {
+ ...acc,
+ [`part${index}`]: `${e.score.correct}/${e.score.total}`,
+ };
+ }, {})
+ : {};
- return {
- ...commonData,
- correct,
- submitted: true,
- date: moment.max(userStats.map((e) => moment(e.date))),
- ...partsData,
- };
- }) as TableData[];
+ return {
+ ...commonData,
+ correct,
+ submitted: true,
+ date: moment.max(userStats.map((e) => moment(e.date))),
+ ...partsData,
+ };
+ }) as TableData[];
- return [...accmA, ...userResults];
- }, [])
- .sort((a, b) => b.score - a.score);
+ return [...accmA, ...userResults];
+ }, [])
+ .sort((a, b) => b.score - a.score);
- // Create a new workbook and add a worksheet
- const workbook = new ExcelJS.Workbook();
- const worksheet = workbook.addWorksheet("Master Statistical");
+ // Create a new workbook and add a worksheet
+ const workbook = new ExcelJS.Workbook();
+ const worksheet = workbook.addWorksheet("Master Statistical");
- const headers = [
- {
- label: "User",
- value: (entry: TableData) => entry.user,
- },
- {
- label: "Email",
- value: (entry: TableData) => entry.email,
- },
- ...(displaySelection
- ? [
- {
- label: "Corporate",
- value: (entry: TableData) => entry.corporate,
- },
- ]
- : []),
- {
- label: "Assignment",
- value: (entry: TableData) => entry.assignment,
- },
- {
- label: "Submitted",
- value: (entry: TableData) => (entry.submitted ? "Yes" : "No"),
- },
- {
- label: "Correct",
- value: (entry: TableData) => entry.correct,
- },
- {
- label: "Date",
- value: (entry: TableData) => entry.date?.format("YYYY/MM/DD") || "",
- },
- {
- label: "Level",
- value: (entry: TableData) => entry.level,
- },
- ...new Array(5).fill(0).map((_, index) => ({
- label: `Part ${index + 1}`,
- value: (entry: TableData) => {
- const key = `part${index}` as keyof TableData;
- return entry[key] || "";
- },
- })),
- ];
+ const headers = [
+ {
+ label: "User",
+ value: (entry: TableData) => entry.user,
+ },
+ {
+ label: "Email",
+ value: (entry: TableData) => entry.email,
+ },
+ ...(displaySelection
+ ? [
+ {
+ label: "Corporate",
+ value: (entry: TableData) => entry.corporate,
+ },
+ ]
+ : []),
+ {
+ label: "Assignment",
+ value: (entry: TableData) => entry.assignment,
+ },
+ {
+ label: "Submitted",
+ value: (entry: TableData) => (entry.submitted ? "Yes" : "No"),
+ },
+ {
+ label: "Correct",
+ value: (entry: TableData) => entry.correct,
+ },
+ {
+ label: "Date",
+ value: (entry: TableData) => entry.date?.format("YYYY/MM/DD") || "",
+ },
+ {
+ label: "Level",
+ value: (entry: TableData) => entry.level,
+ },
+ ...new Array(5).fill(0).map((_, index) => ({
+ label: `Part ${index + 1}`,
+ value: (entry: TableData) => {
+ const key = `part${index}` as keyof TableData;
+ return entry[key] || "";
+ },
+ })),
+ ];
- const filteredSearch = searchText
- ? search(searchText, searchFilters, tableResults)
- : tableResults;
+ const filteredSearch = searchText ? search(searchText, searchFilters, tableResults) : tableResults;
- worksheet.addRow(headers.map((h) => h.label));
- (filteredSearch as TableData[]).forEach((entry) => {
- worksheet.addRow(headers.map((h) => h.value(entry)));
- });
+ worksheet.addRow(headers.map((h) => h.label));
+ (filteredSearch as TableData[]).forEach((entry) => {
+ worksheet.addRow(headers.map((h) => h.value(entry)));
+ });
- // Convert workbook to Buffer (Node.js) or Blob (Browser)
- const buffer = await workbook.xlsx.writeBuffer();
+ // Convert workbook to Buffer (Node.js) or Blob (Browser)
+ const buffer = await workbook.xlsx.writeBuffer();
- // generate the file ref for storage
- const fileName = `${Date.now().toString()}.xlsx`;
- const refName = `statistical/${fileName}`;
- const fileRef = ref(storage, refName);
- // upload the pdf to storage
- await uploadBytes(fileRef, buffer, {
- contentType:
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- });
+ // generate the file ref for storage
+ const fileName = `${Date.now().toString()}.xlsx`;
+ const refName = `statistical/${fileName}`;
+ const fileRef = ref(storage, refName);
+ // upload the pdf to storage
+ await uploadBytes(fileRef, buffer, {
+ contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
- const url = await getDownloadURL(fileRef);
- res.status(200).end(url);
- return;
- }
+ const url = await getDownloadURL(fileRef);
+ res.status(200).end(url);
+ return;
+ }
- return res.status(401).json({ error: "Unauthorized" });
+ return res.status(401).json({error: "Unauthorized"});
}