Merge branch 'develop' into feature/writing-diff-viewer

This commit is contained in:
Tiago Ribeiro
2024-01-17 12:58:44 +00:00
6 changed files with 66 additions and 202 deletions

View File

@@ -42,7 +42,7 @@ export default function StudentDashboard({user}: Props) {
const setAssignment = useExamStore((state) => state.setAssignment); const setAssignment = useExamStore((state) => state.setAssignment);
useEffect(() => { useEffect(() => {
getUserCorporate(user.id).then(setCorporateUserToShow); getUserCorporate("IXdh9EQziAVXXh0jOiC5cPVlgS82").then(setCorporateUserToShow);
}, [user]); }, [user]);
const startAssignment = (assignment: Assignment) => { const startAssignment = (assignment: Assignment) => {
@@ -70,7 +70,7 @@ export default function StudentDashboard({user}: Props) {
<> <>
{corporateUserToShow && ( {corporateUserToShow && (
<div className="absolute top-4 right-4 bg-neutral-200 px-2 rounded-lg py-1"> <div className="absolute top-4 right-4 bg-neutral-200 px-2 rounded-lg py-1">
Linked to: <b>{corporateUserToShow?.corporateInformation.companyInformation.name || corporateUserToShow.name}</b> Linked to: <b>{corporateUserToShow?.corporateInformation?.companyInformation.name || corporateUserToShow.name}</b>
</div> </div>
)} )}
<ProfileSummary <ProfileSummary

View File

@@ -244,7 +244,7 @@ export default function TeacherDashboard({user}: Props) {
<> <>
{corporateUserToShow && ( {corporateUserToShow && (
<div className="absolute top-4 right-4 bg-neutral-200 px-2 rounded-lg py-1"> <div className="absolute top-4 right-4 bg-neutral-200 px-2 rounded-lg py-1">
Linked to: <b>{corporateUserToShow?.corporateInformation.companyInformation.name || corporateUserToShow.name}</b> Linked to: <b>{corporateUserToShow?.corporateInformation?.companyInformation.name || corporateUserToShow.name}</b>
</div> </div>
)} )}
<section <section

View File

@@ -65,7 +65,7 @@ export default function BatchCodeGenerator({user}: {user: User}) {
return EMAIL_REGEX.test(email) && !users.map((u) => u.email).includes(email) return EMAIL_REGEX.test(email) && !users.map((u) => u.email).includes(email)
? { ? {
email: email.toString(), email: email.toString(),
name: `${firstName} ${lastName}`, name: `${firstName ?? ""} ${lastName ?? ""}`.trim(),
passport_id: passport_id.toString(), passport_id: passport_id.toString(),
} }
: undefined; : undefined;

View File

@@ -139,9 +139,9 @@ export default function Stats() {
} }
}, [startDate, endDate]); }, [startDate, endDate]);
const calculateTotalScore = (stats: Stat[]) => { const calculateTotalScore = (stats: Stat[], divisionFactor: number) => {
const moduleScores = calculateModuleScore(stats); const moduleScores = calculateModuleScore(stats);
return moduleScores.reduce((acc, curr) => acc + curr.score, 0) / 4; return moduleScores.reduce((acc, curr) => acc + curr.score, 0) / divisionFactor;
}; };
const calculateScorePerModule = (stats: Stat[], module: Module) => { const calculateScorePerModule = (stats: Stat[], module: Module) => {
@@ -278,7 +278,10 @@ export default function Stats() {
</span> </span>
<span className="px-2"> <span className="px-2">
Level{" "} Level{" "}
{calculateTotalScore(stats.filter((s) => timestampToMoment(s).isBefore(date))).toFixed(1)} {calculateTotalScore(
stats.filter((s) => timestampToMoment(s).isBefore(date)),
5,
).toFixed(1)}
</span> </span>
</div> </div>
) : null; ) : null;
@@ -364,6 +367,7 @@ export default function Stats() {
return date.isValid() return date.isValid()
? calculateTotalScore( ? calculateTotalScore(
stats.filter((s) => timestampToMoment(s).isBefore(date)), stats.filter((s) => timestampToMoment(s).isBefore(date)),
5,
).toFixed(1) ).toFixed(1)
: undefined; : undefined;
}) })
@@ -599,9 +603,12 @@ export default function Stats() {
}} }}
/> />
<div className="flex -md:flex-col -md:items-center gap-4 flex-wrap"> <div className="flex -md:flex-col -md:items-center gap-4 flex-wrap">
{/* Reading Score Band in Interval */} {/* Module Score Band in Interval */}
<div className="w-full md:max-w-2xl border border-mti-gray-platinum p-4 pb-12 rounded-xl h-fit md:h-96"> {MODULE_ARRAY.map((module, index) => (
<span className="text-sm font-bold">Reading Score Band in Interval</span> <div
className="w-full md:max-w-2xl border border-mti-gray-platinum p-4 pb-12 rounded-xl h-fit md:h-96"
key={module}>
<span className="text-sm font-bold">{capitalize(module)} Score Band in Interval</span>
<Chart <Chart
options={{ options={{
scales: { scales: {
@@ -617,17 +624,18 @@ export default function Stats() {
datasets: [ datasets: [
{ {
type: "line", type: "line",
label: "Reading", label: capitalize(module),
fill: false, fill: false,
borderColor: COLORS[0], borderColor: COLORS[index],
backgroundColor: COLORS[0], backgroundColor: COLORS[index],
borderWidth: 2, borderWidth: 2,
spanGaps: true, spanGaps: true,
data: intervalDates.map((date) => { data: intervalDates.map((date) => {
return calculateTotalScore( return calculateTotalScore(
stats.filter( stats.filter(
(s) => timestampToMoment(s).isBefore(date) && s.module === "reading", (s) => timestampToMoment(s).isBefore(date) && s.module === module,
), ),
1,
).toFixed(1); ).toFixed(1);
}), }),
}, },
@@ -635,152 +643,7 @@ export default function Stats() {
}} }}
/> />
</div> </div>
))}
{/* Listening Score Band in Interval */}
<div className="w-full md:max-w-2xl border border-mti-gray-platinum p-4 pb-12 rounded-xl h-fit md:h-96">
<span className="text-sm font-bold">Listening Score Band in Interval</span>
<Chart
options={{
scales: {
y: {
min: 0,
max: 9,
},
},
}}
type="line"
data={{
labels: intervalDates.map((date) => moment(date).format("DD/MM/YYYY")),
datasets: [
{
type: "line",
label: "Listening",
fill: false,
borderColor: COLORS[1],
backgroundColor: COLORS[1],
borderWidth: 2,
spanGaps: true,
data: intervalDates.map((date) => {
return calculateTotalScore(
stats.filter(
(s) => timestampToMoment(s).isBefore(date) && s.module === "listening",
),
).toFixed(1);
}),
},
],
}}
/>
</div>
{/* Writing Score Band in Interval */}
<div className="w-full md:max-w-2xl border border-mti-gray-platinum p-4 pb-12 rounded-xl h-fit md:h-96">
<span className="text-sm font-bold">Writing Score Band in Interval</span>
<Chart
options={{
scales: {
y: {
min: 0,
max: 9,
},
},
}}
type="line"
data={{
labels: intervalDates.map((date) => moment(date).format("DD/MM/YYYY")),
datasets: [
{
type: "line",
label: "Writing",
fill: false,
borderColor: COLORS[2],
backgroundColor: COLORS[2],
borderWidth: 2,
spanGaps: true,
data: intervalDates.map((date) => {
return calculateTotalScore(
stats.filter(
(s) => timestampToMoment(s).isBefore(date) && s.module === "writing",
),
).toFixed(1);
}),
},
],
}}
/>
</div>
{/* Speaking Score Band in Interval */}
<div className="w-full md:max-w-2xl border border-mti-gray-platinum p-4 pb-12 rounded-xl h-fit md:h-96">
<span className="text-sm font-bold">Speaking Score Band in Interval</span>
<Chart
options={{
scales: {
y: {
min: 0,
max: 9,
},
},
}}
type="line"
data={{
labels: intervalDates.map((date) => moment(date).format("DD/MM/YYYY")),
datasets: [
{
type: "line",
label: "Speaking",
fill: false,
borderColor: COLORS[3],
backgroundColor: COLORS[3],
borderWidth: 2,
spanGaps: true,
data: intervalDates.map((date) => {
return calculateTotalScore(
stats.filter(
(s) => timestampToMoment(s).isBefore(date) && s.module === "speaking",
),
).toFixed(1);
}),
},
],
}}
/>
</div>
{/* Level Score Band in Interval */}
<div className="w-full md:max-w-2xl border border-mti-gray-platinum p-4 pb-12 rounded-xl h-fit md:h-96">
<span className="text-sm font-bold">Level Score Band in Interval</span>
<Chart
options={{
scales: {
y: {
min: 0,
max: 9,
},
},
}}
type="line"
data={{
labels: intervalDates.map((date) => moment(date).format("DD/MM/YYYY")),
datasets: [
{
type: "line",
label: "Level",
fill: false,
borderColor: COLORS[4],
backgroundColor: COLORS[4],
borderWidth: 2,
spanGaps: true,
data: intervalDates.map((date) => {
return calculateTotalScore(
stats.filter((s) => timestampToMoment(s).isBefore(date) && s.module === "level"),
).toFixed(1);
}),
},
],
}}
/>
</div>
</div> </div>
</div> </div>
</> </>

View File

@@ -13,6 +13,6 @@ export const getUserCorporate = async (userID: string) => {
const groups = (await axios.get<Group[]>(`/api/groups?participant=${userID}`)).data; const groups = (await axios.get<Group[]>(`/api/groups?participant=${userID}`)).data;
const users = (await axios.get<User[]>("/api/users/list")).data; const users = (await axios.get<User[]>("/api/users/list")).data;
const admins = groups.map((g) => users.find((u) => u.id === g.admin)); const admins = groups.map((g) => users.find((u) => u.id === g.admin)).filter((x) => x?.type === "corporate");
return admins.map((x) => x?.type).includes("corporate") ? (admins[0] as CorporateUser) : undefined; return admins.length > 0 ? (admins[0] as CorporateUser) : undefined;
}; };

View File

@@ -1,5 +1,5 @@
import {Module} from "@/interfaces"; import {Module} from "@/interfaces";
import { LevelScore } from "@/constants/ielts"; import {LevelScore} from "@/constants/ielts";
type Type = "academic" | "general"; type Type = "academic" | "general";
@@ -96,7 +96,7 @@ const academicMarking: {[key: number]: number} = {
const levelMarking: {[key: number]: number} = { const levelMarking: {[key: number]: number} = {
88: 9, // Advanced 88: 9, // Advanced
64: 8 , // Upper-Intermediate 64: 8, // Upper-Intermediate
52: 6, // Intermediate 52: 6, // Intermediate
32: 4, // Pre-Intermediate 32: 4, // Pre-Intermediate
16: 2, // Elementary 16: 2, // Elementary
@@ -142,23 +142,24 @@ export const calculateBandScore = (correct: number, total: number, module: Modul
}; };
export const calculateAverageLevel = (levels: {[key in Module]: number}) => { export const calculateAverageLevel = (levels: {[key in Module]: number}) => {
return Object.keys(levels).reduce((accumulator, current) => levels[current as Module] + accumulator, 0) / 4; return Object.keys(levels).reduce((accumulator, current) => levels[current as Module] + accumulator, 0) / 5;
}; };
export const getLevelScore = (level: number) => { export const getLevelScore = (level: number) => {
switch(level) { switch (level) {
case 0: case 0:
return ['Beginner', 'Low A1']; return ["Beginner", "Low A1"];
case 2: case 2:
return ['Elementary', 'High A1/Low A2']; return ["Elementary", "High A1/Low A2"];
case 4: case 4:
return ['Pre-Intermediate', 'High A2/Low B1']; return ["Pre-Intermediate", "High A2/Low B1"];
case 6: case 6:
return ['Intermediate', 'High B1/Low B2']; return ["Intermediate", "High B1/Low B2"];
case 8: case 8:
return ['Upper-Intermediate', 'High B2/Low C1']; return ["Upper-Intermediate", "High B2/Low C1"];
case 9: case 9:
return ['Advanced', 'C1']; return ["Advanced", "C1"];
default: return []; default:
return [];
} }
} };