Skip to content

Commit 6a217b8

Browse files
authored
Locations and Departments (#107)
1 parent f3280dc commit 6a217b8

3 files changed

Lines changed: 81 additions & 51 deletions

File tree

my-app/firebase.js

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { initializeApp } from "firebase/app";
22
import { getAuth, GoogleAuthProvider, onAuthStateChanged } from "firebase/auth";
33
import { get, getDatabase, ref, set, onValue, push } from "firebase/database";
44
import { reaction, toJS } from "mobx";
5-
// import throttle from "lodash.throttle";
65

76
// Your web app's Firebase configuration
87
const firebaseConfig = {
@@ -27,20 +26,20 @@ let noUpload = false;
2726

2827
export function connectToFirebase(model) {
2928
loadCoursesFromCacheOrFirebase(model);
30-
29+
fetchDepartmentsAndLocations(model);
3130
// setting missing
3231
// also save filters to local storage
33-
//
32+
//
3433
const options = JSON.parse(localStorage.getItem("filterOptions"));
35-
if (options) {
36-
model.setFilterOptions(options);
37-
console.log("Restore options from local storage");
38-
}
34+
if (options) {
35+
model.setFilterOptions(options);
36+
console.log("Restore options from local storage");
37+
}
3938

4039
reaction(
41-
() => ({filterOptions: JSON.stringify(model.filterOptions)}),
40+
() => ({ filterOptions: JSON.stringify(model.filterOptions) }),
4241
// eslint-disable-next-line no-unused-vars
43-
({filterOptions}) => {
42+
({ filterOptions }) => {
4443
localStorage.setItem("filterOptions", filterOptions);
4544
}
4645
);
@@ -64,8 +63,8 @@ async function firebaseToModel(model) {
6463
if (!snapshot.exists()) return;
6564
const data = snapshot.val();
6665
noUpload = true;
67-
if (data.favourites) model.setFavourite(data.favourites);
68-
if (data.currentSearchText)
66+
if (data?.favourites) model.setFavourite(data.favourites);
67+
if (data?.currentSearchText)
6968
model.setCurrentSearchText(data.currentSearchText);
7069
// if (data.scrollPosition)
7170
// model.setScrollPosition(data.scrollPosition);
@@ -84,18 +83,15 @@ export function syncModelToFirebase(model) {
8483
// Add more per-user attributes here
8584
}),
8685
// eslint-disable-next-line no-unused-vars
87-
({ userId, favourites, currentSearchText, filterOptions }) => {
86+
({ userId, favourites, currentSearchText }) => {
8887
if (noUpload || !userId) return;
89-
const userRef = ref(db, `users/${userId}`);
88+
const userRef = ref(db, "users/${userId}");
9089
const dataToSync = {
9190
favourites,
9291
currentSearchText,
9392
// filterOptions,
9493
};
95-
96-
set(userRef, dataToSync)
97-
.then(() => console.log("User model synced to Firebase"))
98-
.catch(console.error);
94+
set(userRef, dataToSync).catch(console.error);
9995
}
10096
);
10197
}
@@ -191,6 +187,53 @@ export async function fetchAllCourses() {
191187
return courses;
192188
}
193189

190+
export async function uploadDepartmentsAndLocations(departments, locations) {
191+
if (departments) {
192+
const departmentsRef = ref(db, "departments");
193+
try {
194+
await set(departmentsRef, departments);
195+
console.log("Uploaded Departments");
196+
} catch (error) {
197+
console.error("Failed to upload departments:", error);
198+
return false;
199+
}
200+
}
201+
if (locations) {
202+
const locationsRef = ref(db, "locations");
203+
try {
204+
await set(locationsRef, locations);
205+
console.log("Uploaded Locations");
206+
} catch (error) {
207+
console.error("Failed to upload locations:", error);
208+
return false;
209+
}
210+
}
211+
return true;
212+
}
213+
214+
export async function fetchDepartmentsAndLocations(model) {
215+
const departmentsRef = ref(db, "departments");
216+
const locationsRef = ref(db, "locations");
217+
let snapshot = await get(departmentsRef);
218+
if (snapshot.exists()) {
219+
const value = snapshot.val();
220+
const set = new Set();
221+
for (const id of Object.keys(value)) {
222+
set.add(value[id]);
223+
}
224+
model.setDepartments(Array.from(set));
225+
}
226+
snapshot = await get(locationsRef);
227+
if (snapshot.exists()) {
228+
const value = snapshot.val();
229+
const set = new Set();
230+
for (const id of Object.keys(value)) {
231+
set.add(value[id]);
232+
}
233+
model.setLocations(Array.from(set));
234+
}
235+
}
236+
194237
async function loadCoursesFromCacheOrFirebase(model) {
195238
const firebaseTimestamp = await fetchLastUpdatedTimestamp();
196239
const dbPromise = new Promise((resolve, reject) => {
@@ -241,32 +284,6 @@ async function loadCoursesFromCacheOrFirebase(model) {
241284
const courses = await fetchAllCourses();
242285
model.setCourses(courses);
243286
saveCoursesToCache(courses, firebaseTimestamp);
244-
245-
}
246-
247-
248-
export async function saveJSONCoursesToFirebase(model, data) {
249-
if (!data || !model) {
250-
console.log("no model or data");
251-
return;
252-
}
253-
const entries = Object.entries(data);
254-
entries.forEach((entry) => {
255-
const course = {
256-
code: entry[1].code,
257-
name: entry[1]?.name ?? "",
258-
location: entry[1]?.location ?? "",
259-
department: entry[1]?.department ?? "",
260-
language: entry[1]?.language ?? "",
261-
description: entry[1]?.description ?? "",
262-
academicLevel: entry[1]?.academic_level ?? "",
263-
period: entry[1]?.period ?? "",
264-
credits: entry[1]?.credits ?? 0,
265-
//lectureCount:entry[1].courseLectureCount,
266-
//prerequisites:entry.coursePrerequisites
267-
};
268-
model.addCourse(course);
269-
});
270287
}
271288

272289
export async function addReviewForCourse(courseCode, review) {

my-app/src/model.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addCourse, addReviewForCourse, getReviewsForCourse } from "../firebase";
1+
import { addCourse, addReviewForCourse, getReviewsForCourse, uploadDepartmentsAndLocations } from "../firebase";
22

33

44
export const model = {
@@ -12,7 +12,8 @@ export const model = {
1212
scrollPosition: 0,
1313
/* list of all course objects downloaded from the Firebase realtime database and stored locally as JSON object in this array */
1414
courses: [],
15-
/* courses the user selected as their favourite */
15+
departments : [],
16+
locations: [],
1617
favourites: [],
1718
isReady: false,
1819
/* this is a boolean flag showing that filtering options in the UI have changed, triggering the FilterPresenter to recalculate the filteredCourses[] */
@@ -38,10 +39,6 @@ export const model = {
3839
creditMin: 0,
3940
creditMax: 45,
4041
applyDepartmentFilter: true,
41-
department: ["EECS/Computational Science and Technology", "EECS/Theoretical Computer Science", "EECS/Electric Power and Energy Systems", "EECS/Network and Systems Engineering",
42-
"ITM/Learning in Engineering Sciences", "ITM/Industrial Economics and Management", "ITM/Energy Systems", "ITM/Integrated Product Development and Design", "ITM/SKD GRU",
43-
"SCI/Mathematics", "SCI/Applied Physics", "SCI/Mechanics", "SCI/Aeronautical and Vehicle Engineering",
44-
"ABE/Sustainability and Environmental Engineering", "ABE/Concrete Structures", "ABE/Structural Design & Bridges", "ABE/History of Science, Technology and Environment", ],
4542
applyRemoveNullCourses: false,
4643
period: [true, true, true, true],
4744
applyPeriodFilter: true
@@ -76,6 +73,12 @@ export const model = {
7673
console.error("Error adding course:", error);
7774
}
7875
},
76+
setDepartments(departments){
77+
this.departments = departments;
78+
},
79+
setLocations(locations){
80+
this.locations = locations;
81+
},
7982
setFavourite(favorites){
8083
this.favourites = favorites;
8184
},
@@ -107,6 +110,8 @@ export const model = {
107110
console.log("no model or data");
108111
return;
109112
}
113+
const dep = new Set();
114+
const loc = new Set();
110115
const entries = Object.entries(data);
111116
entries.forEach(entry => {
112117
const course = {
@@ -124,7 +129,13 @@ export const model = {
124129
learning_outcomes: entry[1]?.learning_outcomes ?? null
125130
};
126131
this.addCourse(course);
132+
dep.add(course.department);
133+
loc.add(course.location);
127134
});
135+
this.departments = Array.from(dep);
136+
this.locations = Array.from(loc);
137+
uploadDepartmentsAndLocations(this.departments, this.locations);
138+
128139
},
129140
//for reviews
130141
async addReview(courseCode, review) {
@@ -223,6 +234,8 @@ export const model = {
223234
const reviews = await getReviewsForCourse(courseCode);
224235
if (!reviews || reviews.length === 0) return null;
225236
const total = reviews.reduce((sum, review) => sum + (review.overallRating || 0), 0);
226-
return (total / reviews.length).toFixed(1);
237+
const avgRtg = (total / reviews.length).toFixed(1);
238+
// cache the result
239+
return avgRtg;
227240
},
228241
};

my-app/src/presenters/SearchbarPresenter.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const SearchbarPresenter = observer(({ model }) => {
1818
{ name: 'name', weight: 0.3 },
1919
{ name: 'description', weight: 0.1 },
2020
],
21-
threshold: 0.3, // adjust this for sensitivity
21+
threshold: 0.4, // adjust this for sensitivity
2222
ignoreLocation: true,
2323
minMatchCharLength: 2,
2424
};

0 commit comments

Comments
 (0)