From da166c7f7f09767a5307cec9a0089814ee856e9f Mon Sep 17 00:00:00 2001 From: benedekboldizsar Date: Wed, 16 Apr 2025 09:29:46 +0200 Subject: [PATCH 1/7] applied filters into the search function using flags in the model, will have to refine more in the filters, but this is great for the demo --- my-app/src/model.js | 5 +++++ my-app/src/pages/App.jsx | 2 +- my-app/src/presenters/FilterPresenter.jsx | 5 +++-- my-app/src/presenters/SearchbarPresenter.jsx | 7 ++++++- my-app/src/views/ListView.jsx | 6 +++--- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/my-app/src/model.js b/my-app/src/model.js index 6fc835fa..7e323ed9 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -10,6 +10,7 @@ export const model = { favourites: [], isReady: false, filtersChange: false, + filtersCalculated: false, filteredCourses: [], filterOptions: { applyTranscriptFilter: true, @@ -108,6 +109,10 @@ export const model = { setFiltersChange() { this.filtersChange = true; }, + + setFiltersCalculated() { + this.filtersCalculated = true; + }, updateLevelFilter(level) { this.filterOptions.level = level; diff --git a/my-app/src/pages/App.jsx b/my-app/src/pages/App.jsx index 206dedce..ac7e426e 100644 --- a/my-app/src/pages/App.jsx +++ b/my-app/src/pages/App.jsx @@ -9,7 +9,7 @@ import { model } from '/src/model.js'; function MainAppLayout({ model }) { return ( -
+
diff --git a/my-app/src/presenters/FilterPresenter.jsx b/my-app/src/presenters/FilterPresenter.jsx index 2e356084..007445f7 100644 --- a/my-app/src/presenters/FilterPresenter.jsx +++ b/my-app/src/presenters/FilterPresenter.jsx @@ -28,8 +28,8 @@ const FilterPresenter = observer(({ model }) => { //console.log(course?.prerequisites); if(course?.prerequisites && (course.prerequisites !== "null")) var resultEligibility = eligibility(storedFinishedCourses, course?.prerequisites); - else{ - //zerocourses.push(course); + else{ // {strong: , zero: , moderate: , weak: } + zerocourses.push(course); return; } if(resultEligibility.strong){ @@ -292,6 +292,7 @@ const FilterPresenter = observer(({ model }) => { model.filteredCourses = [...localFilteredCourses]; model.filtersChange = false; + model.setFiltersCalculated(); console.log("filtered objects number of elements: ", model.filteredCourses.length); } }); diff --git a/my-app/src/presenters/SearchbarPresenter.jsx b/my-app/src/presenters/SearchbarPresenter.jsx index 1e127dca..c1a86f77 100644 --- a/my-app/src/presenters/SearchbarPresenter.jsx +++ b/my-app/src/presenters/SearchbarPresenter.jsx @@ -11,7 +11,7 @@ const SearchbarPresenter = observer(({ model }) => { //model.filteredCourses is essentially a smaller subset of model.courses, if theres no filters, it should be the same console.log("---------------search recalculated"); console.log("filtered courses length: ", model.filteredCourses.length); - const searchResults = model.courses.filter(course => + const searchResults = model.filteredCourses.filter(course => course.code.toLowerCase().includes(query.toLowerCase()) || course.name.toLowerCase().includes(query.toLowerCase()) || course.description.toLowerCase().includes(query.toLowerCase()) @@ -61,6 +61,11 @@ const SearchbarPresenter = observer(({ model }) => { prerequisiteTree={preP} />; + if(model.filtersCalculated){ + searchCourses(""); + model.filtersCalculated = false; + } + return ( 0 + const coursesToDisplay = props.searchResults; + /*(props.searchResults && props.searchResults.length > 0 ? props.searchResults - : props.courses) || []; + : props.courses) || [];*/ const [displayedCourses, setDisplayedCourses] = useState([]); const [hasMore, setHasMore] = useState(true); From 190a822d8643a64c2b9622c09de2c01d6f57baa9 Mon Sep 17 00:00:00 2001 From: benedekboldizsar Date: Wed, 16 Apr 2025 10:18:01 +0200 Subject: [PATCH 2/7] wrote departments filter option --- my-app/src/model.js | 3 ++- my-app/src/presenters/FilterPresenter.jsx | 31 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/my-app/src/model.js b/my-app/src/model.js index 7e323ed9..5e8d3c08 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -24,7 +24,8 @@ export const model = { applyCreditsFilter:true, creditMin: 0, creditMax: 45, - //applyDepartmentFilter:false, + applyDepartmentFilter:false, + department: [] }, setUser(user) { diff --git a/my-app/src/presenters/FilterPresenter.jsx b/my-app/src/presenters/FilterPresenter.jsx index 007445f7..46c71b84 100644 --- a/my-app/src/presenters/FilterPresenter.jsx +++ b/my-app/src/presenters/FilterPresenter.jsx @@ -267,6 +267,33 @@ const FilterPresenter = observer(({ model }) => { } localFilteredCourses = [...stayingCourses];*/ } + + function updateDepartments(){ + const deparments = model.filterOptions.deparment; + let bestCourses = []; + let worstCourses = []; + + 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) { + 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]; @@ -289,6 +316,10 @@ const FilterPresenter = observer(({ model }) => { 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; From 7ca07a11877222994152e4e33cc11b883d8b13a5 Mon Sep 17 00:00:00 2001 From: benedekboldizsar Date: Wed, 16 Apr 2025 11:26:04 +0200 Subject: [PATCH 3/7] added check to make sure to not recommend courses the client has taken before --- my-app/src/presenters/FilterPresenter.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/my-app/src/presenters/FilterPresenter.jsx b/my-app/src/presenters/FilterPresenter.jsx index 46c71b84..70f45f5a 100644 --- a/my-app/src/presenters/FilterPresenter.jsx +++ b/my-app/src/presenters/FilterPresenter.jsx @@ -26,6 +26,8 @@ const FilterPresenter = observer(({ model }) => { localFilteredCourses.forEach(course => { //console.log(storedFinishedCourses); //console.log(course?.prerequisites); + if(storedFinishedCourses.includes(course?.code)) + return; if(course?.prerequisites && (course.prerequisites !== "null")) var resultEligibility = eligibility(storedFinishedCourses, course?.prerequisites); else{ // {strong: , zero: , moderate: , weak: } From df2872b446c4a44eb4e26cf45208f0a338f81a8d Mon Sep 17 00:00:00 2001 From: kexana Date: Wed, 16 Apr 2025 14:04:19 +0200 Subject: [PATCH 4/7] initial state good --- my-app/src/model.js | 6 +- my-app/src/pages/App.jsx | 2 +- my-app/src/presenters/FilterPresenter.jsx | 181 ++++++++++-------- my-app/src/presenters/SearchbarPresenter.jsx | 3 +- my-app/src/presenters/SidebarPresenter.jsx | 20 +- .../presenters/UploadTranscriptPresenter.jsx | 5 +- .../CollapsibleCheckboxes.jsx | 8 +- .../CourseTranscriptList.jsx | 5 +- .../SideBarComponents/DropDownField.jsx | 9 +- .../SideBarComponents/UploadField.jsx | 5 +- my-app/src/views/ListView.jsx | 9 +- my-app/src/views/SidebarView.jsx | 1 + 12 files changed, 158 insertions(+), 96 deletions(-) diff --git a/my-app/src/model.js b/my-app/src/model.js index 5e8d3c08..e118a497 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -16,7 +16,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, @@ -24,7 +24,7 @@ export const model = { applyCreditsFilter:true, creditMin: 0, creditMax: 45, - applyDepartmentFilter:false, + applyDepartmentFilter: true, department: [] }, @@ -138,6 +138,8 @@ export const model = { }, setApplyLevelFilter(levelFilterState) { this.filterOptions.applyLevelFilter = levelFilterState; + + console.log("model -",this.filterOptions.level); }, setApplyLanguageFilter(languageFilterState) { this.filterOptions.applyLanguageFilter = languageFilterState; 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 70f45f5a..a673d1ab 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,38 +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(storedFinishedCourses.includes(course?.code)) + if (storedFinishedCourses.includes(course?.code)) return; - if(course?.prerequisites && (course.prerequisites !== "null")) + 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]; @@ -67,7 +68,7 @@ const FilterPresenter = observer(({ model }) => { case "weak": { localFilteredCourses = [...strongcourses, ...moderatecourses, ...weakcourses, ...zerocourses]; - break; + break; } default: { @@ -76,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; } - + }); } @@ -105,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; @@ -143,7 +144,7 @@ const FilterPresenter = observer(({ model }) => { //course.language.swedish (true/false/"null") //console.log(data); - + switch (languages) { case "none": { @@ -160,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; } @@ -185,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; } @@ -210,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; } @@ -243,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)); - + /* let levels = model.filterOptions.level; let stayingCourses = []; @@ -270,64 +271,90 @@ 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]; + async function run() { + if (model.courses.length == 0) { + return; + } + if (model.filtersChange) { + localFilteredCourses = [...model.courses]; - if (model.filterOptions.applyLocationFilter) { - //after deo finishes locations, until then dont + 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(); - } + //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.filtersChange) { + localFilteredCourses = [...model.courses]; + + if (model.filterOptions.applyLocationFilter) { + //after deo finishes locations, until then dont - model.filteredCourses = [...localFilteredCourses]; - model.filtersChange = false; - model.setFiltersCalculated(); - console.log("filtered objects number of elements: ", model.filteredCourses.length); + //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 c1a86f77..2e9ecb2b 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..039670e3 100644 --- a/my-app/src/presenters/SidebarPresenter.jsx +++ b/my-app/src/presenters/SidebarPresenter.jsx @@ -1,12 +1,16 @@ -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"]; function handleLanguageFilterChange(param) { if (param === "English") { switch (currentLanguageSet) { @@ -117,6 +121,8 @@ const SidebarPresenter = observer(({ model }) => { break; case "level": console.log("level filter set to: " + param[1]); + + console.log("model -",model.filterOptions.level); model.setApplyLevelFilter(param[1]); break; case "location": @@ -136,9 +142,17 @@ const SidebarPresenter = observer(({ model }) => { } 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..2ec89c70 100644 --- a/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx +++ b/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx @@ -7,7 +7,7 @@ const CollapsibleCheckboxes = (props) => { const [checkedSubItems, setCheckedSubItems] = useState({}); const [stupidLines, setStupidLines] = useState(0); - const strokeWidth = 2; + const strokeWidth = 5; const toggleExpand = (id, subItems) => { setExpanded((prev) => ({ @@ -107,13 +107,13 @@ const CollapsibleCheckboxes = (props) => { { + 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 72f4e8f6..3ef9a523 100644 --- a/my-app/src/views/ListView.jsx +++ b/my-app/src/views/ListView.jsx @@ -3,6 +3,8 @@ import { DotPulse, Quantum } from 'ldrs/react'; import 'ldrs/react/Quantum.css'; import InfiniteScroll from 'react-infinite-scroll-component'; +var startupFlag = true; + function ListView(props) { const coursesToDisplay = props.searchResults; /*(props.searchResults && props.searchResults.length > 0 @@ -21,6 +23,12 @@ function ListView(props) { })); }; + if (startupFlag) { + startupFlag = false; + console.log("first presenter"); + //model.setFiltersCalculated(); +} + const handleFavouriteClick = (course) => { if (props.favouriteCourses?.some((fav) => fav.code === course.code)) { props.removeFavourite(course); @@ -54,7 +62,6 @@ function ListView(props) {
); } - return (
{isLoading ? ( diff --git a/my-app/src/views/SidebarView.jsx b/my-app/src/views/SidebarView.jsx index d9afe5ed..f7b92def 100644 --- a/my-app/src/views/SidebarView.jsx +++ b/my-app/src/views/SidebarView.jsx @@ -24,6 +24,7 @@ function SidebarView(props) { HandleFilterChange={props.HandleFilterChange} filterName = "transcript" HandleFilterEnable={props.HandleFilterEnable} + reApplyFilter = {props.reApplyFilter} />
From d8f15435d0a6d75d31a41ebb66fc1d0396b56458 Mon Sep 17 00:00:00 2001 From: kexana Date: Wed, 16 Apr 2025 15:29:47 +0200 Subject: [PATCH 5/7] departments go to model --- my-app/src/model.js | 18 ++++-- my-app/src/presenters/SidebarPresenter.jsx | 32 ++++++++-- .../CollapsibleCheckboxes.jsx | 37 ++---------- my-app/src/views/SidebarView.jsx | 59 ++++++++++++++++--- 4 files changed, 98 insertions(+), 48 deletions(-) diff --git a/my-app/src/model.js b/my-app/src/model.js index e118a497..15f3275b 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -25,7 +25,10 @@ export const model = { creditMin: 0, creditMax: 45, applyDepartmentFilter: true, - department: [] + 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", ] }, setUser(user) { @@ -132,14 +135,17 @@ 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; }, setApplyLevelFilter(levelFilterState) { this.filterOptions.applyLevelFilter = levelFilterState; - - console.log("model -",this.filterOptions.level); }, setApplyLanguageFilter(languageFilterState) { this.filterOptions.applyLanguageFilter = languageFilterState; @@ -150,9 +156,9 @@ export const model = { setApplyCreditsFilter(creditsFilterState) { this.filterOptions.applyCreditsFilter = creditsFilterState; }, - // setApplyDepartmentFilter(departmentFilterState) { - // this.filterOptions.applyDepartmentFilter = departmentFilterState; - // }, + setApplyDepartmentFilter(departmentFilterState) { + this.filterOptions.applyDepartmentFilter = departmentFilterState; + }, diff --git a/my-app/src/presenters/SidebarPresenter.jsx b/my-app/src/presenters/SidebarPresenter.jsx index 039670e3..ed6f4afe 100644 --- a/my-app/src/presenters/SidebarPresenter.jsx +++ b/my-app/src/presenters/SidebarPresenter.jsx @@ -11,6 +11,12 @@ const SidebarPresenter = observer(({ model }) => { let currentLanguageSet = 'none'; 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) { @@ -77,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) @@ -101,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"); } @@ -121,8 +143,6 @@ const SidebarPresenter = observer(({ model }) => { break; case "level": console.log("level filter set to: " + param[1]); - - console.log("model -",model.filterOptions.level); model.setApplyLevelFilter(param[1]); break; case "location": @@ -137,6 +157,10 @@ 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"); } @@ -146,12 +170,12 @@ const SidebarPresenter = observer(({ model }) => { model.setFiltersChange(); } - + return ( ); }); diff --git a/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx b/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx index 2ec89c70..be644fde 100644 --- a/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx +++ b/my-app/src/views/Components/SideBarComponents/CollapsibleCheckboxes.jsx @@ -9,6 +9,10 @@ const CollapsibleCheckboxes = (props) => { const strokeWidth = 5; + let paramFieldType = "checkboxhierarchy"; + + const rows = props.fields; + const toggleExpand = (id, subItems) => { setExpanded((prev) => ({ ...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 (
@@ -190,7 +165,7 @@ const CollapsibleCheckboxes = (props) => { onChange={() => toggleSubCheckbox(row.id, index)} />
); diff --git a/my-app/src/views/SidebarView.jsx b/my-app/src/views/SidebarView.jsx index f7b92def..04c016a0 100644 --- a/my-app/src/views/SidebarView.jsx +++ b/my-app/src/views/SidebarView.jsx @@ -18,27 +18,27 @@ function SidebarView(props) { }} >
- Filters -
+ Filters +
- + @@ -59,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", + ], + }, + ] + } />
From b162882a5accaf5be341240df8c51041e0b87527 Mon Sep 17 00:00:00 2001 From: benedekboldizsar Date: Wed, 16 Apr 2025 15:31:36 +0200 Subject: [PATCH 6/7] trying to add filtering out courses with NULL fields as an implementable filter option, merging with main start as per teams request --- my-app/src/model.js | 3 +- my-app/src/presenters/FilterPresenter.jsx | 92 +++++++++++++++-------- my-app/src/views/ListView.jsx | 2 +- 3 files changed, 64 insertions(+), 33 deletions(-) diff --git a/my-app/src/model.js b/my-app/src/model.js index d259614d..12ed3897 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -27,7 +27,8 @@ export const model = { creditMin: 0, creditMax: 45, applyDepartmentFilter: true, - department: [] + department: [], + applyRemoveNullCourses: false }, setUser(user) { diff --git a/my-app/src/presenters/FilterPresenter.jsx b/my-app/src/presenters/FilterPresenter.jsx index a673d1ab..0a7df957 100644 --- a/my-app/src/presenters/FilterPresenter.jsx +++ b/my-app/src/presenters/FilterPresenter.jsx @@ -252,7 +252,7 @@ const FilterPresenter = observer(({ model }) => { 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; @@ -297,6 +297,52 @@ const FilterPresenter = observer(({ model }) => { localFilteredCourses = [...bestCourses, ...worstCourses]; } + + function updateNoNullcourses(){ + let local = [...localFilteredCourses]; + + console.log("miauuuuu:",local.length); + + if(model.filterOptions.applyTranscriptFilter){ + local = local.filter(function(course){ + return (course?.prerequisites && (course.prerequisites !== "null")); + }) + } + console.log("miauuuuu:",local.length); + if(model.filterOptions.applyLevelFilter){ + local = local.filter(function(course){ + return (course?.prerequisites && (course.prerequisites !== "null")); + }) + } + 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")); + }) + } + 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")); + }) + } + console.log("miauuuuu:",local.length); + if(model.filterOptions.applyDepartmentFilter){ + local = local.filter(function(course){ + return ((course?.deparment) && (course?.department !== "null")); + }) + } + console.log("miauuuuu:",local.length); + + localFilteredCourses = [...local]; + } + async function run() { if (model.courses.length == 0) { return; @@ -304,6 +350,9 @@ const FilterPresenter = observer(({ model }) => { if (model.filtersChange) { localFilteredCourses = [...model.courses]; + if (model.filterOptions.applyRemoveNullCourses) { + updateNoNullcourses(); + } if (model.filterOptions.applyLocationFilter) { //after deo finishes locations, until then dont @@ -319,37 +368,18 @@ const FilterPresenter = observer(({ model }) => { if (model.filterOptions.applyCreditsFilter) { updateCredits(); } - if (model.filtersChange) { - localFilteredCourses = [...model.courses]; - - 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); + 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); } } diff --git a/my-app/src/views/ListView.jsx b/my-app/src/views/ListView.jsx index 8a09b640..9b565ddb 100644 --- a/my-app/src/views/ListView.jsx +++ b/my-app/src/views/ListView.jsx @@ -6,7 +6,7 @@ import InfiniteScroll from 'react-infinite-scroll-component'; var startupFlag = true; 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({}); From 170e1b48c8992062befa6d7c247b89f09fccf5e4 Mon Sep 17 00:00:00 2001 From: benedekboldizsar Date: Wed, 16 Apr 2025 15:38:08 +0200 Subject: [PATCH 7/7] merging into brain? --- my-app/src/views/ListView.jsx | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/my-app/src/views/ListView.jsx b/my-app/src/views/ListView.jsx index 9b565ddb..211a27f2 100644 --- a/my-app/src/views/ListView.jsx +++ b/my-app/src/views/ListView.jsx @@ -3,8 +3,6 @@ import { DotPulse, Quantum } from 'ldrs/react'; import 'ldrs/react/Quantum.css'; import InfiniteScroll from 'react-infinite-scroll-component'; -var startupFlag = true; - function ListView(props) { const coursesToDisplay = props.searchResults; const [displayedCourses, setDisplayedCourses] = useState([]); @@ -42,15 +40,25 @@ function ListView(props) { setHasMore(displayedCourses.length + nextItems.length < coursesToDisplay.length); }, [displayedCourses.length, coursesToDisplay, hasMore]); - if (!props.courses) { - return ( -
-
- ⚠️ No course data available. -
-
- ); - } + const [isRestoringScroll, setIsRestoringScroll] = useState(false); + useEffect(() => { + if (props.targetScroll > 0 && !isRestoringScroll) { + setIsRestoringScroll(true); + props.persistantScrolling(fetchMoreCourses, hasMore); + setIsRestoringScroll(false); + } + }, [props.targetScroll, hasMore, displayedCourses.length]); + + if (!props.courses) { + return ( +
+
+ ⚠️ No course data available. +
+
+ ); + } + return (
{isLoading ? (