Skip to content

Commit

Permalink
Merge pull request #26 from UTDNebula/feat/v1
Browse files Browse the repository at this point in the history
Feat/v1
  • Loading branch information
heartgg authored Mar 22, 2023
2 parents 2cdf3c8 + 8e9344d commit b8f8ecc
Show file tree
Hide file tree
Showing 30 changed files with 823 additions and 410 deletions.
310 changes: 310 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "sk.edge",
"displayName": "sk.edge",
"version": "0.0.1",
"description": "the all-in-one registration tool by students, for students",
"description": "your registration assistant by students, for students",
"author": "Nebula Labs",
"packageManager": "[email protected]",
"scripts": {
Expand All @@ -12,13 +12,15 @@
},
"dependencies": {
"@plasmohq/messaging": "^0.1.6",
"@plasmohq/storage": "^1.3.1",
"apexcharts": "^3.37.1",
"next": "^13.1.5",
"plasmo": "^0.67.3",
"react": "18.2.0",
"react-apexcharts": "^1.4.0",
"react-dom": "18.2.0",
"react-icons": "^4.7.1",
"react-loader-spinner": "^5.3.4",
"react-router-dom": "^6.8.2"
},
"devDependencies": {
Expand Down
73 changes: 73 additions & 0 deletions src/background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { scrapeCourseData, CourseHeader } from "~content";
import { Storage } from "@plasmohq/storage";

export interface ShowCourseTabPayload {
header: CourseHeader;
professors: string[];
}

// State vars
let courseTabId: number = null;
let scrapedCourseData: ShowCourseTabPayload = null;

// for persistent state
const storage = new Storage();

/** Injects the content script if we hit a course page */
chrome.webNavigation.onHistoryStateUpdated.addListener(details => {
if (/^.*:\/\/utdallas\.collegescheduler\.com\/terms\/.*\/courses\/.+$/.test(
details.url
))
{
chrome.scripting.executeScript({
target: {
tabId: details.tabId,
},
world: "MAIN",
// content script injection only works reliably on the prod packaged extension
// b/c of the plasmo dev server connections
func: scrapeCourseData,
}, async function (resolve) {
if (resolve && resolve[0] && resolve[0].result) {
const result: ShowCourseTabPayload = resolve[0].result;
scrapedCourseData = result;
await storage.set("scrapedCourseData", scrapedCourseData)
};
});
chrome.action.setBadgeText({text: "!"});
chrome.action.setBadgeBackgroundColor({color: 'green'});
courseTabId = details.tabId
storage.set("courseTabId", courseTabId)
storage.set("courseTabUrl", details.url)
} else {
chrome.action.setBadgeText({text: ""});
}
});

/** Sets the icon to be active if we're on a course tab */
chrome.tabs.onActivated.addListener(async details => {
const cachedTabUrl: string = await storage.get("courseTabUrl")
const currentTabUrl: string = (await getCurrentTab()).url
if (cachedTabUrl === currentTabUrl) {
chrome.action.setBadgeText({text: "!"});
chrome.action.setBadgeBackgroundColor({color: 'green'});
} else {
chrome.action.setBadgeText({text: ""});
}
});

export async function getScrapedCourseData() {
const cachedTabUrl: string = await storage.get("courseTabUrl")
const currentTabUrl: string = (await getCurrentTab()).url
if (cachedTabUrl === currentTabUrl) {
return await storage.get("scrapedCourseData");
}
return null
}

async function getCurrentTab() {
let queryOptions = { active: true, lastFocusedWindow: true };
// `tab` will either be a `tabs.Tab` instance or `undefined`.
let [tab] = await chrome.tabs.query(queryOptions);
return tab;
}
61 changes: 0 additions & 61 deletions src/background/index.ts

This file was deleted.

9 changes: 3 additions & 6 deletions src/background/messages/getScrapeData.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import type { PlasmoMessaging } from "@plasmohq/messaging"
import {getScrapedCourseData} from "../index";
import { getScrapedCourseData } from "../../background";

const handler: PlasmoMessaging.MessageHandler = async (req, res) => {
const data = getScrapedCourseData();

res.send({
data
})
const data = await getScrapedCourseData();
res.send(data)
}

export default handler
9 changes: 0 additions & 9 deletions src/backgroundInterfaces.ts

This file was deleted.

17 changes: 17 additions & 0 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import nebulaLogo from "data-base64:../../assets/nebula-logo.svg"

export const Footer = () => {

const navigateToNebula = (): void => {
window.open("https://www.utdnebula.com/", "_blank")
}

return (
<div className="rounded-b-2xl p-2 bg-gray-light -mb-4 -ml-4 -mr-4">
<div className="flex items-center justify-center">
<h4 className="pr-2">Powered by Nebula Labs</h4>
<img onClick={navigateToNebula} src={nebulaLogo} alt="Nebula Labs Logo" className="w-[25px] h-[25px] hover:cursor-pointer"></img>
</div>
</div>
)
}
6 changes: 3 additions & 3 deletions src/components/HorizontalScores.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export const HorizontalScores = ({ rmpScore, diffScore, wtaPercent } : Scores) =
<h2 className="bg-blue-dark text-white text-center py-1 rounded-tl-2xl">RMP</h2>
<h2 className="bg-blue-dark text-white text-center py-1">DIFF</h2>
<h2 className="bg-blue-dark text-white text-center py-1 rounded-tr-2xl">WTA</h2>
<h1 style={{backgroundColor: getScoreColor(rmpScore, 5, false)}} className="text-blue-dark text-center py-0.5 rounded-bl-2xl">{rmpScore}</h1>
<h1 style={{backgroundColor: getScoreColor(diffScore, 5, true)}} className="text-blue-dark text-center py-0.5">{diffScore}</h1>
<h1 style={{backgroundColor: getScoreColor(wtaPercent, 100, false)}} className="text-blue-dark text-center py-0.5 rounded-br-2xl">{wtaPercent}%</h1>
<h1 style={{backgroundColor: getScoreColor(rmpScore, 5, false)}} className="text-blue-dark text-center py-0.5 rounded-bl-2xl">{rmpScore ? rmpScore.toFixed(1) : "NA"}</h1>
<h1 style={{backgroundColor: getScoreColor(diffScore, 5, true)}} className="text-blue-dark text-center py-0.5">{diffScore ? diffScore.toFixed(1) : "NA"}</h1>
<h1 style={{backgroundColor: getScoreColor(wtaPercent, 100, false)}} className="text-blue-dark text-center py-0.5 rounded-br-2xl">{wtaPercent ? Math.round(wtaPercent) : "NA"}%</h1>
</div>
)
}
33 changes: 33 additions & 0 deletions src/components/Landing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Card } from "./Card"
import { Footer } from "./Footer"
import skedgeLogo from "data-base64:../../assets/icon.png"

