diff --git a/my-app/src/model.js b/my-app/src/model.js index 4fb011a3..3152d604 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -18,7 +18,7 @@ export const model = { applyTranscriptFilter: true, eligibility: "weak", //the possible values for the string are: "weak"/"moderate"/"strong" applyLevelFilter: true, - level: [], //the possible values for the array are: "PREPARATORY", "BASIC", "ADVANCED", "RESEARCH" + level: ["PREPARATORY", "BASIC", "ADVANCED", "RESEARCH"], //the possible values for the array are: "PREPARATORY", "BASIC", "ADVANCED", "RESEARCH" applyLanguageFilter: true, language: "none", //the possible values for the string are: "none"/"english"/"swedish"/"both" applyLocationFilter:true, @@ -26,8 +26,12 @@ export const model = { applyCreditsFilter:true, creditMin: 0, creditMax: 45, - applyDepartmentFilter:false, - department: [] + applyDepartmentFilter: true, + department: ["EECS/Computational Science and Technology", "EECS/Theoretical Computer Science", "EECS/Electric Power and Energy Systems", "EECS/Network and Systems Engineering", + "ITM/Learning in Engineering Sciences", "ITM/Industrial Economics and Management", "ITM/Energy Systems", "ITM/Integrated Product Development and Design", "ITM/SKD GRU", + "SCI/Mathematics", "SCI/Applied Physics", "SCI/Mechanics", "SCI/Aeronautical and Vehicle Engineering", + "ABE/Sustainability and Environmental Engineering", "ABE/Concrete Structures", "ABE/Structural Design & Bridges", "ABE/History of Science, Technology and Environment", ], + applyRemoveNullCourses: false }, setUser(user) { @@ -144,6 +148,11 @@ export const model = { this.filterOptions.eligibility = eligibility; }, + updateDepartmentFilter(department) { + console.log(department); + this.filterOptions.department = department; + }, + //setters for the filter options setApplyTranscriptFilter(transcriptFilterState) { this.filterOptions.applyTranscriptFilter = transcriptFilterState; @@ -160,9 +169,9 @@ export const model = { setApplyCreditsFilter(creditsFilterState) { this.filterOptions.applyCreditsFilter = creditsFilterState; }, - // setApplyDepartmentFilter(departmentFilterState) { - // this.filterOptions.applyDepartmentFilter = departmentFilterState; - // }, + setApplyDepartmentFilter(departmentFilterState) { + this.filterOptions.applyDepartmentFilter = departmentFilterState; + }, async getAverageRating(courseCode) { const reviews = await getReviewsForCourse(courseCode); diff --git a/my-app/src/pages/App.jsx b/my-app/src/pages/App.jsx index ac7e426e..0beae15d 100644 --- a/my-app/src/pages/App.jsx +++ b/my-app/src/pages/App.jsx @@ -10,7 +10,6 @@ import { model } from '/src/model.js'; function MainAppLayout({ model }) { return (
-
@@ -21,6 +20,7 @@ function MainAppLayout({ model }) {
+
); diff --git a/my-app/src/presenters/FilterPresenter.jsx b/my-app/src/presenters/FilterPresenter.jsx index 46c71b84..0a7df957 100644 --- a/my-app/src/presenters/FilterPresenter.jsx +++ b/my-app/src/presenters/FilterPresenter.jsx @@ -1,13 +1,14 @@ import React from 'react'; import { observer } from "mobx-react-lite"; import eligibility from "../scripts/eligibility_refined.js"; +import { SearchbarPresenter } from './SearchbarPresenter.jsx'; const FilterPresenter = observer(({ model }) => { var localFilteredCourses = []; //might need to declare out of scope. idk js function applyTranscriptEligibility() { - if(localFilteredCourses.length == 0) + if (localFilteredCourses.length == 0) return; /* this elias thing */ const eligibilitytype = model.filterOptions.eligibility; @@ -22,36 +23,38 @@ const FilterPresenter = observer(({ model }) => { if (localStorage.getItem("completedCourses")) storedFinishedCourses = JSON.parse(localStorage.getItem("completedCourses")); - + localFilteredCourses.forEach(course => { //console.log(storedFinishedCourses); //console.log(course?.prerequisites); - if(course?.prerequisites && (course.prerequisites !== "null")) + if (storedFinishedCourses.includes(course?.code)) + return; + if (course?.prerequisites && (course.prerequisites !== "null")) var resultEligibility = eligibility(storedFinishedCourses, course?.prerequisites); - else{ // {strong: , zero: , moderate: , weak: } + else { // {strong: , zero: , moderate: , weak: } zerocourses.push(course); return; } - if(resultEligibility.strong){ + if (resultEligibility.strong) { strongcourses.push(course); return; - }else if(resultEligibility.zero){ + } else if (resultEligibility.zero) { zerocourses.push(course); return; - }else if(resultEligibility.moderate){ + } else if (resultEligibility.moderate) { moderatecourses.push(course); return; - }else if(resultEligibility.weak){ + } else if (resultEligibility.weak) { weakcourses.push(course); return; - }else{ + } else { //it's not eligible at all return; } - + }); - switch(eligibilitytype){ + switch (eligibilitytype) { case "strong": { localFilteredCourses = [...strongcourses, ...zerocourses]; @@ -65,7 +68,7 @@ const FilterPresenter = observer(({ model }) => { case "weak": { localFilteredCourses = [...strongcourses, ...moderatecourses, ...weakcourses, ...zerocourses]; - break; + break; } default: { @@ -74,24 +77,24 @@ const FilterPresenter = observer(({ model }) => { break; } } - + } function updateCredits() { - if(localFilteredCourses.length == 0) + if (localFilteredCourses.length == 0) return; const min = model.filterOptions.creditMin; const max = model.filterOptions.creditMax; - localFilteredCourses = localFilteredCourses.filter(function(course){ + localFilteredCourses = localFilteredCourses.filter(function (course) { try { - return ((course.credits >= min)&&(course.credits <= max)); + return ((course.credits >= min) && (course.credits <= max)); } catch (error) { console.log("for some reason course.credits is: ", course?.credits, error); return false; } - + }); } @@ -103,31 +106,31 @@ const FilterPresenter = observer(({ model }) => { let bestCourses = []; let worstCourses = []; - bestCourses = localFilteredCourses.filter(function(course) { + bestCourses = localFilteredCourses.filter(function (course) { try { return (locations.includes(course.location)); } catch (error) { console.log("for some reason course.location is: ", course?.location, error); return false; } - + }); - worstCourses = localFilteredCourses.filter(function(course) { + worstCourses = localFilteredCourses.filter(function (course) { try { return ((course?.location === undefined) || (course?.location === "null")); } catch (error) { console.log("BIG ERROR", error); return false; } - + }); localFilteredCourses = [...bestCourses, ...worstCourses]; - + } function updateLanguages() { - if(localFilteredCourses.length == 0) + if (localFilteredCourses.length == 0) return; //possible model.filterOptions.languages values: "none"/"english"/"swedish"/"both" const languages = model.filterOptions.language; @@ -141,7 +144,7 @@ const FilterPresenter = observer(({ model }) => { //course.language.swedish (true/false/"null") //console.log(data); - + switch (languages) { case "none": { @@ -158,18 +161,18 @@ const FilterPresenter = observer(({ model }) => { console.log("BIG ERROR", error); return false; } - + } ); - worstCourses = data.filter(function(course) { + worstCourses = data.filter(function (course) { try { - return ((course?.language === undefined ) || course?.language?.english === "null"); + return ((course?.language === undefined) || course?.language?.english === "null"); } catch (error) { console.log(course); console.log("BIG ERROR"); return false; } - + }); break; } @@ -183,18 +186,18 @@ const FilterPresenter = observer(({ model }) => { console.log("BIG ERROR"); return false; } - + } ); - worstCourses = data.filter(function(course) { + worstCourses = data.filter(function (course) { try { - return ((course?.language === undefined ) || course?.language?.swedish === "null"); + return ((course?.language === undefined) || course?.language?.swedish === "null"); } catch (error) { console.log(course); console.log("BIG ERROR"); return false; } - + }); break; } @@ -208,30 +211,30 @@ const FilterPresenter = observer(({ model }) => { console.log("BIG ERROR"); return false; } - + } ); middleCourses = data.filter(function (course) { try { return (((course?.language?.english === true) && (course?.language?.swedish === false)) - || ((course?.language?.english === false) && (course?.language?.swedish === true))); + || ((course?.language?.english === false) && (course?.language?.swedish === true))); } catch (error) { console.log(course); console.log("BIG ERROR"); return false; } - - } + + } ); - worstCourses = data.filter(function(course) { + worstCourses = data.filter(function (course) { try { - return ((course?.language === undefined ) || course?.language?.english === "null"); + return ((course?.language === undefined) || course?.language?.english === "null"); } catch (error) { console.log(course); console.log("BIG ERROR"); return false; } - + }); break; } @@ -241,16 +244,16 @@ const FilterPresenter = observer(({ model }) => { } function updateLevels() { - if(localFilteredCourses.length == 0) + if (localFilteredCourses.length == 0) return; //the possible values are: "PREPARATORY", "BASIC", "ADVANCED", "RESEARCH" //model.filterOptions.level is an array. it can have [] const levels = model.filterOptions.level; - - - localFilteredCourses = localFilteredCourses.filter(course => levels.includes(course.academicLevel)); - + + + localFilteredCourses = localFilteredCourses.filter(course => levels.includes(course?.academicLevel)); + /* let levels = model.filterOptions.level; let stayingCourses = []; @@ -268,64 +271,120 @@ const FilterPresenter = observer(({ model }) => { localFilteredCourses = [...stayingCourses];*/ } - function updateDepartments(){ + function updateDepartments() { const deparments = model.filterOptions.deparment; let bestCourses = []; let worstCourses = []; - bestCourses = localFilteredCourses.filter(function(course) { + bestCourses = localFilteredCourses.filter(function (course) { try { return (deparments.includes(course.deparment)); } catch (error) { console.log("for some reason course.department is: ", course?.department, error); return false; } - + }); - worstCourses = localFilteredCourses.filter(function(course) { + worstCourses = localFilteredCourses.filter(function (course) { try { return ((course?.department === undefined) || (course?.deparment === "null")); } catch (error) { console.log("BIG ERROR", error); return false; } - + }); localFilteredCourses = [...bestCourses, ...worstCourses]; } - - if (model.filtersChange) { - localFilteredCourses = [...model.courses]; - if (model.filterOptions.applyLocationFilter) { - //after deo finishes locations, until then dont + function updateNoNullcourses(){ + let local = [...localFilteredCourses]; + + console.log("miauuuuu:",local.length); - //console.log("going to apply location on:",localFilteredCourses.length); - //updateLocations(); + if(model.filterOptions.applyTranscriptFilter){ + local = local.filter(function(course){ + return (course?.prerequisites && (course.prerequisites !== "null")); + }) } - if (model.filterOptions.applyLevelFilter) { - updateLevels(); + console.log("miauuuuu:",local.length); + if(model.filterOptions.applyLevelFilter){ + local = local.filter(function(course){ + return (course?.prerequisites && (course.prerequisites !== "null")); + }) } - if (model.filterOptions.applyLanguageFilter) { - updateLanguages(); + console.log("miauuuuu:",local.length); + if(model.filterOptions.applyLanguageFilter){ + local = local.filter(function(course){ + return ((course?.language) && (course?.language?.swedish !== "null" && course?.language?.english !== "null")); + }) } - if (model.filterOptions.applyCreditsFilter) { - updateCredits(); + console.log("miauuuuu:",local.length); + /*if(model.filterOptions.applyLocationFilter){ + local = local.filter(function(course){ + return ((course?.location) && (course?.location !== "null")); + }) + }*/ + console.log("miauuuuu:",local.length); + if(model.filterOptions.applyCreditsFilter){ + local = local.filter(function(course){ + return ((course?.credit) && (course?.credit !== "null")); + }) } - if (model.filterOptions.applyTranscriptFilter) { - applyTranscriptEligibility(); + console.log("miauuuuu:",local.length); + if(model.filterOptions.applyDepartmentFilter){ + local = local.filter(function(course){ + return ((course?.deparment) && (course?.department !== "null")); + }) } - if (model.filterOptions.applyDepartments) { - //console.log("going to apply location on:",localFilteredCourses.length); - //updateDepartments(); + console.log("miauuuuu:",local.length); + + localFilteredCourses = [...local]; + } + + async function run() { + if (model.courses.length == 0) { + return; } + if (model.filtersChange) { + localFilteredCourses = [...model.courses]; - model.filteredCourses = [...localFilteredCourses]; - model.filtersChange = false; - model.setFiltersCalculated(); - console.log("filtered objects number of elements: ", model.filteredCourses.length); + if (model.filterOptions.applyRemoveNullCourses) { + updateNoNullcourses(); + } + if (model.filterOptions.applyLocationFilter) { + //after deo finishes locations, until then dont + + //console.log("going to apply location on:",localFilteredCourses.length); + //updateLocations(); + } + if (model.filterOptions.applyLevelFilter) { + updateLevels(); + } + if (model.filterOptions.applyLanguageFilter) { + updateLanguages(); + } + if (model.filterOptions.applyCreditsFilter) { + updateCredits(); + } + if (model.filterOptions.applyTranscriptFilter) { + applyTranscriptEligibility(); + } + if (model.filterOptions.applyDepartments) { + //console.log("going to apply location on:",localFilteredCourses.length); + //updateDepartments(); + } + + model.filteredCourses = [...localFilteredCourses]; + model.filtersChange = false; + model.setFiltersCalculated(); + console.log("filtered objects number of elements: ", model.filteredCourses.length); + } } + + run(); + }); export { FilterPresenter }; \ No newline at end of file diff --git a/my-app/src/presenters/SearchbarPresenter.jsx b/my-app/src/presenters/SearchbarPresenter.jsx index 242b9d02..67d1cc39 100644 --- a/my-app/src/presenters/SearchbarPresenter.jsx +++ b/my-app/src/presenters/SearchbarPresenter.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { observer } from "mobx-react-lite"; import { useState } from 'react'; import CoursePagePopup from '../views/Components/CoursePagePopup.jsx'; @@ -7,6 +7,7 @@ import { ReviewPresenter } from "../presenters/ReviewPresenter.jsx"; import SearchbarView from "../views/SearchbarView.jsx"; const SearchbarPresenter = observer(({ model }) => { + const searchCourses = (query) => { //model.filteredCourses is essentially a smaller subset of model.courses, if theres no filters, it should be the same console.log("---------------search recalculated"); diff --git a/my-app/src/presenters/SidebarPresenter.jsx b/my-app/src/presenters/SidebarPresenter.jsx index 42bab7f2..ed6f4afe 100644 --- a/my-app/src/presenters/SidebarPresenter.jsx +++ b/my-app/src/presenters/SidebarPresenter.jsx @@ -1,12 +1,22 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { observer } from "mobx-react-lite"; import SidebarView from "../views/SidebarView.jsx"; const SidebarPresenter = observer(({ model }) => { + useEffect(() => { + model.setFiltersChange(); + }) + let currentLanguageSet = 'none'; - let currentLevelSet = []; + let currentLevelSet = ["PREPARATORY", "BASIC", "ADVANCED", "RESEARCH"]; + let currentDepartmentSet = [ + "EECS/Computational Science and Technology", "EECS/Theoretical Computer Science", "EECS/Electric Power and Energy Systems", "EECS/Network and Systems Engineering", + "ITM/Learning in Engineering Sciences", "ITM/Industrial Economics and Management", "ITM/Energy Systems", "ITM/Integrated Product Development and Design", "ITM/SKD GRU", + "SCI/Mathematics", "SCI/Applied Physics", "SCI/Mechanics", "SCI/Aeronautical and Vehicle Engineering", + "ABE/Sustainability and Environmental Engineering", "ABE/Concrete Structures", "ABE/Structural Design & Bridges", "ABE/History of Science, Technology and Environment", + ] function handleLanguageFilterChange(param) { if (param === "English") { switch (currentLanguageSet) { @@ -73,6 +83,19 @@ const SidebarPresenter = observer(({ model }) => { model.updateLevelFilter(currentLevelSet); } + function handleDepartmentFilterChange(param) { + if (currentDepartmentSet.includes(param)) { + const index = currentDepartmentSet.indexOf(param); + if (index > -1) { + currentDepartmentSet.splice(index, 1); + } + } else { + currentDepartmentSet.push(param); + } + model.updateDepartmentFilter(currentDepartmentSet); + model.setFiltersChange(); + } + /*HandleFilterChange param is structured as such [ type of the field: (toggle, slider, dropdown, buttongroup) @@ -97,6 +120,9 @@ const SidebarPresenter = observer(({ model }) => { case "eligibility": model.updateTranscriptElegibilityFilter(param[2].toLowerCase()); break; + case "department": + handleDepartmentFilterChange(param[2]); + break; default: console.log("Invalid filter type"); } @@ -131,14 +157,26 @@ const SidebarPresenter = observer(({ model }) => { console.log("transcript filter set to: " + param[1]); model.setApplyTranscriptFilter(param[1]); break; + case "department": + console.log("department filter set to: " + param[1]); + model.setApplyDepartmentFilter(param[1]); + break; default: console.log("Invalid filter type"); } model.setFiltersChange(); } + function reApplyFilter() { + model.setFiltersChange(); + } + + + return ( + HandleFilterEnable={HandleFilterEnable} + reApplyFilter={reApplyFilter} + /> ); }); diff --git a/my-app/src/presenters/UploadTranscriptPresenter.jsx b/my-app/src/presenters/UploadTranscriptPresenter.jsx index c473d157..7bd85005 100644 --- a/my-app/src/presenters/UploadTranscriptPresenter.jsx +++ b/my-app/src/presenters/UploadTranscriptPresenter.jsx @@ -167,6 +167,8 @@ const UploadTranscriptPresenter = observer((props) => { } writeLocalStorage_completedCourses(scrapedCodes); //console.log(localStorage.getItem("completedCourses")); + + props.reApplyFilter(); } const handleFileChange = (event) => { @@ -185,7 +187,8 @@ const UploadTranscriptPresenter = observer((props) => { fileInputValue={fileInputValue} HandleFilterEnable={props.HandleFilterEnable} HandleFilterChange={props.HandleFilterChange} - filterName= {props.filterName} + filterName={props.filterName} + reApplyFilter = {props.reApplyFilter} />); }); diff --git a/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx b/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx index 8d445a05..be644fde 100644 --- a/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx +++ b/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx @@ -7,7 +7,11 @@ const CollapsibleCheckboxes = (props) => { const [checkedSubItems, setCheckedSubItems] = useState({}); const [stupidLines, setStupidLines] = useState(0); - const strokeWidth = 2; + const strokeWidth = 5; + + let paramFieldType = "checkboxhierarchy"; + + const rows = props.fields; const toggleExpand = (id, subItems) => { setExpanded((prev) => ({ @@ -33,38 +37,9 @@ const CollapsibleCheckboxes = (props) => { ...prev, [key]: !prev[key], })); + props.HandleFilterChange([paramFieldType, props.filterName, rows.find(item => item.id === mainId).label+"/"+rows.find(item => item.id === mainId).subItems[index]]); }; - const rows = [ - { - id: 1, - label: "Category 1", - subItems: ["Sub-item 1.1", "Sub-item 1.2", "Sub-item 1.3"], - }, - { - id: 2, - label: "Category 2", - subItems: ["Sub-item 2.1", "Sub-item 2.2"], - }, - { - id: 3, - label: "Category 2", - subItems: ["Sub-item 2.1", "Sub-item 2.2"], - }, - { - id: 4, - label: "Category 3", - subItems: [ - "Sub-item 3.1", - "Sub-item 3.2", - "Sub-item 3.3", - "Sub-item 3.4", - "Sub-item 3.5", - "Sub-item 3.6", - ], - }, - ]; - return (
@@ -107,13 +82,13 @@ const CollapsibleCheckboxes = (props) => { { onChange={() => toggleSubCheckbox(row.id, index)} />
); diff --git a/my-app/src/views/Components/SideBarComponents/CourseTranscriptList.jsx b/my-app/src/views/Components/SideBarComponents/CourseTranscriptList.jsx index f4ba0bd1..fe193fc8 100644 --- a/my-app/src/views/Components/SideBarComponents/CourseTranscriptList.jsx +++ b/my-app/src/views/Components/SideBarComponents/CourseTranscriptList.jsx @@ -1,6 +1,6 @@ import { useState } from "react"; -export default function CourseTranscriptList() { +export default function CourseTranscriptList(props) { let local = []; if (localStorage.getItem("completedCourses")) local = JSON.parse(localStorage.getItem("completedCourses")); @@ -23,12 +23,13 @@ export default function CourseTranscriptList() { } localStorage.setItem("completedCourses", JSON.stringify(newItems)); window.dispatchEvent(new Event("completedCourses changed")); + props.reApplyFilter(); }; function removeAllItems() { let newitems = []; localStorage.setItem("completedCourses", JSON.stringify(newitems)); window.dispatchEvent(new Event("completedCourses changed")); - + props.reApplyFilter(); }; diff --git a/my-app/src/views/Components/SideBarComponents/DropDownField.jsx b/my-app/src/views/Components/SideBarComponents/DropDownField.jsx index d8cdfd52..9949c774 100644 --- a/my-app/src/views/Components/SideBarComponents/DropDownField.jsx +++ b/my-app/src/views/Components/SideBarComponents/DropDownField.jsx @@ -12,12 +12,17 @@ export default function DropDownField(props) { const items = props.options; + useEffect(() => { + setSelectedItems(items); + }, [items]); + const toggleDropdown = () => setIsOpen(!isOpen); const handleCheckboxChange = (item) => { setSelectedItems((prev) => prev.includes(item) ? prev.filter((i) => i !== item) : [...prev, item] ); + console.log(item); props.HandleFilterChange([paramFieldType, props.filterName, item]); }; @@ -52,7 +57,7 @@ export default function DropDownField(props) {
-
+
{/* Dropdown Button */}
); diff --git a/my-app/src/views/ListView.jsx b/my-app/src/views/ListView.jsx index d93e6a42..211a27f2 100644 --- a/my-app/src/views/ListView.jsx +++ b/my-app/src/views/ListView.jsx @@ -4,7 +4,7 @@ import 'ldrs/react/Quantum.css'; import InfiniteScroll from 'react-infinite-scroll-component'; function ListView(props) { - const coursesToDisplay = props.searchResults.length > 0 ? props.searchResults : props.courses; + const coursesToDisplay = props.searchResults; const [displayedCourses, setDisplayedCourses] = useState([]); const [hasMore, setHasMore] = useState(true); const [readMore, setReadMore] = useState({}); diff --git a/my-app/src/views/SidebarView.jsx b/my-app/src/views/SidebarView.jsx index d9afe5ed..04c016a0 100644 --- a/my-app/src/views/SidebarView.jsx +++ b/my-app/src/views/SidebarView.jsx @@ -18,26 +18,27 @@ function SidebarView(props) { }} >
- Filters -
+ Filters +
- + @@ -58,6 +59,51 @@ function SidebarView(props) { HandleFilterChange={props.HandleFilterChange} filterName="department" HandleFilterEnable={props.HandleFilterEnable} + fields={ + [ + { + id: 1, + label: "EECS", + subItems: [ + "Computational Science and Technology", + "Theoretical Computer Science", + "Electric Power and Energy Systems", + "Network and Systems Engineering", + ], + }, + { + id: 2, + label: "ITM", + subItems: [ + "Learning in Engineering Sciences", + "Industrial Economics and Management", + "Energy Systems", + "Integrated Product Development and Design", + "SKD GRU", + ], + }, + { + id: 3, + label: "SCI", + subItems: [ + "Mathematics", + "Applied Physics", + "Mechanics", + "Aeronautical and Vehicle Engineering", + ], + }, + { + id: 4, + label: "ABE", + subItems: [ + "Sustainability and Environmental Engineering", + "Concrete Structures", + "Structural Design & Bridges", + "History of Science, Technology and Environment", + ], + }, + ] + } />