From 94ea336f75b24c818112199a096c5eef7d1d102d Mon Sep 17 00:00:00 2001 From: Justus Kluge Date: Thu, 15 May 2025 16:47:01 +0200 Subject: [PATCH] Making the search persistent again... --- my-app/firebase.js | 14 +- my-app/package-lock.json | 9 - my-app/src/index.jsx | 2 +- my-app/src/model.js | 774 ++++++++++--------- my-app/src/pages/App.jsx | 18 +- my-app/src/presenters/SearchbarPresenter.jsx | 18 +- my-app/src/views/SearchbarView.jsx | 1 - 7 files changed, 425 insertions(+), 411 deletions(-) diff --git a/my-app/firebase.js b/my-app/firebase.js index 012d98d..0eda206 100644 --- a/my-app/firebase.js +++ b/my-app/firebase.js @@ -56,15 +56,20 @@ export async function connectToFirebase(model) { // also save filters to local storage // const options = JSON.parse(localStorage.getItem("filterOptions")); + const search = localStorage.getItem("search"); if (options) { model.setFilterOptions(options); } + if(search){ + model.setCurrentSearchText(search); + } - // automaticaly save filter options to local storage whenever they change + // automaticaly save filter and search to local storage whenever they change reaction( - () => ({ filterOptions: JSON.stringify(model.filterOptions) }), - ({ filterOptions }) => { + () => ({ filterOptions: JSON.stringify(model.filterOptions), search: model.currentSearchText }), + ({ filterOptions, search }) => { localStorage.setItem("filterOptions", filterOptions); + localStorage.setItem("search", search); } ); /** @@ -78,8 +83,10 @@ export async function connectToFirebase(model) { syncScrollPositionToFirebase(model); } else { model.setUser(null); // If no user, clear user-specific data + model.setReady(); } }); + } // fetches all relevant information to create the model @@ -100,6 +107,7 @@ async function firebaseToModel(model) { return currentData; // Return the current data to avoid overwriting }); }); + model.setReady(); } /** diff --git a/my-app/package-lock.json b/my-app/package-lock.json index 360afab..2a49d1f 100644 --- a/my-app/package-lock.json +++ b/my-app/package-lock.json @@ -3869,15 +3869,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001714", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001714.tgz", diff --git a/my-app/src/index.jsx b/my-app/src/index.jsx index 6d8d65a..af40b85 100644 --- a/my-app/src/index.jsx +++ b/my-app/src/index.jsx @@ -44,4 +44,4 @@ createRoot(document.getElementById("root")).render( ); // give user access for debugging purpose -// window.myModel = reactiveModel; +window.myModel = reactiveModel; diff --git a/my-app/src/model.js b/my-app/src/model.js index 1dab325..de3d5d0 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -1,391 +1,397 @@ import { query } from "firebase/database"; -import { addCourse, addReviewForCourse, getReviewsForCourse, uploadDepartmentsAndLocations } from "../firebase"; - +import { + addCourse, + addReviewForCourse, + getReviewsForCourse, + uploadDepartmentsAndLocations, +} from "../firebase"; export const model = { - user: undefined, - //add searchChange: false, //this is for reworking the searchbar presenter, so that it triggers as a model, - //instead of passing searchcouses lambda function down into the searchbarview. - /* courses returned from SearchbarPresenter (search is applied on top of filteredCourses[]) to be shown in the ListView */ - currentSearch: [], - - sidebarIsOpen: true, - /* current query text */ - currentSearchText: "", - scrollPosition: 0, - /* list of all course objects downloaded from the Firebase realtime database and stored locally as JSON object in this array */ - courses: [], - departments: [], - locations: [], - // indexes: 0 -> overall rating; 1 -> difficulty; 2->teacher rating - avgRatings: [], - // model.avgRatings["IK1203"][0] - /* courses the user selected as their favourite */ - favourites: [], - searchHistory: [], - isReady: false, - /* this is a boolean flag showing that filtering options in the UI have changed, triggering the FilterPresenter to recalculate the filteredCourses[] */ - filtersChange: false, - /* this is a flag showing if the filteredCourses[] has changed (since FilterPresenter recalculated it), so now SearchBarPresenter needs to + user: undefined, + //add searchChange: false, //this is for reworking the searchbar presenter, so that it triggers as a model, + //instead of passing searchcouses lambda function down into the searchbarview. + /* courses returned from SearchbarPresenter (search is applied on top of filteredCourses[]) to be shown in the ListView */ + currentSearch: [], + + sidebarIsOpen: true, + /* current query text */ + currentSearchText: "", + scrollPosition: 0, + /* list of all course objects downloaded from the Firebase realtime database and stored locally as JSON object in this array */ + courses: [], + departments: [], + locations: [], + // indexes: 0 -> overall rating; 1 -> difficulty; 2->teacher rating + avgRatings: [], + // model.avgRatings["IK1203"][0] + /* courses the user selected as their favourite */ + favourites: [], + searchHistory: [], + isReady: false, + /* this is a boolean flag showing that filtering options in the UI have changed, triggering the FilterPresenter to recalculate the filteredCourses[] */ + filtersChange: false, + /* this is a flag showing if the filteredCourses[] has changed (since FilterPresenter recalculated it), so now SearchBarPresenter needs to recalculate currentSearch[] depending this updated list of courses */ - filtersCalculated: false, - /* this is the array that FilterPresenter fills up with course objects, filtered from the model.courses[] */ - filteredCourses: [], - /* JSON object containing all important parameters the FilterPresenter needs to calculate the filtered list of courses */ - filterOptions: { - //apply-X-Filter boolean triggering flag wether corresponding filtering functions should run or not - //different arrays require different data, some uses string arrays, some boolean values, and so on - applyTranscriptFilter: false, - eligibility: "weak", //the possible values for the string are: "weak"/"moderate"/"strong" - applyLevelFilter: false, - level: ["PREPARATORY", "BASIC", "ADVANCED", "RESEARCH"], //the possible values for the array are: "PREPARATORY", "BASIC", "ADVANCED", "RESEARCH" - applyLanguageFilter: false, - language: "none", //the possible values for the string are: "none"/"english"/"swedish"/"both" - applyLocationFilter: false, - location: [], //the possible values for the array are: 'KTH Campus', 'KTH Kista', 'AlbaNova', 'KTH Flemingsberg', 'KTH Solna', 'KTH Södertälje', 'Handelshögskolan', 'KI Solna', 'Stockholms universitet', 'KONSTFACK' - applyCreditsFilter: false, - creditMin: 0, - creditMax: 45, - applyDepartmentFilter: false, - department: [], - applyRemoveNullCourses: false, - period: [true, true, true, true], - applyPeriodFilter: false, - }, - isPopupOpen: false, - selectedCourse: null, - searchQueryModel: "", - - _coursesListeners: [], // internal list of listeners - - onCoursesSet(callback) { - this._coursesListeners.push(callback); - }, - - _coursesListeners: [], // internal list of listeners - urlStackPointer: 0, - - onCoursesSet(callback) { - this._coursesListeners.push(callback); - }, - - setUser(user) { - if (!this.user) - this.user = user; - }, - - setCurrentSearch(searchResults) { - this.currentSearch = searchResults; - }, - - setCurrentSearchText(text) { - this.currentSearchText = text; - }, - - setScrollPosition(position) { - this.scrollPosition = position; - }, - - setCourses(courses) { - this.courses = courses; - this._coursesListeners.forEach(cb => cb(courses)); - }, - - async addCourse(course) { - try { - await addCourse(course); - this.courses = [...this.courses, course]; - } catch (error) { - console.error("Error adding course:", error); - } - }, - addHistoryItem(course_id) { - try { - this.searchHistory = [...this.searchHistory, course_id]; - } catch (error) { - console.error("Error adding course code to the history:", error); - } - }, - setDepartments(departments) { - this.departments = departments; - }, - setLocations(locations) { - this.locations = locations; - }, - setAverageRatings(ratings) { - this.avgRatings = ratings; - }, - updateAverageRating(courseCode, rating) { - if (this.avgRatings != null) - this.avgRatings[courseCode] = rating; - }, - setFavourite(favorites) { - this.favourites = favorites; - }, - - addFavourite(course) { - this.favourites = [...this.favourites, course]; - }, - - removeFavourite(course) { - this.favourites = (this.favourites || []).filter(fav => fav.code !== course.code); - }, - - getCourse(courseID) { - return this.courses.find(course => course.code === courseID); - }, - - getCourseNames(courseID_array) { - let return_obj = {}; - for (let course of this.courses) { - if (courseID_array.includes(course.code)) { - return_obj[course.code] = course.name; - } - } - return return_obj; - }, - - populateDatabase(data) { - if (!data || !this) { - console.log("no model or data"); - return; - } - const dep = new Set(); - const loc = new Set(); - const entries = Object.entries(data); - entries.forEach(entry => { - const course = { - code: entry[1].code, - name: entry[1]?.name ?? null, - location: entry[1]?.location ?? null, - department: entry[1]?.department ?? null, - language: entry[1]?.language ?? null, - description: entry[1]?.description ?? null, - academicLevel: entry[1]?.academic_level ?? null, - periods: entry[1]?.periods ?? null, - credits: entry[1]?.credits ?? 0, - prerequisites: entry[1]?.prerequisites ?? null, - prerequisites_text: entry[1]?.prerequisites_text ?? null, - learning_outcomes: entry[1]?.learning_outcomes ?? null - }; - this.addCourse(course); - dep.add(course.department); - loc.add(course.location); - }); - this.departments = Array.from(dep); - this.locations = Array.from(loc); - uploadDepartmentsAndLocations(this.departments, this.locations); - - }, - //for reviews - async addReview(courseCode, review) { - try { - await addReviewForCourse(courseCode, review); - return true; - } catch (error) { - console.error("Error adding review:", error); - return false; - } - }, - - async getReviews(courseCode) { - try { - return await getReviewsForCourse(courseCode); - } catch (error) { - console.error("Error fetching reviews:", error); - return []; - } - }, - //for filters - - setFiltersChange() { - this.filtersChange = true; - }, - - setFiltersCalculated() { - this.filtersCalculated = true; - }, - - setFilterOptions(options) { - this.filterOptions = options; // do we want to set the flags? What about useEffect? - }, - - setApplyRemoveNullCourses() { - this.filterOptions.applyRemoveNullCourses = !this.filterOptions.applyRemoveNullCourses; - this.setFiltersChange(); - }, - - setApplyRemoveNullCourses() { - this.filterOptions.applyRemoveNullCourses = !this.filterOptions.applyRemoveNullCourses; - this.setFiltersChange(); - }, - - updateLevelFilter(level) { - this.filterOptions.level = level; - }, - - updateDepartmentFilter(department) { - this.filterOptions.department = department; - }, - - updateLanguageFilter(languages) { - this.filterOptions.language = languages; - }, - updateLocationFilter(location) { - this.filterOptions.location = location; - }, - updateCreditsFilter(creditLimits) { - this.filterOptions.creditMin = creditLimits[0]; - this.filterOptions.creditMax = creditLimits[1]; - }, - updateTranscriptElegibilityFilter(eligibility) { - this.filterOptions.eligibility = eligibility; - }, - - updateDepartmentFilter(department) { - this.filterOptions.department = department; - }, - - updatePeriodFilter(period) { - this.filterOptions.period = period; - }, - - setApplyTranscriptFilter(transcriptFilterState) { - this.filterOptions.applyTranscriptFilter = transcriptFilterState; - }, - setApplyLevelFilter(levelFilterState) { - this.filterOptions.applyLevelFilter = levelFilterState; - }, - setApplyLanguageFilter(languageFilterState) { - this.filterOptions.applyLanguageFilter = languageFilterState; - }, - setApplyLocationFilter(locationFilterState) { - this.filterOptions.applyLocationFilter = locationFilterState; - }, - setApplyCreditsFilter(creditsFilterState) { - this.filterOptions.applyCreditsFilter = creditsFilterState; - }, - setApplyDepartmentFilter(departmentFilterState) { - this.filterOptions.applyDepartmentFilter = departmentFilterState; - }, - setApplyPeriodFilter(periodfilterState) { - this.filterOptions.applyPeriodFilter = periodfilterState; - }, - //for better display we would like the departments in a structured format based on school - formatDepartments() { - const grouped = this?.departments.reduce((acc, item) => { - const [school, department] = item.split("/"); - if (!acc[school]) { - acc[school] = []; - } - acc[school].push(department?.trim()); - return acc; - }, {}); - const sortedGrouped = Object.keys(grouped) - .sort() - .reduce((acc, key) => { - acc[key] = grouped[key].sort(); - return acc; - }, {}); - const fields = Object.entries(sortedGrouped).map(([school, departments], index) => ({ - id: index + 1, - label: school, - subItems: departments, - })); - return fields; - }, - async getAverageRating(courseCode, option) { - const reviews = await getReviewsForCourse(courseCode); - if (!reviews || reviews.length === 0) return null; - - let validReviews = 0; - let total = 0; - - switch (option) { - case "avg": - reviews.forEach(review => { - if (typeof review.overallRating === 'number') { - total += review.overallRating; - validReviews++; - } - }); - break; - case "diff": - reviews.forEach(review => { - if (typeof review.difficultyRating === 'number') { - total += review.difficultyRating; - validReviews++; - } - }); - break; - case "prof": - reviews.forEach(review => { - if (typeof review.professorRating === 'number') { - total += review.professorRating; - validReviews++; - } - }); - break; - default: - return null; - } - - if (validReviews === 0) return null; - return (total / validReviews).toFixed(1); - }, - - setPopupOpen(isOpen) { - if (!isOpen) { - let current_url = window.location.href; - let end_index = indexOfNth(current_url, '/', 3); - if (end_index + 1 != current_url.length) { - window.history.back(); - } - } - - this.isPopupOpen = isOpen; - }, - - setSelectedCourse(course) { - this.selectedCourse = course; - }, - - - toggleSidebarIsOpen() { - this.sidebarIsOpen = !this.sidebarIsOpen; - }, - - handleUrlChange() { - let current_url = window.location.href; - - let start_idx = indexOfNth(current_url, '/', 3) + 2; - - if (start_idx > 0 && start_idx < current_url.length) { - - let course_code = current_url.slice(start_idx); - let course = this.getCourse(course_code); - if (course) { - this.setSelectedCourse(course); - this.setPopupOpen(true); - } - this.urlStackPointer++; - } else if (start_idx > 0) { - this.setPopupOpen(false); - } - } - + filtersCalculated: false, + /* this is the array that FilterPresenter fills up with course objects, filtered from the model.courses[] */ + filteredCourses: [], + /* JSON object containing all important parameters the FilterPresenter needs to calculate the filtered list of courses */ + filterOptions: { + //apply-X-Filter boolean triggering flag wether corresponding filtering functions should run or not + //different arrays require different data, some uses string arrays, some boolean values, and so on + applyTranscriptFilter: false, + eligibility: "weak", //the possible values for the string are: "weak"/"moderate"/"strong" + applyLevelFilter: false, + level: ["PREPARATORY", "BASIC", "ADVANCED", "RESEARCH"], //the possible values for the array are: "PREPARATORY", "BASIC", "ADVANCED", "RESEARCH" + applyLanguageFilter: false, + language: "none", //the possible values for the string are: "none"/"english"/"swedish"/"both" + applyLocationFilter: false, + location: [], //the possible values for the array are: 'KTH Campus', 'KTH Kista', 'AlbaNova', 'KTH Flemingsberg', 'KTH Solna', 'KTH Södertälje', 'Handelshögskolan', 'KI Solna', 'Stockholms universitet', 'KONSTFACK' + applyCreditsFilter: false, + creditMin: 0, + creditMax: 45, + applyDepartmentFilter: false, + department: [], + applyRemoveNullCourses: false, + period: [true, true, true, true], + applyPeriodFilter: false, + }, + isPopupOpen: false, + selectedCourse: null, + searchQueryModel: "", + isReady: false, + _coursesListeners: [], // internal list of listeners + + setReady() { + this.isReady = true; + }, + onCoursesSet(callback) { + this._coursesListeners.push(callback); + }, + + _coursesListeners: [], // internal list of listeners + urlStackPointer: 0, + + onCoursesSet(callback) { + this._coursesListeners.push(callback); + }, + + setUser(user) { + if (!this.user) this.user = user; + }, + + setCurrentSearch(searchResults) { + this.currentSearch = searchResults; + }, + + setCurrentSearchText(text) { + this.currentSearchText = text; + }, + + setScrollPosition(position) { + this.scrollPosition = position; + }, + + setCourses(courses) { + this.courses = courses; + this._coursesListeners.forEach((cb) => cb(courses)); + }, + + async addCourse(course) { + try { + await addCourse(course); + this.courses = [...this.courses, course]; + } catch (error) { + console.error("Error adding course:", error); + } + }, + addHistoryItem(course_id) { + try { + this.searchHistory = [...this.searchHistory, course_id]; + } catch (error) { + console.error("Error adding course code to the history:", error); + } + }, + setDepartments(departments) { + this.departments = departments; + }, + setLocations(locations) { + this.locations = locations; + }, + setAverageRatings(ratings) { + this.avgRatings = ratings; + }, + updateAverageRating(courseCode, rating) { + if (this.avgRatings != null) this.avgRatings[courseCode] = rating; + }, + setFavourite(favorites) { + this.favourites = favorites; + }, + + addFavourite(course) { + this.favourites = [...this.favourites, course]; + }, + + removeFavourite(course) { + this.favourites = (this.favourites || []).filter( + (fav) => fav.code !== course.code + ); + }, + + getCourse(courseID) { + return this.courses.find((course) => course.code === courseID); + }, + + getCourseNames(courseID_array) { + let return_obj = {}; + for (let course of this.courses) { + if (courseID_array.includes(course.code)) { + return_obj[course.code] = course.name; + } + } + return return_obj; + }, + + populateDatabase(data) { + if (!data || !this) { + console.log("no model or data"); + return; + } + const dep = new Set(); + const loc = new Set(); + const entries = Object.entries(data); + entries.forEach((entry) => { + const course = { + code: entry[1].code, + name: entry[1]?.name ?? null, + location: entry[1]?.location ?? null, + department: entry[1]?.department ?? null, + language: entry[1]?.language ?? null, + description: entry[1]?.description ?? null, + academicLevel: entry[1]?.academic_level ?? null, + periods: entry[1]?.periods ?? null, + credits: entry[1]?.credits ?? 0, + prerequisites: entry[1]?.prerequisites ?? null, + prerequisites_text: entry[1]?.prerequisites_text ?? null, + learning_outcomes: entry[1]?.learning_outcomes ?? null, + }; + this.addCourse(course); + dep.add(course.department); + loc.add(course.location); + }); + this.departments = Array.from(dep); + this.locations = Array.from(loc); + uploadDepartmentsAndLocations(this.departments, this.locations); + }, + //for reviews + async addReview(courseCode, review) { + try { + await addReviewForCourse(courseCode, review); + return true; + } catch (error) { + console.error("Error adding review:", error); + return false; + } + }, + + async getReviews(courseCode) { + try { + return await getReviewsForCourse(courseCode); + } catch (error) { + console.error("Error fetching reviews:", error); + return []; + } + }, + //for filters + + setFiltersChange() { + this.filtersChange = true; + }, + + setFiltersCalculated() { + this.filtersCalculated = true; + }, + + setFilterOptions(options) { + this.filterOptions = options; // do we want to set the flags? What about useEffect? + }, + + setApplyRemoveNullCourses() { + this.filterOptions.applyRemoveNullCourses = !this.filterOptions + .applyRemoveNullCourses; + this.setFiltersChange(); + }, + + setApplyRemoveNullCourses() { + this.filterOptions.applyRemoveNullCourses = !this.filterOptions + .applyRemoveNullCourses; + this.setFiltersChange(); + }, + + updateLevelFilter(level) { + this.filterOptions.level = level; + }, + + updateDepartmentFilter(department) { + this.filterOptions.department = department; + }, + + updateLanguageFilter(languages) { + this.filterOptions.language = languages; + }, + updateLocationFilter(location) { + this.filterOptions.location = location; + }, + updateCreditsFilter(creditLimits) { + this.filterOptions.creditMin = creditLimits[0]; + this.filterOptions.creditMax = creditLimits[1]; + }, + updateTranscriptElegibilityFilter(eligibility) { + this.filterOptions.eligibility = eligibility; + }, + + updateDepartmentFilter(department) { + this.filterOptions.department = department; + }, + + updatePeriodFilter(period) { + this.filterOptions.period = period; + }, + + setApplyTranscriptFilter(transcriptFilterState) { + this.filterOptions.applyTranscriptFilter = transcriptFilterState; + }, + setApplyLevelFilter(levelFilterState) { + this.filterOptions.applyLevelFilter = levelFilterState; + }, + setApplyLanguageFilter(languageFilterState) { + this.filterOptions.applyLanguageFilter = languageFilterState; + }, + setApplyLocationFilter(locationFilterState) { + this.filterOptions.applyLocationFilter = locationFilterState; + }, + setApplyCreditsFilter(creditsFilterState) { + this.filterOptions.applyCreditsFilter = creditsFilterState; + }, + setApplyDepartmentFilter(departmentFilterState) { + this.filterOptions.applyDepartmentFilter = departmentFilterState; + }, + setApplyPeriodFilter(periodfilterState) { + this.filterOptions.applyPeriodFilter = periodfilterState; + }, + //for better display we would like the departments in a structured format based on school + formatDepartments() { + const grouped = this?.departments.reduce((acc, item) => { + const [school, department] = item.split("/"); + if (!acc[school]) { + acc[school] = []; + } + acc[school].push(department?.trim()); + return acc; + }, {}); + const sortedGrouped = Object.keys(grouped) + .sort() + .reduce((acc, key) => { + acc[key] = grouped[key].sort(); + return acc; + }, {}); + const fields = Object.entries(sortedGrouped).map( + ([school, departments], index) => ({ + id: index + 1, + label: school, + subItems: departments, + }) + ); + return fields; + }, + async getAverageRating(courseCode, option) { + const reviews = await getReviewsForCourse(courseCode); + if (!reviews || reviews.length === 0) return null; + + let validReviews = 0; + let total = 0; + + switch (option) { + case "avg": + reviews.forEach((review) => { + if (typeof review.overallRating === "number") { + total += review.overallRating; + validReviews++; + } + }); + break; + case "diff": + reviews.forEach((review) => { + if (typeof review.difficultyRating === "number") { + total += review.difficultyRating; + validReviews++; + } + }); + break; + case "prof": + reviews.forEach((review) => { + if (typeof review.professorRating === "number") { + total += review.professorRating; + validReviews++; + } + }); + break; + default: + return null; + } + + if (validReviews === 0) return null; + return (total / validReviews).toFixed(1); + }, + + setPopupOpen(isOpen) { + if (!isOpen) { + let current_url = window.location.href; + let end_index = indexOfNth(current_url, "/", 3); + if (end_index + 1 != current_url.length) { + window.history.back(); + } + } + + this.isPopupOpen = isOpen; + }, + + setSelectedCourse(course) { + this.selectedCourse = course; + }, + + toggleSidebarIsOpen() { + this.sidebarIsOpen = !this.sidebarIsOpen; + }, + + handleUrlChange() { + let current_url = window.location.href; + + let start_idx = indexOfNth(current_url, "/", 3) + 2; + + if (start_idx > 0 && start_idx < current_url.length) { + let course_code = current_url.slice(start_idx); + let course = this.getCourse(course_code); + if (course) { + this.setSelectedCourse(course); + this.setPopupOpen(true); + } + this.urlStackPointer++; + } else if (start_idx > 0) { + this.setPopupOpen(false); + } + }, }; - function indexOfNth(string, char, n) { - let count = 0; - for (let i = 0; i < string.length; i++) { - if (string[i] == char) { - count++; - } - if (count == n) { - return i; - } - } - return -1; -} \ No newline at end of file + let count = 0; + for (let i = 0; i < string.length; i++) { + if (string[i] == char) { + count++; + } + if (count == n) { + return i; + } + } + return -1; +} diff --git a/my-app/src/pages/App.jsx b/my-app/src/pages/App.jsx index 0799e06..457112e 100644 --- a/my-app/src/pages/App.jsx +++ b/my-app/src/pages/App.jsx @@ -15,17 +15,17 @@ import { slide as Menu } from "react-burger-menu"; function App({ model }) { const [sidebarIsOpen, setSidebarIsOpen] = useState(model.sidebarIsOpen); - useEffect(() => { - const clearStorageOnUnload = () => { - localStorage.clear(); - }; + // useEffect(() => { + // const clearStorageOnUnload = () => { + // localStorage.clear(); + // }; - window.addEventListener("unload", clearStorageOnUnload); + // window.addEventListener("unload", clearStorageOnUnload); - return () => { - window.removeEventListener("unload", clearStorageOnUnload); - }; - }, []); + // return () => { + // window.removeEventListener("unload", clearStorageOnUnload); + // }; + // }, []); return ( /* The sidebar styling(under the menu)*/ diff --git a/my-app/src/presenters/SearchbarPresenter.jsx b/my-app/src/presenters/SearchbarPresenter.jsx index 175660e..ebe76d6 100644 --- a/my-app/src/presenters/SearchbarPresenter.jsx +++ b/my-app/src/presenters/SearchbarPresenter.jsx @@ -4,13 +4,13 @@ import { useState } from 'react'; import SearchbarView from "../views/SearchbarView.jsx"; import Fuse from 'fuse.js' import debounce from 'lodash.debounce'; +import { useEffect } from 'react'; /** * This presenter handles searches. The searching is done via a debounced fuzzy search engine called "fuse.js". * Favourites are handled here as well. */ const SearchbarPresenter = observer(({ model }) => { - const [searchQuery, setSearchQuery] = useState(""); // the search uses fuse.js const fuseOptions = useMemo(() => ({ @@ -55,6 +55,16 @@ const SearchbarPresenter = observer(({ model }) => { model.addFavourite(course); }; + const setCurrentSearchText = (text) =>{ + model.setCurrentSearchText(text); + searchCourses(text); + } + + useEffect(() => { + searchCourses(model.currentSearchText); + console.log("Current Search is:"+model.currentSearchText); + }, [model.isReady]) + const removeFavourite = (course) => { model.removeFavourite(course); }; @@ -80,7 +90,7 @@ const SearchbarPresenter = observer(({ model }) => { } if(model.filtersCalculated){ - searchCourses(searchQuery); + searchCourses(model.currentSearchText); model.filtersCalculated = false; } @@ -94,8 +104,8 @@ const SearchbarPresenter = observer(({ model }) => { isPopupOpen={model.isPopupOpen} setIsPopupOpen={(isOpen) => model.setPopupOpen(isOpen)} setSelectedCourse={(course) => model.setSelectedCourse(course)} - setSearchQuery={setSearchQuery} - searchQuery={searchQuery} + setSearchQuery={setCurrentSearchText} + searchQuery={model.currentSearchText} handleFavouriteClick={handleFavouriteClick} totalCredits={creditsSum(model.favourites)} resetScrollPosition={resetScoll} diff --git a/my-app/src/views/SearchbarView.jsx b/my-app/src/views/SearchbarView.jsx index adeb5f4..c66c14e 100644 --- a/my-app/src/views/SearchbarView.jsx +++ b/my-app/src/views/SearchbarView.jsx @@ -25,7 +25,6 @@ export function SearchbarView(props) { const handleSearch = (query) => { props.resetScrollPosition(); props.setSearchQuery(query); - props.searchCourses(query); }; const handleSignIn = async () => {