const SURVEY_URL = "https://docs.google.com/forms/d/e/1FAIpQLScGIXzlYgsx1SxHYTTCwRaMNVYNRe6I67RingPRVzcT1tLwSg/viewform?usp=sf_link"
const GALAXY_URL = "https://www.utdallas.edu/galaxy/"

export const Landing = () => {

const navigativeToScheduler = (): void => {
window.open(GALAXY_URL, "_blank")
}

const navigateToSurvey = (): void => {
window.open(SURVEY_URL, "_blank")
}

return(
<Card>
<div className="h-auto">
<h1>Welcome to sk.edge 👋</h1>
<h6 className="my-2">your registration assistant by students, for students</h6>
<img src={skedgeLogo} alt="" className="w-[100px] h-[100px] float-right" />
<p className="mb-2">Log into <b>Schedule Planner</b> and click <b>Options</b> on a course to get started!</p>
<p className="mb-2">Got feedback? Let us know <button className="text-purple-dark" onClick={navigateToSurvey}>here</button>!</p>
<button onClick={navigativeToScheduler} className="text-center flex py-2 px-4 mb-4 bg-blue-dark hover:bg-blue-dark-hover rounded-lg transition duration-250 ease-in-out">
<h3 className="text-center text-white">To Galaxy!</h3>
</button>
<Footer />
</div>
</Card>
)
}
18 changes: 18 additions & 0 deletions src/components/Loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Rings } from "react-loader-spinner"

export const Loading = () => {
return (
<div className="h-64 flex justify-center items-center">
<Rings
height="80"
width="80"
color="#1C2A6D"
radius="6"
wrapperStyle={{}}
wrapperClass="block mx-auto w-[80px] h-[80px]"
visible={true}
ariaLabel="rings-loading"
/>
</div>
)
}
6 changes: 4 additions & 2 deletions src/components/MiniGrades.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useState } from "react";
import Chart from "react-apexcharts"
import { miniGradeChartOptions } from "~utils/styling";
import type { GradeDistribution } from "./ProfileGrades"

export const MiniGrades = ({ gradeDistributionData } : { gradeDistributionData: GradeDistribution }) => {
miniGradeChartOptions.title.text = gradeDistributionData.name;
const config = JSON.parse(JSON.stringify(miniGradeChartOptions))
config.title.text = gradeDistributionData.name;
return (
<>
<Chart options={miniGradeChartOptions} series={gradeDistributionData.series} type="bar" height={124}></Chart>
<Chart options={config} series={gradeDistributionData.series} type="bar" height={124}></Chart>
</>
)
}
6 changes: 3 additions & 3 deletions src/components/MiniProfessor.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { FaUser } from "react-icons/fa"
import { NavigateFunction, useNavigate } from "react-router-dom"
import type { ProfessorProfileInterface } from "~routes/about"
import type { ProfessorProfileInterface } from "~data/builder"
import { Card } from "./Card"
import { MiniGrades } from "./MiniGrades"
import { MiniScore } from "./MiniScore"

