Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
da166c7
applied filters into the search function using flags in the model, wi…
boldizsarbenedek Apr 16, 2025
190a822
wrote departments filter option
boldizsarbenedek Apr 16, 2025
c61814b
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
a865fa4
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
7ca07a1
added check to make sure to not recommend courses the client has take…
boldizsarbenedek Apr 16, 2025
df2872b
initial state good
kexana Apr 16, 2025
000d882
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
41c4cfe
commit?
boldizsarbenedek Apr 16, 2025
d8f1543
departments go to model
kexana Apr 16, 2025
b162882
trying to add filtering out courses with NULL fields as an implementa…
boldizsarbenedek Apr 16, 2025
1ca3881
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
170e1b4
merging into brain?
boldizsarbenedek Apr 16, 2025
c33ceb3
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
9d9bf3e
merging/
boldizsarbenedek Apr 16, 2025
855f4ab
some ?. properties check, because skill issue
boldizsarbenedek Apr 16, 2025
fce40c0
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
fb0554b
more course?. things
boldizsarbenedek Apr 16, 2025
05f9fd2
finished the noNull feature, essentially fixed typos
boldizsarbenedek Apr 16, 2025
f1ac1bf
null course checkbox
kexana Apr 16, 2025
917184e
null check linked
kexana Apr 16, 2025
b41e5a8
Null field toggle works
kexana Apr 16, 2025
2d2a84a
rebase to main
kexana May 7, 2025
db72583
nice and beutiful
kexana May 7, 2025
a97fa17
rebase with main
kexana May 7, 2025
17cb87c
removed the explicit null string checks, hopefully doesnt break, also…
boldizsarbenedek May 7, 2025
4dc5311
period filter
kexana May 7, 2025
95b9000
a bit polishing, touching on the period presenter since i thought its…
boldizsarbenedek May 7, 2025
401ce83
fixed some filters logic (level filter, period filter), added descrip…
boldizsarbenedek May 8, 2025
20c98a5
visually persistent filters
kexana May 8, 2025
a0925dd
check period filter
kexana May 8, 2025
882f7a1
good filters merge
kexana May 8, 2025
3518e20
now fixed
kexana May 8, 2025
1ae1a5b
once again
kexana May 8, 2025
bf5401c
pulling main and merging
boldizsarbenedek May 8, 2025
36abf33
unlocking departments and locations
boldizsarbenedek May 8, 2025
1f83e38
wip
kexana May 8, 2025
40e26eb
filters enabled by clicking on them
kexana May 8, 2025
0c5047f
My side merge with Dean's side
boldizsarbenedek May 8, 2025
c81034b
departments half functional
kexana May 9, 2025
73a2f38
rebase to main
kexana May 9, 2025
7fefd1f
rebase to main
kexana May 9, 2025
16497c4
rebase to main
kexana May 9, 2025
1d77e0f
Merge branch 'main' of https://github.com/jkluge/Find-My-Next-Course …
kexana May 9, 2025
1b0e488
Refactoring transcript scraper (#126)
boldizsarbenedek May 9, 2025
7a48c87
Merge branch 'responsive-filtering' of https://github.com/jkluge/Find…
kexana May 9, 2025
6b30175
fixed couple errors relating to the new LocaleStorage finished course…
boldizsarbenedek May 9, 2025
a182c12
fixed a lot of typos (deparmen != department)
boldizsarbenedek May 9, 2025
466adef
trying to add hover over tooltips such that it displayes name of course
boldizsarbenedek May 9, 2025
e4b8f52
inbetween
kexana May 9, 2025
a5036e1
Merge branch 'responsive-filtering' of https://github.com/jkluge/Find…
kexana May 9, 2025
dc2463a
removing the console.logs because theyre dumb and we should remove th…
boldizsarbenedek May 13, 2025
6e7775f
department percistency done only SU and Education Office broken
kexana May 13, 2025
0d5d816
even more documentation, added descriptions and cleared up toolTips o…
boldizsarbenedek May 13, 2025
5131b25
Merge branch 'responsive-filtering' of github.com:InferenceKTH/Find-M…
boldizsarbenedek May 13, 2025
144b302
departments should be working
kexana May 14, 2025
9b4bf95
nothing really
boldizsarbenedek May 14, 2025
dbc3deb
work on upload bahaviour
kexana May 14, 2025
4436fdf
Merge branch 'responsive-filtering' of https://github.com/jkluge/Find…
kexana May 14, 2025
d077a32
merge-rebase w main
boldizsarbenedek May 14, 2025
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
6 changes: 0 additions & 6 deletions my-app/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export function connectToFirebase(model) {
const options = JSON.parse(localStorage.getItem("filterOptions"));
if (options) {
model.setFilterOptions(options);
console.log("Restore options from local storage");
}

reaction(
Expand Down Expand Up @@ -203,7 +202,6 @@ export async function uploadDepartmentsAndLocations(departments, locations) {
const departmentsRef = ref(db, "departments");
try {
await set(departmentsRef, departments);
console.log("Uploaded Departments");
} catch (error) {
console.error("Failed to upload departments:", error);
return false;
Expand All @@ -213,7 +211,6 @@ export async function uploadDepartmentsAndLocations(departments, locations) {
const locationsRef = ref(db, "locations");
try {
await set(locationsRef, locations);
console.log("Uploaded Locations");
} catch (error) {
console.error("Failed to upload locations:", error);
return false;
Expand Down Expand Up @@ -275,7 +272,6 @@ async function loadCoursesFromCacheOrFirebase(model) {
});

if (cachedTimestamp === firebaseTimestamp) {
console.log("Using cached courses from IndexedDB...");
const courseTx = db.transaction("courses", "readonly");
const courseStore = courseTx.objectStore("courses");
const getAllReq = courseStore.getAll();
Expand All @@ -291,7 +287,6 @@ async function loadCoursesFromCacheOrFirebase(model) {
}

// fallback: fetch from Firebase
console.log("Fetching courses from Firebase...");
const courses = await fetchAllCourses();
model.setCourses(courses);
saveCoursesToCache(courses, firebaseTimestamp);
Expand All @@ -304,7 +299,6 @@ export async function addReviewForCourse(courseCode, review) {
const updateCourseAvgRating = httpsCallable(functions, 'updateCourseAvgRating');
const result = await updateCourseAvgRating({ courseCode });

console.log('Average rating updated:', result.data.avgRating);
} catch (error) {
console.error("Error when adding a course to firebase or updating the average:", error);
}
Expand Down
3 changes: 1 addition & 2 deletions my-app/src/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ export const model = {

updateLevelFilter(level) {
this.filterOptions.level = level;
console.log(level);
},

updateDepartmentFilter(department) {
Expand Down Expand Up @@ -274,7 +273,7 @@ export const model = {
},
//for better display we would like the departments in a structured format based on school
formatDepartments() {
const grouped = this.departments?.reduce((acc, item) => {
const grouped = this?.departments.reduce((acc, item) => {
const [school, department] = item.split("/");
if (!acc[school]) {
acc[school] = [];
Expand Down
73 changes: 33 additions & 40 deletions my-app/src/presenters/FilterPresenter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@ import { SearchbarPresenter } from './SearchbarPresenter.jsx';
/* FilterPresenter is responsible for applying the logic necessary to filter out the courses from the overall list */
const FilterPresenter = observer(({ model }) => {
/* global variable for the scope of this presenter, all the smaller functions depend on it instead of passing it back and forth as params */
var localFilteredCourses = []; //might need to declare out of scope. idk js
var localFilteredCourses = [];

/* functions declared here are generally things the main function of this observer takes and runs if the given filters are enabled,
* this is determined through model.filterOptions.apply*Insert filter name* flags.
* This presenter should be changed such that it uses side-effects instead model.filtersChange flag, since
*/

/* functions */
function applyTranscriptEligibility() {
if (localFilteredCourses.length == 0)
return;

/* */
/* this should be either weak/moderate/strong */
const eligibilitytype = model.filterOptions.eligibility;

/* I am doing this trick in a multitude of filters, essentially the best fitting courses should appear first in the
* list view on the right side, so we just filter for those and at the very end merge them back together into a single array
*/
let strongcourses = [];
let zerocourses = [];
let moderatecourses = [];
Expand All @@ -24,7 +32,7 @@ const FilterPresenter = observer(({ model }) => {
let storedFinishedCourses = [];

if (localStorage.getItem("completedCourses"))
storedFinishedCourses = JSON.parse(localStorage.getItem("completedCourses"));
storedFinishedCourses = JSON.parse(localStorage.getItem("completedCourses")).map(obj => String(obj.id));


localFilteredCourses.forEach(course => {
Expand Down Expand Up @@ -55,6 +63,7 @@ const FilterPresenter = observer(({ model }) => {

});

/* If user selects strong matching he should get all courses which might be strongly fitting (so strong courses and zero/missing prereq courses) */
switch (eligibilitytype) {
case "strong":
{
Expand All @@ -73,7 +82,7 @@ const FilterPresenter = observer(({ model }) => {
}
default:
{
console.log("Error: somehow we got into a state where model.eligibility is no \"strong\"/\"moderate\"/\"weak\".");
console.log("Error: somehow we got into a state where model.eligibility is not either \"strong\"/\"moderate\"/\"weak\".");
localFilteredCourses = [];
break;
}
Expand Down Expand Up @@ -182,8 +191,6 @@ const FilterPresenter = observer(({ model }) => {
//course?.language.english (true/false/undefined)
//course?.language.swedish (true/false/undefined)

//console.log(data);

switch (languages) {
case "none":
{
Expand All @@ -196,8 +203,7 @@ const FilterPresenter = observer(({ model }) => {
try {
return (course?.language?.english === true);
} catch (error) {
console.log(course);
console.log("BIG ERROR", error);
console.log("BIG ERROR", error, course);
return false;
}

Expand All @@ -207,8 +213,7 @@ const FilterPresenter = observer(({ model }) => {
try {
return (course?.language === undefined);
} catch (error) {
console.log(course);
console.log("BIG ERROR");
console.log("BIG ERROR", error, course);
return false;
}

Expand All @@ -221,8 +226,7 @@ const FilterPresenter = observer(({ model }) => {
try {
return (course?.language?.swedish === true);
} catch (error) {
console.log(course);
console.log("BIG ERROR");
console.log("BIG ERROR", error, course);
return false;
}

Expand All @@ -232,8 +236,7 @@ const FilterPresenter = observer(({ model }) => {
try {
return (course?.language === undefined);
} catch (error) {
console.log(course);
console.log("BIG ERROR");
console.log("BIG ERROR", error, course);
return false;
}

Expand All @@ -246,8 +249,7 @@ const FilterPresenter = observer(({ model }) => {
try {
return ((course?.language?.english === true) && (course?.language?.swedish === true));
} catch (error) {
console.log(course);
console.log("BIG ERROR");
console.log("BIG ERROR", error, course);
return false;
}

Expand All @@ -258,8 +260,7 @@ const FilterPresenter = observer(({ model }) => {
return (((course?.language?.english === true) && (course?.language?.swedish === false))
|| ((course?.language?.english === false) && (course?.language?.swedish === true)));
} catch (error) {
console.log(course);
console.log("BIG ERROR");
console.log("BIG ERROR", error, course);
return false;
}

Expand All @@ -269,8 +270,7 @@ const FilterPresenter = observer(({ model }) => {
try {
return (course?.language === undefined);
} catch (error) {
console.log(course);
console.log("BIG ERROR");
console.log("BIG ERROR", error, course);
return false;
}

Expand All @@ -293,31 +293,16 @@ const FilterPresenter = observer(({ model }) => {

localFilteredCourses = localFilteredCourses.filter(course => levels.includes(course?.academicLevel));

/*
let levels = model.filterOptions.level;
let stayingCourses = [];

for(let i=0; i<localFilteredCourses.length; i++){
let stay = false;
for(let j=0; j<levels.length; j++){
if(localFilteredCourses[i].academicLevel === levels[j]){
stay = true;
break;
}
}
if(stay) stayingCourses.push(localFilteredCourses[i]);
}
localFilteredCourses = [...stayingCourses];*/
}

function updateDepartments() {
const deparments = model.filterOptions.deparment;
const departments = model.filterOptions.department;
let bestCourses = [];
let worstCourses = [];

bestCourses = localFilteredCourses.filter(function (course) {
try {
return (deparments.includes(course?.deparment));
return (departments.includes(course?.department));
} catch (error) {
console.log("for some reason course?.department is: ", course?.department, error);
return false;
Expand All @@ -328,7 +313,7 @@ const FilterPresenter = observer(({ model }) => {
try {
return (course?.department === undefined);
} catch (error) {
console.log("BIG ERROR", error);
console.log("BIG ERROR", error, course);
return false;
}

Expand All @@ -337,6 +322,10 @@ const FilterPresenter = observer(({ model }) => {
localFilteredCourses = [...bestCourses, ...worstCourses];
}

/* Function that deals with removing the courses that have no properties or have null properties in the categories the user
* using for filtering. The "null" check is a remainder from a version where we didn't use the ?. property accessing yet,
* should be able to be removed without problem in the future.
*/
function updateNoNullcourses(){
let local = [...localFilteredCourses];

Expand Down Expand Up @@ -380,6 +369,7 @@ const FilterPresenter = observer(({ model }) => {
localFilteredCourses = [...local];
}

/* function that should run every single time the model changes (see note below) */
async function run() {
if (model.courses.length == 0) {
return;
Expand Down Expand Up @@ -408,17 +398,20 @@ const FilterPresenter = observer(({ model }) => {
if (model.filterOptions.applyTranscriptFilter) {
applyTranscriptEligibility();
}
if (model.filterOptions.applyDepartments) {
if (model.filterOptions.applyDepartmentFilter) {
updateDepartments();
}

model.filteredCourses = [...localFilteredCourses];
model.filtersChange = false;
model.setFiltersCalculated();
//console.log("filtered objects number of elements: ", model.filteredCourses.length);
}
}

/* the problem is that unless using sideeffects, the run() not being async and/or it setting the filterschange = false very early can mean
* that 0 courses will get put into the model.filtered courses (which is the list of courses getting passed to search, and then listview)
* therefore TODO: rework it to stop using this dumb flags we started before learning anything about react,observers,js
*/
run();

});
Expand Down
19 changes: 0 additions & 19 deletions my-app/src/presenters/PrerequisitePresenter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export const PrerequisitePresenter = observer((props) => {
const nodeHeight = 36;

loadTree();
//console.log(initialNodes);

const getLayoutedElements = (nodes, edges, direction = 'LR') => {
const isHorizontal = direction === 'LR';
Expand Down Expand Up @@ -237,8 +236,6 @@ export const PrerequisitePresenter = observer((props) => {

if (!Array.isArray(current_object)) { // Is object
let key = Object.keys(current_object)[0];
//console.log("Len: " + current_object[key].length);
//console.log("Type: " + typeof current_object[key]);
if (current_object[key] != null && current_object[key].length == 1 && (typeof current_object[key][0] == "string"
|| (current_object[key][0].length == 1 && typeof current_object[key][0][0] == "string"))) {
prereq_convert(courses_taken, current_object[key], key, previous_node_id);
Expand Down Expand Up @@ -281,13 +278,10 @@ export const PrerequisitePresenter = observer((props) => {
if (!started_compressing) {
if (i < current_object.length - 2 && typeof current_object[i + 1] == "string" && typeof current_object[i + 2] == "string") {
let next = current_object[i + 1]; let next_next = current_object[i + 2];
//console.log(next)
//console.log(course_number, next.slice(2), next_next.slice(2))
if (next.slice(0, 2) === course_letters
&& next_next.slice(0, 2) === course_letters && !isNaN(next.slice(2))
&& !isNaN(next_next.slice(2)) && parseInt(next.slice(2)) == course_number + 1
&& parseInt(next_next.slice(2)) == course_number + 2) {
//console.log(course_number, next.slice(2), next_next.slice(2))
current_compresion.push([i, course_letters, course_number]);
current_compresion.push([i + 1, course_letters, course_number + 1]);
current_compresion.push([i + 2, course_letters, course_number + 2]);
Expand All @@ -312,7 +306,6 @@ export const PrerequisitePresenter = observer((props) => {
} else {
started_compressing = false;
//refined_course_array.push([i + 1, current_object[i + 1].slice(0, 2), current_object[i + 1].slice(2)]);
//console.log(current_compresion);
refined_course_array.push([-1, "!", current_compresion]);
current_compresion = [];
}
Expand All @@ -331,8 +324,6 @@ export const PrerequisitePresenter = observer((props) => {
}

}
//console.log("HERERERERERE!!!")
//console.log(refined_course_array);


for (let i = 0; i < refined_course_array.length; i++) {
Expand All @@ -359,8 +350,6 @@ export const PrerequisitePresenter = observer((props) => {
} else if (previous_key == "and" && compressed_done_count == compressed_length) {
course_done = true;
}
//console.log("Compressed:");
//console.log(refined_course_array[i][2]);
course_code = refined_course_array[i][2][0][1] + refined_course_array[i][2][0][2] +
"-" + refined_course_array[i][2][compressed_length - 1][1] + refined_course_array[i][2][compressed_length - 1][2];
input_text = course_code;
Expand Down Expand Up @@ -394,9 +383,6 @@ export const PrerequisitePresenter = observer((props) => {
if (typeof current_object == "object" && !Array.isArray(current_object)) {
let key = Object.keys(current_object)[0];
let object_array = current_object[key];
//console.log("DEBUGGING ")
//console.log(current_node)
//console.log(object_array)
let num_of_matches = 0;
for (let i = 0; i < object_array.length; i++) {
if (Array.isArray(object_array[i])) {
Expand Down Expand Up @@ -430,15 +416,12 @@ export const PrerequisitePresenter = observer((props) => {
} else if(object_array[i] === true) {num_of_matches++}
}
if (key == "or" && num_of_matches > 0) {
//console.log(current_node)
current_object[key] = true;
if (current_node != null) {
current_node["style"]["backgroundColor"] = "lightgreen";
}
}
else if (key == "and" && num_of_matches == object_array.length) {
//console.log("DEBUGGING 2");
//console.log(num_of_matches, object_array.length)
current_object[key] = true;
if (current_node != null) {
current_node["style"]["backgroundColor"] = "lightgreen";
Expand All @@ -453,7 +436,6 @@ export const PrerequisitePresenter = observer((props) => {

function generateTree(courses_taken, prereqs) {
prereq_convert(courses_taken, prereqs, null, props.selectedCourse.code);
//console.log(JSON.stringify(prereqs, null, 4));
let key = Object.keys(prereqs);
if (prereqs[key] === true) {
return true;
Expand All @@ -467,7 +449,6 @@ export const PrerequisitePresenter = observer((props) => {

function loadTree() {

//console.log(JSON.stringify(props.selectedCourse.prerequisites, null, 4));
if (!props.selectedCourse?.prerequisites || props.selectedCourse.prerequisites.length == 0) {
let display_node = createNode("No Prerequisites", "No Prerequisites", "default");
display_node.style["pointerEvents"] = "none";
Expand Down
Loading