220 lines
4.0 KiB
TypeScript
220 lines
4.0 KiB
TypeScript
import {Module, Step} from "@/interfaces";
|
|
import {Stat, User} from "@/interfaces/user";
|
|
|
|
type Type = "academic" | "general";
|
|
|
|
export const writingReverseMarking: {[key: number]: number} = {
|
|
9: 90,
|
|
8.5: 85,
|
|
8: 80,
|
|
7.5: 75,
|
|
7: 70,
|
|
6.5: 65,
|
|
6: 60,
|
|
5.5: 55,
|
|
5: 50,
|
|
4.5: 45,
|
|
4: 40,
|
|
3.5: 35,
|
|
3: 30,
|
|
2.5: 25,
|
|
2: 20,
|
|
1.5: 15,
|
|
1: 10,
|
|
0.5: 5,
|
|
0: 0,
|
|
};
|
|
|
|
export const speakingReverseMarking: {[key: number]: number} = {
|
|
9: 90,
|
|
8.5: 85,
|
|
8: 80,
|
|
7.5: 75,
|
|
7: 70,
|
|
6.5: 65,
|
|
6: 60,
|
|
5.5: 55,
|
|
5: 50,
|
|
4.5: 45,
|
|
4: 40,
|
|
3.5: 35,
|
|
3: 30,
|
|
2.5: 25,
|
|
2: 20,
|
|
1.5: 15,
|
|
1: 10,
|
|
0.5: 5,
|
|
0: 0,
|
|
};
|
|
|
|
export const writingMarking: {[key: number]: number} = {
|
|
90: 9,
|
|
80: 8,
|
|
70: 7,
|
|
60: 6,
|
|
50: 5,
|
|
40: 4,
|
|
30: 3,
|
|
20: 2,
|
|
10: 1,
|
|
0: 0,
|
|
};
|
|
|
|
const readingGeneralMarking: {[key: number]: number} = {
|
|
100: 9,
|
|
97.5: 8.5,
|
|
92.5: 8,
|
|
90: 7.5,
|
|
85: 7,
|
|
80: 6.5,
|
|
75: 6,
|
|
67.5: 5.5,
|
|
57.5: 5,
|
|
45.5: 4.5,
|
|
37.5: 4,
|
|
30: 3.5,
|
|
22.5: 3,
|
|
15: 2.5,
|
|
};
|
|
|
|
const academicMarking: {[key: number]: number} = {
|
|
97.5: 9,
|
|
92.5: 8.5,
|
|
87.5: 8,
|
|
80: 7.5,
|
|
75: 7,
|
|
65: 6.5,
|
|
57.5: 6,
|
|
45: 5.5,
|
|
40: 5,
|
|
32.5: 4.5,
|
|
25: 4,
|
|
20: 3.5,
|
|
15: 3,
|
|
10: 2.5,
|
|
};
|
|
|
|
const levelMarking: {[key: number]: number} = {
|
|
88: 9, // Advanced
|
|
64: 8, // Upper-Intermediate
|
|
52: 6, // Intermediate
|
|
32: 4, // Pre-Intermediate
|
|
16: 2, // Elementary
|
|
0: 0, // Beginner
|
|
};
|
|
|
|
const moduleMarkings: {[key in Module | "overall"]: {[key in Type]: {[key: number]: number}}} = {
|
|
reading: {
|
|
academic: academicMarking,
|
|
general: readingGeneralMarking,
|
|
},
|
|
listening: {
|
|
academic: academicMarking,
|
|
general: academicMarking,
|
|
},
|
|
writing: {
|
|
academic: writingMarking,
|
|
general: writingMarking,
|
|
},
|
|
speaking: {
|
|
academic: writingMarking,
|
|
general: writingMarking,
|
|
},
|
|
level: {
|
|
academic: levelMarking,
|
|
general: levelMarking,
|
|
},
|
|
overall: {
|
|
academic: levelMarking,
|
|
general: levelMarking,
|
|
},
|
|
};
|
|
|
|
export const calculateBandScore = (correct: number, total: number, module: Module | "overall", type: Type) => {
|
|
const marking = moduleMarkings[module][type];
|
|
const percentage = (correct * 100) / total;
|
|
|
|
if (module === "level") return percentage;
|
|
|
|
for (const value of Object.keys(marking)
|
|
.map((x) => parseFloat(x))
|
|
.sort((a, b) => b - a)) {
|
|
if (percentage >= value) {
|
|
return marking[value];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
export const calculateAverageLevel = (levels: {[key in Module]: number}) => {
|
|
return (
|
|
Object.keys(levels)
|
|
.filter((x) => x !== "level")
|
|
.reduce((accumulator, current) => levels[current as Module] + accumulator, 0) / 4
|
|
);
|
|
};
|
|
|
|
export const getLevelScore = (level: number) => {
|
|
switch (level) {
|
|
case 0:
|
|
return ["Beginner", "Low A1"];
|
|
case 2:
|
|
return ["Elementary", "High A1/Low A2"];
|
|
case 4:
|
|
return ["Pre-Intermediate", "High A2/Low B1"];
|
|
case 6:
|
|
return ["Intermediate", "High B1/Low B2"];
|
|
case 8:
|
|
return ["Upper-Intermediate", "High B2/Low C1"];
|
|
case 9:
|
|
return ["Advanced", "C1"];
|
|
default:
|
|
return [];
|
|
}
|
|
};
|
|
|
|
export const getLevelLabel = (level: number) => {
|
|
if (level < 2) return ["Foundation", "Pre-A1"];
|
|
if (level < 4) return ["Elementary", "A1"];
|
|
if (level < 5) return ["Pre-intermediate", "A2"];
|
|
if (level < 6) return ["Intermediate", "B1"];
|
|
if (level < 7) return ["Upper Intermediate", "B2"];
|
|
if (level < 8) return ["Advanced", "C1"];
|
|
|
|
return ["Proficiency", "C2"];
|
|
};
|
|
|
|
export const getGradingLabel = (score: number, grading: Step[]) => {
|
|
for (const step of grading) {
|
|
if (score >= step.min && score <= step.max) return step.label;
|
|
}
|
|
|
|
return "N/A";
|
|
};
|
|
|
|
export const averageLevelCalculator = (users: User[], studentStats: Stat[]) => {
|
|
const formattedStats = studentStats
|
|
.map((s) => ({
|
|
focus: users.find((u) => u.id === s.user)?.focus,
|
|
score: s.score,
|
|
module: s.module,
|
|
}))
|
|
.filter((f) => !!f.focus);
|
|
const bandScores = formattedStats.map((s) => ({
|
|
module: s.module,
|
|
level: calculateBandScore(s.score.correct, s.score.total, s.module, s.focus!),
|
|
}));
|
|
|
|
const levels: {[key in Module]: number} = {
|
|
reading: 0,
|
|
listening: 0,
|
|
writing: 0,
|
|
speaking: 0,
|
|
level: 0,
|
|
};
|
|
bandScores.forEach((b) => (levels[b.module] += b.level));
|
|
|
|
return calculateAverageLevel(levels);
|
|
};
|