export const MiniProfessor = ({ professorData } : { professorData: ProfessorProfileInterface }) => {
export const MiniProfessor = ({ professorData, profiles } : { professorData: ProfessorProfileInterface, profiles: ProfessorProfileInterface[] }) => {
const navigation: NavigateFunction = useNavigate()

const toProfessorProfile = (): void => {
navigation("/about", { state: professorData })
navigation("/professor", { state: { professorData, profiles } })
}

return(
Expand Down
3 changes: 2 additions & 1 deletion src/components/MiniScore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const MiniScore = ({ name, score, maxScore, inverted } : MiniScoreProps)
return(
<div className="grid grid-cols-12">
<h3 className="bg-blue-dark rounded-l-xl text-white text-center py-1.5 col-span-5">{name}</h3>
<h1 style={{backgroundColor: getScoreColor(score, maxScore, inverted)}} className="text-blue-dark text-center py-0.5 rounded-r-xl col-span-7">{name == "WTA" ? score : score.toFixed(1)}</h1>
{score !== undefined && <h1 style={{backgroundColor: getScoreColor(score, maxScore, inverted)}} className="text-blue-dark text-center py-0.5 rounded-r-xl col-span-7">{name === "WTA" ? Math.round(score) : score.toFixed(1)}</h1>}
{score === undefined && <h1 style={{backgroundColor: "white"}} className="text-blue-dark text-center py-0.5 rounded-r-xl col-span-7">NA</h1>}
</div>
)}
8 changes: 4 additions & 4 deletions src/components/ProfileGrades.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ export const ProfileGrades = ({ gradeDistributionData } : { gradeDistributionDat

return (
<>
<header className="bg-blue-dark rounded-t-2xl flex">
<button onClick={prevPage} className="flex-auto text-center hover:bg-blue-dark-hover rounded-tl-2xl transition duration-250 ease-in-out flex items-center justify-center"><AiFillCaretLeft size={20} color="white" /></button>
<h2 className="flex-auto text-center text-white mx-auto py-2">{gradeDistributionData[page].name}</h2>
<button onClick={nextPage} className="flex-auto text-center hover:bg-blue-dark-hover rounded-tr-2xl transition duration-250 ease-in-out flex items-center justify-center"><AiFillCaretRight size={20} color="white" /></button>
<header className="bg-blue-dark rounded-t-2xl grid grid-cols-12">
<button onClick={prevPage} className="col-span-2 text-center hover:bg-blue-dark-hover rounded-tl-2xl transition duration-250 ease-in-out flex items-center justify-center"><AiFillCaretLeft size={20} color="white" /></button>
<h2 className="col-span-8 text-center text-white mx-auto py-2">{gradeDistributionData[page].name}</h2>
<button onClick={nextPage} className="col-span-2 text-center hover:bg-blue-dark-hover rounded-tr-2xl transition duration-250 ease-in-out flex items-center justify-center"><AiFillCaretRight size={20} color="white" /></button>
</header>
<div className="border-blue-dark border-r-2 border-l-2 border-b-2 rounded-b-2xl">
<Chart options={gradeChartOptions} series={gradeDistributionData[page].series} type="bar" height={150}></Chart>
Expand Down
15 changes: 10 additions & 5 deletions src/components/ProfileHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { TiArrowBack } from "react-icons/ti"
import { FaExternalLinkAlt } from "react-icons/fa"
import { NavigateFunction, useNavigate } from "react-router-dom"
import type { ProfessorProfileInterface } from "~data/builder";

export const ProfileHeader = ({ name, profilePicUrl } : { name: string, profilePicUrl: string }) => {
export const ProfileHeader = ({ name, profilePicUrl, rmpId, profiles } : { name: string, profilePicUrl: string, rmpId: number, profiles: ProfessorProfileInterface[] }) => {
const navigation: NavigateFunction = useNavigate();

const returnToSections = (): void => {
navigation(-1)
navigation("/", { state: profiles })
}

const navigativeToRmp = (): void => {
window.open('https://www.ratemyprofessors.com/professor/' + rmpId, '_blank')
}

return (
Expand All @@ -15,13 +20,13 @@ export const ProfileHeader = ({ name, profilePicUrl } : { name: string, profileP
<button onClick={returnToSections} className="justify-center items-center flex">
<TiArrowBack size={40} color="white" className="p-2 hover:bg-blue-dark-hover rounded-lg transition duration-250 ease-in-out" />
</button>
<h2 className="col-span-3 text-center text-white mx-auto my-auto">{name}</h2>
<button className="justify-center items-center flex">
<h2 className="col-span-3 text-center text-white mx-auto my-auto">{name.split(' ').at(0) + " " + name.split(' ').at(-1)}</h2>
<button className="justify-center items-center flex" onClick={navigativeToRmp}>
<FaExternalLinkAlt size={40} color="white" className="p-3 hover:bg-blue-dark-hover rounded-lg transition duration-250 ease-in-out" />
</button>
</div>
<div className="absolute top-[66px] left-1/2 -translate-x-1/2 rounded-full h-32 w-32 bg-gray-light">
<img className="object-cover rounded-full h-32 border-8 border-gray-light" src={profilePicUrl} alt="" />
<img className="object-cover rounded-full h-32 border-8 border-gray-light" src={profilePicUrl ? profilePicUrl : "https://profiles.utdallas.edu/img/default.png"} alt="" />
</div>
</header>
)
Expand Down
Loading

0 comments on commit b8f8ecc

Please sign in to comment.