Added integration with backend to fetch skills feedback

This commit is contained in:
Joao Ramos
2024-01-08 01:01:17 +00:00
parent 5e8e46ff09
commit e6c82412bf
2 changed files with 104 additions and 30 deletions

View File

@@ -3,6 +3,7 @@ import {Module} from "@/interfaces";
export interface ModuleScore { export interface ModuleScore {
score: number; score: number;
total: number; total: number;
code: Module;
module: Module | 'Overall'; module: Module | 'Overall';
feedback?: string, feedback?: string,
png?: string, png?: string,

View File

@@ -22,6 +22,10 @@ import { ModuleScore } from "@/interfaces/module.scores";
import qrcode from "qrcode"; import qrcode from "qrcode";
import { SkillExamDetails } from "@/exams/pdf/details/skill.exam"; import { SkillExamDetails } from "@/exams/pdf/details/skill.exam";
import { LevelExamDetails } from "@/exams/pdf/details/level.exam"; import { LevelExamDetails } from "@/exams/pdf/details/level.exam";
import { calculateBandScore } from "@/utils/score";
import axios from "axios";
import { moduleLabels } from "@/utils/moduleUtils";
const db = getFirestore(app); const db = getFirestore(app);
export default withIronSessionApiRoute(handler, sessionOptions); export default withIronSessionApiRoute(handler, sessionOptions);
@@ -115,6 +119,36 @@ const getFeedback = (module: Module) => {
} }
}; };
interface SkillsFeedbackRequest {
code: Module;
name: string;
grade: number;
}
interface SkillsFeedbackResponse extends SkillsFeedbackRequest {
evaluation: string;
suggestions: string;
}
const getSkillsFeedback = async (sections: SkillsFeedbackRequest[]) => {
try {
const backendRequest = await axios.post(
`${process.env.BACKEND_URL}/grading_summary`,
{ sections },
{
headers: {
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
},
}
);
return backendRequest.data?.sections;
} catch (err) {
console.log(err);
return null;
}
};
const generateQRCode = async (link: string) => { const generateQRCode = async (link: string) => {
try { try {
const qrCodeDataURL = await qrcode.toDataURL(link); const qrCodeDataURL = await qrcode.toDataURL(link);
@@ -125,14 +159,18 @@ const generateQRCode = async (link: string) => {
} }
}; };
type RADIAL_PROGRESS_COLOR = 'laranja' | 'azul'; type RADIAL_PROGRESS_COLOR = "laranja" | "azul";
const getRadialProgressPNG = (color: RADIAL_PROGRESS_COLOR, score: number, total: number) => { const getRadialProgressPNG = (
color: RADIAL_PROGRESS_COLOR,
score: number,
total: number
) => {
const percent = (score / total) * 100; const percent = (score / total) * 100;
const remainder = percent % 10; const remainder = percent % 10;
const roundedPercent = percent - remainder; const roundedPercent = percent - remainder;
return `public/radial_progress/${color}_${roundedPercent}.png`; return `public/radial_progress/${color}_${roundedPercent}.png`;
} };
async function post(req: NextApiRequest, res: NextApiResponse) { async function post(req: NextApiRequest, res: NextApiResponse) {
if (req.session.user) { if (req.session.user) {
@@ -163,37 +201,72 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
const user = docUser.data() as User; const user = docUser.data() as User;
const stats = docsSnap.docs.map((d) => d.data()); const stats = docsSnap.docs.map((d) => d.data());
const results = (stats.reduce((accm: ModuleScore[], { module, score }) => { const results = (
const fixedModuleStr = module[0].toUpperCase() + module.substring(1); stats.reduce((accm: ModuleScore[], { module, score }) => {
if (accm.find((e: ModuleScore) => e.module === fixedModuleStr)) { const fixedModuleStr = module[0].toUpperCase() + module.substring(1);
return accm.map((e: ModuleScore) => { if (accm.find((e: ModuleScore) => e.module === fixedModuleStr)) {
if (e.module === fixedModuleStr) { return accm.map((e: ModuleScore) => {
return { if (e.module === fixedModuleStr) {
...e, return {
score: e.score + score.correct, ...e,
total: e.total + score.total, score: e.score + score.correct,
}; total: e.total + score.total,
} };
}
return e; return e;
}); });
} }
return [ return [
...accm, ...accm,
{ {
module: fixedModuleStr, module: fixedModuleStr,
score: score.correct, score: score.correct,
total: score.total, total: score.total,
feedback: getFeedback(module), feedback: getFeedback(module),
}, code: module,
]; },
}, []) as ModuleScore[]).map((moduleScore) => { ];
}, []) as ModuleScore[]
).map((moduleScore) => {
const { score, total } = moduleScore; const { score, total } = moduleScore;
const bandScore = calculateBandScore(
score,
total,
moduleScore.code as Module,
user.focus
);
return { return {
...moduleScore, ...moduleScore,
png: getRadialProgressPNG('azul', score, total), png: getRadialProgressPNG("azul", score, total),
bandScore,
};
});
const skillsFeedback =
(await getSkillsFeedback(
results.map(({ code, bandScore }) => ({
code,
name: moduleLabels[code],
grade: bandScore,
}))
)) || ([] as SkillsFeedbackResponse[]);
const finalResults = results.map((result) => {
const feedback = skillsFeedback.find(
(f: SkillsFeedbackResponse) => f.code === result.module
);
if (feedback) {
return {
...result,
feedback: feedback?.evaluation + " " + feedback?.suggestions,
};
} }
return result;
}); });
const [stat] = stats as Stat[]; const [stat] = stats as Stat[];
@@ -211,9 +284,9 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
module: "Overall", module: "Overall",
score: overallScore, score: overallScore,
total: overallTotal, total: overallTotal,
png: getRadialProgressPNG('laranja', overallScore, overallTotal), png: getRadialProgressPNG("laranja", overallScore, overallTotal),
} as ModuleScore; } as ModuleScore;
const testDetails = [overallDetail, ...results]; const testDetails = [overallDetail, ...finalResults];
const renderDetails = () => { const renderDetails = () => {
if (stats[0].module === "level") { if (stats[0].module === "level") {
return <LevelExamDetails detail={overallDetail} />; return <LevelExamDetails detail={overallDetail} />;