diff --git a/src/exams/pdf/details/level.exam.tsx b/src/exams/pdf/details/level.exam.tsx
index 9230a7c0..9ab87a9b 100644
--- a/src/exams/pdf/details/level.exam.tsx
+++ b/src/exams/pdf/details/level.exam.tsx
@@ -5,6 +5,7 @@ import { styles } from "../styles";
import { RadialResult } from "./radial.result";
interface Props {
detail: ModuleScore;
+ title: string;
}
const thresholds = [
@@ -63,7 +64,7 @@ const customStyles = StyleSheet.create({
},
});
-export const LevelExamDetails = ({ detail }: Props) => {
+export const LevelExamDetails = ({ detail, title }: Props) => {
const updatedThresholds = thresholds.map((t) => ({
...t,
match: detail.score >= t.minValue && detail.score <= t.maxValue,
@@ -86,7 +87,7 @@ export const LevelExamDetails = ({ detail }: Props) => {
- Level as per CEFR Levels
+ {title}
diff --git a/src/exams/pdf/details/radial.result.tsx b/src/exams/pdf/details/radial.result.tsx
index 4bec5181..125983a2 100644
--- a/src/exams/pdf/details/radial.result.tsx
+++ b/src/exams/pdf/details/radial.result.tsx
@@ -1,39 +1,22 @@
/* eslint-disable jsx-a11y/alt-text */
import React from "react";
-import { View, Text, Image, StyleSheet } from "@react-pdf/renderer";
+import { View, Text, Image } from "@react-pdf/renderer";
import { styles } from "../styles";
import { ModuleScore } from "@/interfaces/module.scores";
-const customStyles = StyleSheet.create({
- container: {
- display: "flex",
- flexDirection: "column",
- alignItems: "center",
- gap: 4,
- position: "relative",
- },
- resultContainer: {
- display: "flex",
- position: "absolute",
- top: 0,
- left: 0,
- width: "100%",
- height: "100%",
- alignItems: "center",
- justifyContent: "center",
- fontSize: 10,
- gap: 8,
- },
-});
-
-export const RadialResult = ({ module, score, total, png }: ModuleScore) => (
-
-
- {module}
-
+export const RadialResult = ({
+ module,
+ score,
+ total,
+ png,
+}: ModuleScore) => (
+
+
+ {module}
+
-
+
{score}
out of {total}
diff --git a/src/exams/pdf/group.test.report.tsx b/src/exams/pdf/group.test.report.tsx
index 10535510..c7fa48b9 100644
--- a/src/exams/pdf/group.test.report.tsx
+++ b/src/exams/pdf/group.test.report.tsx
@@ -13,7 +13,6 @@ import { styles } from "./styles";
import TestReportFooter from "./test.report.footer";
import { ModuleScore, StudentData } from "@/interfaces/module.scores";
import ProgressBar from "./progress.bar";
-
Font.registerHyphenationCallback((word) => [word]);
interface Props {
@@ -32,6 +31,9 @@ interface Props {
institution: string;
studentsData: StudentData[];
showLevel: boolean;
+ summaryPNG: string;
+ summaryScore: string;
+ groupScoreSummary: any[];
}
const customStyles = StyleSheet.create({
@@ -44,13 +46,11 @@ const customStyles = StyleSheet.create({
flexDirection: "column",
// maxWidth: "600px",
// margin: "0 auto",
- border: "1px solid #ccc",
// borderCollapse: 'collapse',
},
tableRow: {
display: "flex",
flexDirection: "row",
- borderBottom: "1px solid #ccc",
},
tableHeader: {
fontWeight: "bold",
@@ -80,6 +80,9 @@ const GroupTestReport = ({
institution,
studentsData,
showLevel,
+ summaryPNG,
+ summaryScore,
+ groupScoreSummary,
}: Props) => {
const defaultTextStyle = [styles.textFont, { fontSize: 8 }];
const defaultSkillsTextStyle = [styles.textFont, { fontSize: 8 }];
@@ -150,8 +153,16 @@ const GroupTestReport = ({
>
Group Overall Performance Summary
-
- {summary}
+
+
+ {summary}
+
+
+
+
+ {summaryScore}
+
+
@@ -173,13 +184,44 @@ const GroupTestReport = ({
gap: 8,
}}
>
- {testDetails
- .filter(
- ({ suggestions, evaluation }) => suggestions || evaluation
- )
- .map(({ module, suggestions, evaluation }) => (
- TODO
+
+ {groupScoreSummary.map(({ label, percent, description }) => (
+
+
+ {label}
+
+
+
+
+
+ {percent}
+
+ {description}
+
))}
+
@@ -205,7 +247,7 @@ const GroupTestReport = ({
style={[
customStyles.table,
styles.textFont,
- { width: "100%", fontSize: "8px" },
+ { border: "1px solid #ccc", width: "100%", fontSize: "8px" },
]}
>
@@ -229,11 +272,17 @@ const GroupTestReport = ({
Result
- Level
+ {showLevel && Level}
{studentsData.map(
({ id, name, email, gender, date, result, level }, index) => (
-
+
{result}
- {level}
+ {showLevel && (
+ {level}
+ )}
)
)}
diff --git a/src/exams/pdf/progress.bar.tsx b/src/exams/pdf/progress.bar.tsx
index ef701132..7ee7060c 100644
--- a/src/exams/pdf/progress.bar.tsx
+++ b/src/exams/pdf/progress.bar.tsx
@@ -40,7 +40,7 @@ const ProgressBar = ({
>
diff --git a/src/exams/pdf/styles.ts b/src/exams/pdf/styles.ts
index 00bbc484..7cde6859 100644
--- a/src/exams/pdf/styles.ts
+++ b/src/exams/pdf/styles.ts
@@ -51,4 +51,23 @@ export const styles = StyleSheet.create({
width: "80px",
height: "80px",
},
+ radialContainer: {
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ gap: 4,
+ position: "relative",
+ },
+ radialResultContainer: {
+ display: "flex",
+ position: "absolute",
+ top: 0,
+ left: 0,
+ width: "100%",
+ height: "100%",
+ alignItems: "center",
+ justifyContent: "center",
+ fontSize: 10,
+ gap: 8,
+ },
});
diff --git a/src/interfaces/module.scores.ts b/src/interfaces/module.scores.ts
index 07d6c65e..2a4d4149 100644
--- a/src/interfaces/module.scores.ts
+++ b/src/interfaces/module.scores.ts
@@ -18,4 +18,5 @@ export interface ModuleScore {
date: string;
result: string;
level?: string;
+ bandScore: number;
}
\ No newline at end of file
diff --git a/src/pages/api/assignments/[id]/export.tsx b/src/pages/api/assignments/[id]/export.tsx
index 7e4e0867..d78fbaf3 100644
--- a/src/pages/api/assignments/[id]/export.tsx
+++ b/src/pages/api/assignments/[id]/export.tsx
@@ -32,6 +32,11 @@ import {
streamToBuffer,
} from "@/utils/pdf";
+interface GroupScoreSummaryHelper {
+ score: [number, number];
+ label: string;
+ sessions: string[];
+}
const db = getFirestore(app);
export default withIronSessionApiRoute(handler, sessionOptions);
@@ -99,13 +104,7 @@ const getScoreAndTotal = (stats: Stat[]) => {
);
};
-const getLevelScoreForUserExams = (
- correct: number,
- total: number,
- module: Module,
- focus: "academic" | "general"
-) => {
- const bandScore = calculateBandScore(correct, total, module, focus);
+const getLevelScoreForUserExams = (bandScore: number) => {
const [level] = getLevelScore(bandScore);
return level;
};
@@ -158,20 +157,45 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
[]
) as Stat[];
+ const docsSnap = await getDocs(
+ query(
+ collection(db, "users"),
+ where(documentId(), "in", data.assignees)
+ )
+ );
+ const users = docsSnap.docs.map((d) => ({
+ ...d.data(),
+ id: d.id,
+ })) as User[];
+
+ const flattenResultsWithGrade = flattenResults.map((e) => {
+ const focus = users.find((u) => u.id === e.user)?.focus || "academic";
+ const bandScore = calculateBandScore(
+ e.score.correct,
+ e.score.total,
+ e.module,
+ focus
+ );
+
+ return { ...e, bandScore };
+ });
+
const moduleResults = data.exams.map(({ module }) => {
- const moduleResults = flattenResults.filter(
+ const moduleResults = flattenResultsWithGrade.filter(
(e) => e.module === module
);
+ const bandScore =
+ moduleResults.reduce((accm, curr) => accm + curr.bandScore, 0) /
+ moduleResults.length;
const { correct, total } = getScoreAndTotal(moduleResults);
- const score = calculateBandScore(correct, total, module, "academic");
- const png = getRadialProgressPNG("azul", score, total);
+ const png = getRadialProgressPNG("azul", correct, total);
return {
- bandScore: score,
+ bandScore,
png,
module: module[0].toUpperCase() + module.substring(1),
- score,
+ score: bandScore,
total,
code: module,
};
@@ -181,12 +205,17 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
getScoreAndTotal(flattenResults);
const overallResult = overallCorrect / overallTotal;
+ const overallPNG = getRadialProgressPNG(
+ "laranja",
+ overallCorrect,
+ overallTotal
+ );
// generate the overall detail report
const overallDetail = {
module: "Overall",
score: overallCorrect,
total: overallTotal,
- png: getRadialProgressPNG("laranja", overallCorrect, overallTotal),
+ png: overallPNG,
} as ModuleScore;
const testDetails = [overallDetail, ...moduleResults];
@@ -207,7 +236,12 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
if (showLevel) {
return {
title: "GROUP ENGLISH LEVEL TEST RESULT REPORT ",
- details: ,
+ details: (
+
+ ),
};
}
@@ -222,21 +256,9 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
const numberOfStudents = data.assignees.length;
const getStudentsData = async (): Promise => {
- // const usersCol = collection(db, "users");
- const docsSnap = await getDocs(
- query(
- collection(db, "users"),
- where(documentId(), "in", data.assignees)
- )
- );
- const users = docsSnap.docs.map((d) => ({
- ...d.data(),
- id: d.id,
- })) as User[];
-
return data.assignees.map((id) => {
const user = users.find((u) => u.id === id);
- const exams = flattenResults.filter((e) => e.user === id);
+ const exams = flattenResultsWithGrade.filter((e) => e.user === id);
const date =
exams.length === 0
? "N/A"
@@ -246,6 +268,11 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
day: "numeric",
});
+ const bandScore =
+ exams.length === 0
+ ? 0
+ : exams.reduce((accm, curr) => accm + curr.bandScore, 0) /
+ exams.length;
const { correct, total } = getScoreAndTotal(exams);
const result = exams.length === 0 ? "N/A" : `${correct}/${total}`;
@@ -258,19 +285,60 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
date,
result,
level: showLevel
- ? getLevelScoreForUserExams(
- correct,
- total,
- baseStat.module,
- user?.focus || "academic"
- )
- : "",
+ ? getLevelScoreForUserExams(bandScore)
+ : undefined,
+ bandScore,
};
});
};
const studentsData = await getStudentsData();
+ const getGroupScoreSummary = () => {
+ const resultHelper = studentsData.reduce(
+ (accm: GroupScoreSummaryHelper[], curr) => {
+ const { bandScore, id } = curr;
+
+ const flooredScore = Math.floor(bandScore);
+
+ const hasMatch = accm.find((a) => a.score.includes(flooredScore));
+ if (hasMatch) {
+ return accm.map((a) => {
+ if (a.score.includes(flooredScore)) {
+ return {
+ ...a,
+ sessions: [...a.sessions, id],
+ };
+ }
+
+ return a;
+ });
+ }
+
+ return [
+ ...accm,
+ {
+ score: [flooredScore, flooredScore + 0.5],
+ label: `${flooredScore} - ${flooredScore + 0.5}`,
+ sessions: [id],
+ },
+ ];
+ },
+ []
+ ) as GroupScoreSummaryHelper[];
+
+ const result = resultHelper.map(({ label, sessions }) => {
+ return {
+ label,
+ percent: Math.floor((sessions.length / numberOfStudents) * 100),
+ description: `No. Candidates ${sessions.length} of ${numberOfStudents}`,
+ };
+ });
+ return result;
+ };
+
+ const groupScoreSummary = getGroupScoreSummary();
+
const pdfStream = await ReactPDF.renderToStream(
);
diff --git a/src/pages/api/stats/[id]/export.tsx b/src/pages/api/stats/[id]/export.tsx
index bb465278..23f89bc7 100644
--- a/src/pages/api/stats/[id]/export.tsx
+++ b/src/pages/api/stats/[id]/export.tsx
@@ -284,7 +284,12 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
if (stat.module === "level") {
return {
title: "ENGLISH LEVEL TEST RESULT REPORT ",
- details: ,
+ details: (
+
+ ),
};
}