Skip to content

Commit 9f47078

Browse files
Responsive filtering good filters merge 2 (#100)
* 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 * wrote departments filter option * added check to make sure to not recommend courses the client has taken before * initial state good * departments go to model * trying to add filtering out courses with NULL fields as an implementable filter option, merging with main start as per teams request * merging into brain? * some ?. properties check, because skill issue * more course?. things * finished the noNull feature, essentially fixed typos * null course checkbox * null check linked * Null field toggle works * nice and beutiful * removed the explicit null string checks, hopefully doesnt break, also wrote logic for Period filtering * period filter * a bit polishing, touching on the period presenter since i thought its broken, but it was the database dropping all course.period data >:( * fixed some filters logic (level filter, period filter), added descriptions to most filters tooltips, fixed About us button, touched Tab title to current working title, fixed some other things * visually persistent filters * now fixed * once again --------- Co-authored-by: benedekboldizsar <bb.boldizsarbenedek@gmail.com>
1 parent cfd6990 commit 9f47078

21 files changed

Lines changed: 948 additions & 673 deletions

my-app/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
<link rel="preconnect" href="https://fonts.googleapis.com">
99
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
1010
<link href="https://fonts.googleapis.com/css2?family=Kanit:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
11-
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Find my course</title>
11+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
12+
<title>Course Compass</title>
1213
</head>
1314
<div id="root"></div>
1415
<script type="module" src="/src/index.jsx"></script>

my-app/src/assets/project_icon.png

-34.2 KB
Loading
32.9 KB
Loading

my-app/src/model.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,27 @@ export const model = {
55
user: undefined,
66
//add searchChange: false, //this is for reworking the searchbar presenter, so that it triggers as a model,
77
//instead of passing searchcouses lambda function down into the searchbarview.
8+
/* courses returned from SearchbarPresenter (search is applied on top of filteredCourses[]) to be shown in the ListView */
89
currentSearch: [],
10+
/* current query text */
911
currentSearchText: "",
1012
scrollPosition: 0,
13+
/* list of all course objects downloaded from the Firebase realtime database and stored locally as JSON object in this array */
1114
courses: [],
15+
/* courses the user selected as their favourite */
1216
favourites: [],
1317
isReady: false,
14-
filtersChange: false,
18+
/* this is a boolean flag showing that filtering options in the UI have changed, triggering the FilterPresenter to recalculate the filteredCourses[] */
19+
filtersChange: false,
20+
/* this is a flag showing if the filteredCourses[] has changed (since FilterPresenter recalculated it), so now SearchBarPresenter needs to
21+
recalculate currentSearch[] depending this updated list of courses */
1522
filtersCalculated: false,
16-
filteredCourses: [],
23+
/* this is the array that FilterPresenter fills up with course objects, filtered from the model.courses[] */
24+
filteredCourses: [],
25+
/* JSON object containing all important parameters the FilterPresenter needs to calculate the filtered list of courses */
1726
filterOptions: {
27+
//apply-X-Filter boolean triggering flag wether corresponding filtering functions should run or not
28+
//different arrays require different data, some uses string arrays, some boolean values, and so on
1829
applyTranscriptFilter: true,
1930
eligibility: "weak", //the possible values for the string are: "weak"/"moderate"/"strong"
2031
applyLevelFilter: true,
@@ -31,7 +42,9 @@ export const model = {
3142
"ITM/Learning in Engineering Sciences", "ITM/Industrial Economics and Management", "ITM/Energy Systems", "ITM/Integrated Product Development and Design", "ITM/SKD GRU",
3243
"SCI/Mathematics", "SCI/Applied Physics", "SCI/Mechanics", "SCI/Aeronautical and Vehicle Engineering",
3344
"ABE/Sustainability and Environmental Engineering", "ABE/Concrete Structures", "ABE/Structural Design & Bridges", "ABE/History of Science, Technology and Environment", ],
34-
applyRemoveNullCourses: false
45+
applyRemoveNullCourses: false,
46+
period: [true, true, true, true],
47+
applyPeriodFilter: true
3548
},
3649

3750
setUser(user) {
@@ -150,6 +163,11 @@ export const model = {
150163
this.setFiltersChange();
151164
},
152165

166+
setApplyRemoveNullCourses() {
167+
this.filterOptions.applyRemoveNullCourses = !this.filterOptions.applyRemoveNullCourses;
168+
this.setFiltersChange();
169+
},
170+
153171
updateLevelFilter(level) {
154172
this.filterOptions.level = level;
155173
},
@@ -172,6 +190,13 @@ export const model = {
172190
this.filterOptions.eligibility = eligibility;
173191
},
174192

193+
updateDepartmentFilter(department) {
194+
this.filterOptions.department = department;
195+
},
196+
197+
updatePeriodFilter(period) {
198+
this.filterOptions.period = period;
199+
},
175200

176201
setApplyTranscriptFilter(transcriptFilterState) {
177202
this.filterOptions.applyTranscriptFilter = transcriptFilterState;
@@ -191,6 +216,9 @@ export const model = {
191216
setApplyDepartmentFilter(departmentFilterState) {
192217
this.filterOptions.applyDepartmentFilter = departmentFilterState;
193218
},
219+
setApplyPeriodFilter(periodfilterState) {
220+
this.filterOptions.applyPeriodFilter = periodfilterState;
221+
},
194222
async getAverageRating(courseCode) {
195223
const reviews = await getReviewsForCourse(courseCode);
196224
if (!reviews || reviews.length === 0) return null;

my-app/src/presenters/FilterPresenter.jsx

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ import { observer } from "mobx-react-lite";
33
import eligibility from "../scripts/eligibility_refined.js";
44
import { SearchbarPresenter } from './SearchbarPresenter.jsx';
55

6+
/* FilterPresenter is responsible for applying the logic necessary to filter out the courses from the overall list */
67
const FilterPresenter = observer(({ model }) => {
8+
/* global variable for the scope of this presenter, all the smaller functions depend on it instead of passing it back and forth as params */
79
var localFilteredCourses = []; //might need to declare out of scope. idk js
810

911

1012
function applyTranscriptEligibility() {
1113
if (localFilteredCourses.length == 0)
1214
return;
13-
/* this elias thing */
15+
16+
/* */
1417
const eligibilitytype = model.filterOptions.eligibility;
1518

1619
let strongcourses = [];
@@ -25,8 +28,6 @@ const FilterPresenter = observer(({ model }) => {
2528

2629

2730
localFilteredCourses.forEach(course => {
28-
//console.log(storedFinishedCourses);
29-
//console.log(course?.prerequisites);
3031
if (storedFinishedCourses.includes(course?.code))
3132
return;
3233
if (course?.prerequisites && (course?.prerequisites !== "null"))
@@ -72,13 +73,51 @@ const FilterPresenter = observer(({ model }) => {
7273
}
7374
default:
7475
{
75-
console.log("Error: somehow we got into a state where model.eligibility is no \"strong\"/\"moderat\"/\"weak\".");
76+
console.log("Error: somehow we got into a state where model.eligibility is no \"strong\"/\"moderate\"/\"weak\".");
7677
localFilteredCourses = [];
7778
break;
7879
}
7980
}
8081

8182

83+
}
84+
85+
function updatePeriods(){
86+
87+
if (localFilteredCourses.length == 0)
88+
return;
89+
90+
const periodArr = [...model.filterOptions.period]; //has 4 boolean values one for each period
91+
// [true, false, false, false] means we are only looking for P1 courses.
92+
let bestcourses = [];
93+
let worstcourses = [];
94+
bestcourses = localFilteredCourses.filter(function (course){
95+
try {
96+
if(course?.periods === undefined)
97+
return false;
98+
if((course?.periods?.P1 == true) && (periodArr[0] == true))
99+
return true;
100+
if((course?.periods?.P2 == true) && (periodArr[1] == true))
101+
return true;
102+
if((course?.periods?.P3 == true) && (periodArr[2] == true))
103+
return true;
104+
if((course?.periods?.P4 == true) && (periodArr[3] == true))
105+
return true;
106+
return false;
107+
} catch (error) {
108+
console.log("for some reason course?.periods is weird: ", course?.periods, error);
109+
return false;
110+
}
111+
112+
})
113+
114+
worstcourses = localFilteredCourses.filter(function (course){
115+
return (course?.periods === undefined);
116+
})
117+
118+
localFilteredCourses = [...bestcourses, ...worstcourses];
119+
120+
82121
}
83122

84123
function updateCredits() {
@@ -117,7 +156,7 @@ const FilterPresenter = observer(({ model }) => {
117156
});
118157
worstCourses = localFilteredCourses.filter(function (course) {
119158
try {
120-
return ((course?.location === undefined) || (course?.location === "null"));
159+
return (course?.location === undefined);
121160
} catch (error) {
122161
console.log("BIG ERROR", error);
123162
return false;
@@ -140,8 +179,8 @@ const FilterPresenter = observer(({ model }) => {
140179
let worstCourses = [];
141180

142181
//in the database a course can have
143-
//course?.language.english (true/false/"null")
144-
//course?.language.swedish (true/false/"null")
182+
//course?.language.english (true/false/undefined)
183+
//course?.language.swedish (true/false/undefined)
145184

146185
//console.log(data);
147186

@@ -166,7 +205,7 @@ const FilterPresenter = observer(({ model }) => {
166205
);
167206
worstCourses = data.filter(function (course) {
168207
try {
169-
return ((course?.language === undefined) || course?.language?.english === "null");
208+
return (course?.language === undefined);
170209
} catch (error) {
171210
console.log(course);
172211
console.log("BIG ERROR");
@@ -191,7 +230,7 @@ const FilterPresenter = observer(({ model }) => {
191230
);
192231
worstCourses = data.filter(function (course) {
193232
try {
194-
return ((course?.language === undefined) || course?.language?.swedish === "null");
233+
return (course?.language === undefined);
195234
} catch (error) {
196235
console.log(course);
197236
console.log("BIG ERROR");
@@ -228,7 +267,7 @@ const FilterPresenter = observer(({ model }) => {
228267
);
229268
worstCourses = data.filter(function (course) {
230269
try {
231-
return ((course?.language === undefined) || course?.language?.english === "null");
270+
return (course?.language === undefined);
232271
} catch (error) {
233272
console.log(course);
234273
console.log("BIG ERROR");
@@ -287,7 +326,7 @@ const FilterPresenter = observer(({ model }) => {
287326
});
288327
worstCourses = localFilteredCourses.filter(function (course) {
289328
try {
290-
return ((course?.department === undefined) || (course?.deparment === "null"));
329+
return (course?.department === undefined);
291330
} catch (error) {
292331
console.log("BIG ERROR", error);
293332
return false;
@@ -301,44 +340,42 @@ const FilterPresenter = observer(({ model }) => {
301340
function updateNoNullcourses(){
302341
let local = [...localFilteredCourses];
303342

304-
console.log("miauuuuu:",local.length);
305343

344+
if(model.filterOptions.applyPeriodFilter){
345+
local = local.filter(function(course){
346+
return (course?.periods && (course?.periods !== "null"));
347+
})
348+
}
306349
if(model.filterOptions.applyTranscriptFilter){
307350
local = local.filter(function(course){
308351
return (course?.prerequisites && (course?.prerequisites !== "null"));
309352
})
310353
}
311-
console.log("miauuuuu:",local.length);
312354
if(model.filterOptions.applyLevelFilter){
313355
local = local.filter(function(course){
314-
return (course?.prerequisites && (course?.prerequisites !== "null"));
356+
return (course?.academicLevel && (course?.academicLevel !== "null"));
315357
})
316358
}
317-
console.log("miauuuuu:",local.length);
318359
if(model.filterOptions.applyLanguageFilter){
319360
local = local.filter(function(course){
320361
return ((course?.language) && ((course?.language?.swedish !== "null") && (course?.language?.english !== "null")));
321362
})
322363
}
323-
console.log("miauuuuu:",local.length);
324-
/*if(model.filterOptions.applyLocationFilter){
364+
if(model.filterOptions.applyLocationFilter){
325365
local = local.filter(function(course){
326366
return ((course?.location) && (course?.location !== "null"));
327367
})
328-
}*/
329-
console.log("miauuuuu:",local.length);
368+
}
330369
if(model.filterOptions.applyCreditsFilter){
331370
local = local.filter(function(course){
332371
return ((course?.credits) && (course?.credits !== "null"));
333372
})
334373
}
335-
console.log("miauuuuu:",local.length);
336374
if(model.filterOptions.applyDepartmentFilter){
337375
local = local.filter(function(course){
338376
return ((course?.department) && (course?.department !== "null"));
339377
})
340378
}
341-
console.log("miauuuuu:",local.length);
342379

343380
localFilteredCourses = [...local];
344381
}
@@ -353,6 +390,9 @@ const FilterPresenter = observer(({ model }) => {
353390
if (model.filterOptions.applyRemoveNullCourses) {
354391
updateNoNullcourses();
355392
}
393+
if(model.filterOptions.applyPeriodFilter){
394+
updatePeriods();
395+
}
356396
if (model.filterOptions.applyLocationFilter) {
357397
//after deo finishes locations, until then dont
358398

@@ -379,7 +419,7 @@ const FilterPresenter = observer(({ model }) => {
379419
model.filteredCourses = [...localFilteredCourses];
380420
model.filtersChange = false;
381421
model.setFiltersCalculated();
382-
console.log("filtered objects number of elements: ", model.filteredCourses.length);
422+
//console.log("filtered objects number of elements: ", model.filteredCourses.length);
383423
}
384424
}
385425

0 commit comments

Comments
 (0)