Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More refactoring, GPA #147

Merged
merged 11 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/components/OverallGpa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { calculateOverallGPA } from '@/lib/gpaUtils';
import { Tooltip } from '@chakra-ui/react';

const OverallGpa = ({ courseData, card }) => {
const { gpa, color, profCount, totalSemCount } = calculateOverallGPA(courseData);

return (
<Tooltip
label={`Averaged across ${totalSemCount} semester(s) and ${profCount} professor(s)`}
hasArrow
placement='auto'
bg='gray.900'
color='white'
openDelay={0}
fontSize='sm'
px={2}
py={1}
>
<div className={`relative justify-center flex whitespace-nowrap
${card ? 'text-sm px-2 py-1 mx-1 my-1 rounded-full' : 'px-5 rounded-md'}`}
style={{ backgroundColor: color }}>
{/* <div className='absolute inset-0 bg-gradient-to-t from-black/20 to-transparent pointer-events-none' /> */}
<span className={`my-auto font-black text-white`}>
GPA: {gpa === 0 ? "N/A" : gpa}
</span>
</div>
</Tooltip>
);
};

export default OverallGpa;
48 changes: 29 additions & 19 deletions src/components/card.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { semesters } from "../lib/utils"
import { CURRENT_SEMESTER } from '@/hooks/useSearchFilters'; // Add this import
import { semesters } from "@/lib/utils"
import { CURRENT_SEMESTER } from '@/hooks/useSearchFilters';
import OverallGpa from "./OverallGpa";

import React from 'react';
import Link from 'next/link'

