Skip to content

Commit

Permalink
implement loading subjects (todo: consider just removing cookies dial…
Browse files Browse the repository at this point in the history
…og and adding privacy policy?)
  • Loading branch information
dtemkin1 committed Jan 10, 2025
1 parent 6a02de8 commit 08d1cf9
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 29 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.2",
"@solidjs/start": "^1.0.11",
"localforage": "^1.10.0",
"lucide-solid": "^0.469.0",
"solid-js": "^1.9.4",
"ua-parser-js": "^2.0.0",
Expand Down Expand Up @@ -64,5 +65,8 @@
"url": "git+/~https://github.com/sipb/courseroad3.git"
},
"license": "MIT",
"keywords": ["mit", "courseroad"]
"keywords": [
"mit",
"courseroad"
]
}
22 changes: 22 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

169 changes: 161 additions & 8 deletions src/context/component.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { makePersisted } from "@solid-primitives/storage";
import { type ParentComponent, createResource } from "solid-js";
import { createStore, produce, reconcile } from "solid-js/store";
import { isServer } from "solid-js/web";

import localforage from "localforage";

import {
CourseDataContext,
Expand All @@ -14,6 +17,7 @@ const CourseDataProvider: ParentComponent = (props) => {
createStore(structuredClone(defaultState)),
{
name: "courseRoadStore",
storage: !isServer ? localforage : undefined,
},
);

Expand Down Expand Up @@ -179,8 +183,130 @@ const CourseDataProvider: ParentComponent = (props) => {
}),
);
},
parseGenericCourses: () => {},
parseGenericIndex: () => {},
parseGenericCourses: () => {
setStore(
"genericCourses",
produce((genericCourses) => {
// clears array
genericCourses.length = 0;

const girAttributes = {
PHY1: ["Physics 1 GIR", "p1"],
PHY2: ["Physics 2 GIR", "p2"],
CHEM: ["Chemistry GIR", "c"],
BIOL: ["Biology GIR", "b"],
CAL1: ["Calculus I GIR", "m1"],
CAL2: ["Calculus II GIR", "m2"],
LAB: ["Lab GIR", "l1"],
REST: ["REST GIR", "r"],
} as const;

const hassAttributes = {
"HASS-A": ["HASS Arts", "ha"],
"HASS-S": ["HASS Social Sciences", "hs"],
"HASS-H": ["HASS Humanities", "hh"],
"HASS-E": ["HASS Elective", "ht"],
} as const;

const ciAttributes = {
"CI-H": ["Communication Intensive", "hc"],
"CI-HW": ["Communication Intensive with Writing", "hw"],
} as const;

const baseGeneric = {
description:
"Use this generic subject to indicate that you are fulfilling a requirement, but do not yet have a specific subject selected.",
total_units: 12,
} as const;

const baseurl =
"http://student.mit.edu/catalog/search.cgi?search=&style=verbatim&when=*&termleng=4&days_offered=*&start_time=*&duration=*&total_units=*" as const;

for (const gir in girAttributes) {
const offeredGir = actions.getMatchingAttributes(
gir,
undefined,
undefined,
);

genericCourses.push({
...baseGeneric,
...offeredGir,

gir_attribute: gir as keyof typeof girAttributes,
title: `Generic ${girAttributes[gir as keyof typeof girAttributes][0]}`,
subject_id: gir,
url: `${baseurl}&cred=${girAttributes[gir as keyof typeof girAttributes][1]}&commun_int=*`,
});
}

for (const hass in hassAttributes) {
const offeredHass = actions.getMatchingAttributes(
undefined,
hass,
undefined,
);

genericCourses.push({
...baseGeneric,
...offeredHass,
hass_attribute: hass as keyof typeof hassAttributes,
title: `Generic ${hass}`,
subject_id: hass,
url: `${baseurl}&cred=${hassAttributes[hass as keyof typeof hassAttributes][1]}&commun_int=*`,
});

const offeredHassCI = actions.getMatchingAttributes(
undefined,
hass,
"CI-H",
);

genericCourses.push({
...baseGeneric,
...offeredHassCI,
hass_attribute: hass as keyof typeof hassAttributes,
communication_requirement: "CI-H",
title: `Generic CI-H ${hass}`,
subject_id: `CI-H ${hass}`,
url: `${baseurl}&cred=${hassAttributes[hass as keyof typeof hassAttributes][1]}&commun_int=${ciAttributes["CI-H"][1]}`,
});
}

for (const ci in ciAttributes) {
const offeredCI = actions.getMatchingAttributes(
undefined,
undefined,
ci,
);

genericCourses.push({
...baseGeneric,
...offeredCI,
communication_requirement: ci as keyof typeof ciAttributes,
title: `Generic ${ci}`,
hass_attribute: "HASS",
subject_id: ci as keyof typeof ciAttributes,
url: `${baseurl}&cred=*&commun_int=${ciAttributes[ci as keyof typeof ciAttributes][1]}`,
});
}
}),
);
},
parseGenericIndex: () => {
setStore(
"genericIndex",
reconcile(
store.genericCourses.reduce(
(obj, item, index) => {
obj[item.subject_id] = index;
return obj;
},
{} as Record<string, number>,
),
),
);
},
parseSubjectsIndex: () => {},
popClassStack: () => {},
pushClassStack: (id) => {},
Expand Down Expand Up @@ -209,7 +335,9 @@ const CourseDataProvider: ParentComponent = (props) => {
setActiveRoad: (activeRoad) => {
setStore("activeRoad", activeRoad);
},
setFullSubjectsInfoLoaded: (isFull) => {},
setFullSubjectsInfoLoaded: (isFull) => {
setStore("fullSubjectsInfoLoaded", isFull);
},
setLoggedIn: (newLoggedIn) => {
setStore("loggedIn", newLoggedIn);
},
Expand Down Expand Up @@ -243,7 +371,9 @@ const CourseDataProvider: ParentComponent = (props) => {
}),
);
},
setSubjectsInfo: (data) => {},
setSubjectsInfo: (data) => {
setStore("subjectsInfo", reconcile(data));
},
setCurrentSemester: (sem) => {
setStore("currentSemester", Math.max(1, sem));
},
Expand All @@ -255,11 +385,34 @@ const CourseDataProvider: ParentComponent = (props) => {
resetFulfillmentNeeded: () => {
setStore("fulfillmentNeeded", "all");
},
setLoadSubjectsPromise: (promise) => {},
setSubjectsLoaded: () => {},
setLoadSubjectsPromise: (promise) => {
setStore("loadSubjectsPromise", promise);
},
setSubjectsLoaded: () => {
setStore("subjectsLoaded", true);
},
queueRoadMigration: (roadID) => {},
clearMigrationQueue: () => {},
loadSubjects: async () => {},
clearMigrationQueue: () => {
setStore("roadsToMigrate", reconcile([]));
},
loadAllSubjects: async () => {
const promise = fetch(
`${import.meta.env.VITE_FIREROAD_URL}/courses/all?full=true`,
).then((response) => response.json() as Promise<SubjectFull[]>);

actions.setLoadSubjectsPromise(promise);
const response = await promise;
actions.setSubjectsLoaded();
actions.setSubjectsInfo(response);
actions.setFullSubjectsInfoLoaded(true);
actions.parseGenericCourses();
actions.parseGenericIndex();
actions.parseSubjectsIndex();
for (const roadID of store.roadsToMigrate) {
actions.migrateOldSubjects(roadID);
}
actions.clearMigrationQueue();
},
addAtPlaceholder: (index) => {},
waitLoadSubjects: async () => {},
waitAndMigrateOldSubjects: (roadID) => {},
Expand Down
2 changes: 1 addition & 1 deletion src/context/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const defaultActions = {
setSubjectsLoaded: () => {},
queueRoadMigration: (roadID: string) => {},
clearMigrationQueue: () => {},
loadSubjects: async () => {},
loadAllSubjects: async () => {},
addAtPlaceholder: (index: number) => {},
waitLoadSubjects: async () => {},
waitAndMigrateOldSubjects: (roadID: string) => {},
Expand Down
26 changes: 13 additions & 13 deletions src/context/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export interface Subject {
offered_IAP: boolean;
offered_spring: boolean;
offered_summer: boolean;
public: boolean;
public?: boolean;
semester?: number; // specifically for when in a road...
units?: number; // is manually set in some places
index?: number; // is also manually set idk why
Expand All @@ -21,32 +21,32 @@ export interface Subject {
not_offered_year?: string;
instructors?: string[];
communication_requirement?: "CI-H" | "CI-HW";
hass_attribute?: "HASS-A" | "HASS-E" | "HASS-H" | "HASS-S";
hass_attribute?: "HASS-A" | "HASS-E" | "HASS-H" | "HASS-S" | "HASS";
gir_attribute?:
| "BIOL"
| "CAL1"
| "CAL2"
| "CHEM"
| "LAB"
| "LAB2"
| "GIR:PHY1"
| "GIR:PHY2"
| "GIR:REST";
| "PHY1"
| "PHY2"
| "REST";
children?: Subject["subject_id"][];
parent?: Subject["subject_id"];
prereqs?: string;
virtual_status?: "In-Person" | "Virtual";
old_id: string;
old_id?: string;
}

export interface SubjectFull extends Subject {
lecture_units: number;
lab_units: number;
design_units: number;
preparation_units: number;
is_variable_units: boolean;
is_half_class: boolean;
has_final: boolean;
lecture_units?: number;
lab_units?: number;
design_units?: number;
preparation_units?: number;
is_variable_units?: boolean;
is_half_class?: boolean;
has_final?: boolean;
description?: string;
prerequisites?: string;
corequisites?: string;
Expand Down
Loading

0 comments on commit 08d1cf9

Please sign in to comment.