Skip to content

Commit 48b8423

Browse files
Abdullah ShahidAbdullah Shahid
authored andcommitted
[DEV] Update
1 parent d6886fe commit 48b8423

File tree

6 files changed

+134
-8
lines changed

6 files changed

+134
-8
lines changed

semtrack/src/components/course/Stats.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Stats: React.FC<StatsProps> = ({ grades }) => {
99
return (
1010
<div>
1111
<div className="stats shadow">
12-
<div className="stat">
12+
<div className="stat pb-5">
1313
<div className="stat-figure text-primary"></div>
1414
<div className="stat-title text-sm font-semibold">Grade</div>
1515
<div className="stat-value">{calculateAverageGrade(grades)} / 100</div>
@@ -19,14 +19,12 @@ const Stats: React.FC<StatsProps> = ({ grades }) => {
1919
<div className="stat-figure text-secondary"><br /></div>
2020
<div className="stat-title text-sm font-semibold">Min Grade</div>
2121
<div className="stat-value">{calculateMinGrade(grades)} / 100</div>
22-
<div className="stat-desc"><br /></div>
2322
</div>
2423

2524
<div className="stat">
2625
<div className="stat-figure text-secondary"></div>
2726
<div className="stat-title text-sm font-semibold">Max Grade</div>
2827
<div className="stat-value">{calculateMaxGrade(grades)} / 100</div>
29-
<div className="stat-desc"></div>
3028
</div>
3129
</div>
3230
</div>

semtrack/src/components/dashboard/SemesterStats.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1-
import { Course } from "../../store/slices/coursesSlice";
1+
import { useSelector } from "react-redux";
2+
import { RootState } from "../../store";
3+
import { calculateGPAFromCourses } from "../../utils/gpa";
24

35

46
const SemesterStats: React.FC = () => {
7+
const {gpa, gradePercentage} = useSelector((state: RootState) =>
8+
{
9+
return calculateGPAFromCourses(state.courses.courses, state.grades, state.gpa)
10+
});
11+
512
return (
613
<div>
714
<div className="stats shadow">
8-
<div className="stat">
15+
<div className="stat pb-5">
916
<div className="stat-figure text-primary"></div>
1017
<div className="stat-title text-sm font-semibold">Semester GPA</div>
11-
<div className="stat-value">{0} / 4.0</div>
18+
<div className="stat-value">{gpa} / 4.0</div>
19+
</div>
20+
<div className="stat">
21+
<div className="stat-figure text-primary"></div>
22+
<div className="stat-title text-sm font-semibold">Average Grade (%)</div>
23+
<div className="stat-value">{gradePercentage} / 100</div>
1224
</div>
1325
</div>
1426
</div>

semtrack/src/pages/Dashboard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ function Dashboard() {
1313
TBD - show reminders to enter grades for upcoming assignments, tests, and
1414
exams.
1515
<div className="mt-4"></div> */}
16-
{/* <SemesterStats /> */}
17-
{/* <div className="mt-8"></div> */}
16+
<SemesterStats />
17+
<div className="mt-8"></div>
1818
<Courses />
1919
</>
2020
);

semtrack/src/store/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ import {
88
setEdit,
99
removeGrade
1010
} from "./slices/gradesSlice";
11+
import { GPAState, gpaReducer } from "./slices/gpaSlice";
1112

1213
export interface RootState {
1314
courses: CourseState;
1415
grades: GradeState;
16+
gpa: GPAState;
1517
}
1618

1719
const store = configureStore({
1820
reducer: {
1921
courses: courseReducer,
2022
grades: gradesReducer,
23+
gpa: gpaReducer,
2124
},
2225
});
2326

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { createSlice } from "@reduxjs/toolkit";
2+
3+
export interface GradeRange {
4+
min: number;
5+
max: number;
6+
gpa: number;
7+
}
8+
9+
export interface GPATemplate {
10+
scale: GradeRange[];
11+
}
12+
13+
export type GPATemplatesByName = {
14+
[name: string]: GPATemplate;
15+
};
16+
17+
18+
export type GPAState = {
19+
activeTemplate: string,
20+
templates: GPATemplatesByName,
21+
isOn: boolean
22+
};
23+
24+
const initialState: GPAState = {
25+
activeTemplate: "uoft",
26+
templates: {
27+
"uoft": {
28+
scale: [
29+
{min: 90, max: 100, gpa: 4.0},
30+
{min: 85, max: 89, gpa: 4.0},
31+
{min: 80, max: 84, gpa: 3.7},
32+
{min: 77, max: 79, gpa: 3.3},
33+
{min: 73, max: 76, gpa: 3.0},
34+
{min: 70, max: 72, gpa: 2.7},
35+
{min: 67, max: 69, gpa: 2.3},
36+
{min: 63, max: 66, gpa: 2.0},
37+
{min: 60, max: 62, gpa: 1.7},
38+
{min: 57, max: 59, gpa: 1.3},
39+
{min: 53, max: 56, gpa: 1.0},
40+
{min: 50, max: 52, gpa: 0.7},
41+
{min: 0, max: 49, gpa: 0.0},
42+
{min: 0, max: 49, gpa: 0.0},
43+
]
44+
}
45+
},
46+
isOn: true
47+
};
48+
49+
const gpaSlice = createSlice({
50+
name: "gpa",
51+
initialState,
52+
reducers: {},
53+
});
54+
55+
export const gpaReducer = gpaSlice.reducer;

semtrack/src/utils/gpa.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Course } from "../store/slices/coursesSlice"
2+
import { GPAState } from "../store/slices/gpaSlice";
3+
import { Grade, GradeState } from "../store/slices/gradesSlice";
4+
import { calculateAverageGrade } from "./grades";
5+
// todo: refactor this entire file
6+
/**
7+
* Calculates the combined GPA of all the given courses
8+
*
9+
* @param {Course[]} courses An array of Course objects
10+
*
11+
* @returns {number} the combined GPA of the given courses
12+
*/
13+
export const calculateGPAFromCourses = (courses: Course[], gradeState: GradeState, GPAState: GPAState) => {
14+
15+
let gpa = 0;
16+
let weight = 0;
17+
18+
let gradePercentage = 0;
19+
20+
for (let course of courses) {
21+
22+
const grades: Grade[] = gradeState.data[course.id];
23+
24+
let grade = calculateAverageGrade(grades);
25+
26+
gradePercentage += grade;
27+
28+
let courseGPA = calculateGPAFromGrade(grade, GPAState);
29+
30+
// when weight is 2, add the gpa twice.
31+
gpa += courseGPA;
32+
weight += 1;
33+
}
34+
35+
gpa = gpa / weight;
36+
gradePercentage /= weight;
37+
38+
return {gpa, gradePercentage };
39+
}
40+
41+
// given grade, convert to gpa
42+
export const calculateGPAFromGrade = (grade: number, GPAState: GPAState): number => {
43+
44+
if (!GPAState.isOn) {
45+
return 0;
46+
}
47+
48+
const activeScale = GPAState.templates[GPAState.activeTemplate].scale;
49+
50+
for (let gradeRange of activeScale) {
51+
if (grade >= gradeRange.min && grade <= gradeRange.max) {
52+
return gradeRange.gpa;
53+
}
54+
}
55+
56+
throw new Error(`No GPA found for grade ${grade}`);
57+
}
58+

0 commit comments

Comments
 (0)