Expand Down Expand Up @@ -39,17 +41,26 @@ const Card = ({ course, searchTerm }) => {

<div onClick={() => handleLink()}>
<h2 className="lg:text-lg md:text-lg font-bold text-white">{course.subjectCode} {course.courseCode}: {course.title}</h2>
<p className="lg:text-sm text-sm text-zinc-400 font-medium my-1">
{course.credits[1] > 1
? `${course.credits[1]} Credits`
: `${course.credits[1]} Credit`}
{` | `}
{uniqueInstructors[0]}
{uniqueInstructors.length > 1 && ", "}
{uniqueInstructors.length > 1 &&
uniqueInstructors[1]
}
</p>

<div className="lg:text-sm text-sm text-zinc-400 font-medium my-1">
<div className="flex flex-row">
<p className="self-center">
{course.credits[1] > 1
? `${course.credits[1]} Credits`
: `${course.credits[1]} Credit`}
{` | `}
</p>

<OverallGpa courseData={course} card />
</div>
<p>
{uniqueInstructors[0]}
{uniqueInstructors.length > 1 && ", "}
{uniqueInstructors.length > 1 &&
uniqueInstructors[1]
}
</p>
</div>

<p className="text-sm text-zinc-300 mb-4 break-words grow">
<span>{course.description.length > 300
Expand All @@ -59,16 +70,15 @@ const Card = ({ course, searchTerm }) => {
</p>

<div className="flex flex-row flex-wrap">
{course.sched.includes("Distance Learning") && <p className="text-sm px-2 py-1 mx-1 my-1 rounded-full border-solid border border-purple-500 bg-purple-300 whitespace-nowrap">
{course.sched.includes("Distance Learning") && <p className="text-sm text-white px-2 py-1 mx-1 my-1 rounded-full border-solid border bg-purple-600 border-purple-800 whitespace-nowrap">
Distance Learning
</p>}
{availableSemesters.map((sem, i) => (
(i < 2) && <span
className={`text-sm text-white px-2 py-1 mx-1 my-1 rounded-full whitespace-nowrap ${
sem === CURRENT_SEMESTER
? 'bg-yellow-600 border-2 border-yellow-700'
: 'bg-sky-800 border-2 border-sky-700'
}`}
className={`text-sm text-white px-2 py-1 mx-1 my-1 rounded-full whitespace-nowrap ${sem === CURRENT_SEMESTER
? 'bg-yellow-600 border-2 border-yellow-700'
: 'bg-sky-800 border-2 border-sky-700'
}`}
key={i}
>
{sem}
Expand Down
96 changes: 37 additions & 59 deletions src/components/fullInstructorModal.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,12 @@
import React, { useEffect, useState } from 'react';
import SearchBar from '@/components/SearchBar';
import { getColor } from '@/lib/gpaUtils';

const FullInstructorModal = ({ course }) => {

const [gpa, setGpa] = useState({});
const [searchQuery, setSearchQuery] = useState('');

// function to get color based on gpa:
const getColor = (gpa) => {
if (gpa === 0) {
return "#18181b";
}

// calculate the color based on gpa as a percentage of 4.0
const perc = gpa / 4.0;
const perc2 = perc * perc * 0.9;
const color1 = [221, 170, 51]; // higher gpa color
const color2 = [79, 0, 56]; // lower gpa color

const w1 = perc2;
const w2 = 1 - perc2;

const r = Math.round(color1[0] * w1 + color2[0] * w2 * 1);
const g = Math.round(color1[1] * w1 + color2[1] * w2 * 1);
const b = Math.round(color1[2] * w1 + color2[2] * w2 * 1);

const hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
// console.log(hex);
return hex;
};


useEffect(() => {
if (!course) return;
Expand Down Expand Up @@ -84,44 +61,45 @@ const FullInstructorModal = ({ course }) => {


return (
<div className='h-[32rem] overflow-y-auto flex flex-col'>
<h1 className='text-white text-2xl font-bold'>All Instructors Breakdown</h1>
<h3 className='text-white text-sm'>
This graphic displays all semesters and professors that have taught this course. Use the search bar below to filter for a specific professor!<br />
GPA: <span className='bg-[#632230] px-2'>1.0</span> ― <span className='bg-[#ddaa33] px-2 text-black'>4.0</span>
</h3>
<SearchBar
placeholder="Filter instructors..."
value={searchQuery}
onChange={setSearchQuery}
/>
<div className='mt-2'>
{Object.keys(gpa).map((semester, index) => {
const filteredInstructors = Object.keys(gpa[semester]).filter(instructor =>
instructor.toLowerCase().includes(searchQuery.toLowerCase())
);

if (filteredInstructors.length === 0) return null;

return (
<div key={index} className='flex flex-col mt-5'>
<h2 className='text-white font-bold text-xl border-b border-yellow-500'>{semester}</h2>
<div className='flex flex-col justify-stretch'>
{filteredInstructors.map((instructor, index) => (
<div key={index} className='flex flex-row mt-2 items-center justify-between'>
<h3 className='text-white font-semibold text-md mr-2'>{instructor}</h3>
<span className='h-0.5 border-b border-dotted flex-grow mx-2' />
<div className='grid w-20 h-10 text-center' style={{ backgroundColor: `${gpa[semester][instructor].color}` }}>
<p className='text-white m-auto font-semibold'>{gpa[semester][instructor].gpa}</p>
</div>
<div className='h-[32rem] overflow-y-auto flex flex-col'>
<h1 className='text-white text-2xl font-bold'>All Instructors Breakdown</h1>
<h3 className='text-white text-sm'>
This graphic displays all semesters and professors that have taught this course. Use the search bar below to filter for a specific professor!<br />
GPA: <span className='bg-[#632230] px-2'>1.0</span> ― <span className='bg-[#ddaa33] px-2 text-black'>4.0</span>
</h3>
<SearchBar
placeholder="Filter instructors..."
value={searchQuery}
onChange={setSearchQuery}
/>
<div className='mt-2'>
{Object.keys(gpa).map((semester, index) => {
const filteredInstructors = Object.keys(gpa[semester]).filter(instructor =>
instructor.toLowerCase().includes(searchQuery.toLowerCase())
);

if (filteredInstructors.length === 0) return null;

return (
<div key={index} className='flex flex-col mt-5'>
<h2 className='text-white font-bold text-xl border-b border-yellow-500'>{semester}</h2>
<div className='flex flex-col justify-stretch'>
{filteredInstructors.map((instructor, index) => (
<div key={index} className='flex flex-row mt-2 items-center justify-between'>
<h3 className='text-white font-semibold text-md mr-2'>{instructor}</h3>
<span className='h-0.5 border-b border-dotted flex-grow mx-2' />
<div className='relative grid w-20 h-10 text-center' style={{ backgroundColor: `${gpa[semester][instructor].color}` }}>
{/* <div className='absolute inset-0 bg-gradient-to-t from-black/10 to-transparent pointer-events-none' /> */}
<p className='text-white m-auto font-black z-10'>{gpa[semester][instructor].gpa}</p>
</div>
))}
</div>
</div>
))}
</div>
);
})}
</div>
</div>
);
})}
</div>
</div>
);
};

Expand Down
95 changes: 8 additions & 87 deletions src/components/gpaModal.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React, { useEffect, useState } from 'react';

import SearchBar from '@/components/SearchBar';

import { CURRENT_SEMESTER } from '@/hooks/useSearchFilters';
import { processGpaData } from '@/lib/gpaUtils';

const replaceZeroGpaWithDash = (gpaValue) => {
return gpaValue === 0 ? '-' : gpaValue;
return gpaValue === 0 ? '-' : gpaValue;
};

const GpaModal = ({ course }) => {
Expand Down Expand Up @@ -41,8 +40,9 @@ const GpaModal = ({ course }) => {
{Object.keys(gpa[instructor]).map((semester, index) => (
// console.log(`bg-[${gpa[instructor][semester].color}]`),
<div key={index} className='flex flex-col mt-2'>
<div className='grid h-12 text-center' style={{ backgroundColor: `${gpa[instructor][semester].color}` }}>
<p className='text-white m-auto font-semibold'>{replaceZeroGpaWithDash(gpa[instructor][semester].gpa)}</p>
<div className='grid h-12 text-center relative overflow-hidden' style={{ backgroundColor: `${gpa[instructor][semester].color}` }}>
{/* <div className='absolute inset-0 bg-gradient-to-t from-black/10 to-transparent pointer-events-none' /> */}
<p className='text-white m-auto font-black relative z-10'>{replaceZeroGpaWithDash(gpa[instructor][semester].gpa)}</p>
</div>
<h3 className='text-zinc-500 text-center text-sm px-1 hidden md:block'>{semester}</h3>
<h3 className='text-zinc-500 text-center text-[10px] px-1 block md:hidden'>{semester.split(" ")[0]}</h3>
Expand Down Expand Up @@ -104,8 +104,9 @@ export const ScheduleGpaModal = ({ course }) => {
<div className='w-full grid grid-flow-col auto-cols-fr justify-stretch gap-1'>
{Object.keys(gpa[instructor]).map((semester, index) => (
<div key={index} className='flex flex-col'>
<div className='grid py-1 text-center rounded-md' style={{ backgroundColor: `${gpa[instructor][semester].color}` }}>
<p className='text-white m-auto text-sm font-light'>{replaceZeroGpaWithDash(gpa[instructor][semester].gpa)}</p>
<div className='grid py-1 text-center rounded-md relative overflow-hidden' style={{ backgroundColor: `${gpa[instructor][semester].color}` }}>
{/* <div className='absolute inset-0 bg-gradient-to-t from-black/20 to-transparent pointer-events-none' /> */}
<p className='text-white m-auto text-sm font-bold relative z-10'>{replaceZeroGpaWithDash(gpa[instructor][semester].gpa)}</p>
</div>
</div>
))}
Expand All @@ -120,84 +121,4 @@ export const ScheduleGpaModal = ({ course }) => {
)}
</div>
);
};

// Function to get color based on GPA
export const getColor = (gpa) => {
if (gpa === 0) {
return "#18181b";
}

// Calculate the color based on GPA as a percentage of 4.0
const perc = gpa / 4.0;
const perc2 = perc * perc * 0.9;
const color1 = [221, 170, 51]; // Higher GPA color
const color2 = [79, 0, 56]; // Lower GPA color

const w1 = perc2;
const w2 = 1 - perc2;

const r = Math.round(color1[0] * w1 + color2[0] * w2 * 1);
const g = Math.round(color1[1] * w1 + color2[1] * w2 * 1);
const b = Math.round(color1[2] * w1 + color2[2] * w2 * 1);

const hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
return hex;
};

// Function to process GPA data
const processGpaData = (course, recentOnly = false) => {
if (!course || Object.keys(course.gpa).length === 0) return {};

const grades = {};
const sems = [];

// Collect all semesters across all instructors
for (const instructor in course.gpa) {
for (const semester in course.gpa[instructor]) {
if (!sems.includes(semester)) {
sems.push(semester);
}
}
}

// Sort semesters chronologically
const sorted_sems = sems.sort((a, b) => {
const a_split = a.split(" ");
const b_split = b.split(" ");
if (a_split[1] !== b_split[1]) {
return a_split[1] - b_split[1]; // Compare years
}

const seasons = ["Spring", "Summer", "Fall"];
return seasons.indexOf(a_split[0]) - seasons.indexOf(b_split[0]); // Compare seasons
});

// Process GPA data for each instructor
for (const instructor in course.gpa) {
grades[instructor] = {};

// Get recent semesters if flag is true, but keep all semesters with GPA = 0
const instructorSemesters = sorted_sems;
const recentSemesters = recentOnly
? instructorSemesters.slice(-5)
: instructorSemesters;

// Fill in GPA and color for each semester
for (const semester of instructorSemesters) {
if (!recentSemesters.includes(semester)) continue; // Skip if not in the recent subset

// Fill in GPA data, defaulting to 0 if not present
if (!course.gpa[instructor][semester]) {
grades[instructor][semester] = { gpa: 0, color: getColor(0) };
} else {
grades[instructor][semester] = {
gpa: course.gpa[instructor][semester][13],
color: getColor(course.gpa[instructor][semester][13]),
};
}
}
}

return grades;
};
Loading
Loading