Skip to content

Commit 6e68412

Browse files
committed
Bug fixes ++
2 parents f073dd0 + 7182c13 commit 6e68412

12 files changed

Lines changed: 435 additions & 175 deletions
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Deploy to Firebase Hosting on merge
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
build_and_deploy:
10+
runs-on: ubuntu-latest
11+
defaults:
12+
run:
13+
working-directory: my-app
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Install dependencies
19+
run: npm ci
20+
21+
- name: Build the app
22+
run: npm run build
23+
24+
- name: Deploy to Firebase Hosting
25+
uses: FirebaseExtended/action-hosting-deploy@v0
26+
with:
27+
repoToken: ${{ secrets.GITHUB_TOKEN }}
28+
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_FINDMYNEXTCOURSE }}
29+
channelId: live
30+
projectId: findmynextcourse
31+
entryPoint: my-app
32+
env:
33+
FIREBASE_CLI_PREVIEWS: hostingchannels
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This file was auto-generated by the Firebase CLI
2+
# https://github.com/firebase/firebase-tools
3+
4+
name: Deploy to Firebase Hosting on PR
5+
on: pull_request
6+
permissions:
7+
checks: write
8+
contents: read
9+
pull-requests: write
10+
jobs:
11+
build_and_preview:
12+
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- run: npm ci && npm run build
17+
- uses: FirebaseExtended/action-hosting-deploy@v0
18+
with:
19+
repoToken: ${{ secrets.GITHUB_TOKEN }}
20+
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_FINDMYNEXTCOURSE }}
21+
projectId: findmynextcourse

my-app/package-lock.json

Lines changed: 63 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

my-app/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
"@xyflow/react": "^12.5.5",
1818
"autoprefixer": "^10.4.21",
1919
"firebase": "^11.5.0",
20+
"fuse.js": "^7.1.0",
2021
"ldrs": "^1.1.6",
22+
"lodash.debounce": "^4.0.8",
2123
"lodash.throttle": "^4.1.1",
2224
"mobx": "^6.13.7",
2325
"mobx-react-lite": "^4.1.0",

my-app/src/presenters/ListViewPresenter.jsx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,35 @@ const ListViewPresenter = observer(({ model }) => {
7676

7777
const [isPopupOpen, setIsPopupOpen] = useState(false);
7878
const [selectedCourse, setSelectedCourse] = useState(null);
79+
const [sortBy, setSortBy] = useState('relevance');
80+
const [sortDirection, setSortDirection] = useState('desc');
81+
const [sortedCourses, setSortedCourses] = useState([]);
82+
83+
const sortCourses = (courses, sortType) => {
84+
if (!courses) return [];
85+
86+
const sortedCourses = [...courses];
87+
const direction = sortDirection === 'asc' ? 1 : -1;
88+
89+
switch (sortType) {
90+
case 'name':
91+
return sortedCourses.sort((a, b) =>
92+
direction * a.name.localeCompare(b.name));
93+
case 'credits':
94+
return sortedCourses.sort((a, b) =>
95+
direction * (parseFloat(a.credits) - parseFloat(b.credits)));
96+
case 'relevance':
97+
return direction === -1 ? sortedCourses : sortedCourses.reverse();
98+
default:
99+
return direction === 1 ? sortedCourses : sortedCourses.reverse();
100+
}
101+
};
102+
103+
useEffect(() => {
104+
const sorted = sortCourses(model.currentSearch, sortBy);
105+
setSortedCourses(sorted);
106+
}, [model.currentSearch, sortBy, sortDirection]);
107+
79108
const preP = <PrerequisitePresenter
80109
model={model}
81110
isPopupOpen={isPopupOpen}
@@ -98,9 +127,9 @@ const ListViewPresenter = observer(({ model }) => {
98127

99128

100129
return <ListView
101-
courses={model.courses}
102-
searchResults={model.currentSearch}
103-
currentSearchLenght={model.currentSearch.length}
130+
// courses={model.courses}
131+
// searchResults={model.currentSearch}
132+
// currentSearchLenght={model.currentSearch.length}
104133

105134
favouriteCourses={model.favourites}
106135
addFavourite={addFavourite}
@@ -117,6 +146,12 @@ const ListViewPresenter = observer(({ model }) => {
117146
scrollContainerRef={scrollContainerRef}
118147
persistantScrolling={persistantScrolling}
119148

149+
sortedCourses={sortedCourses}
150+
sortBy={sortBy}
151+
setSortBy={setSortBy}
152+
sortDirection={sortDirection}
153+
setSortDirection={setSortDirection}
154+
currentSearchLenght={sortedCourses.length}
120155
/>;
121156
});
122157

my-app/src/presenters/SearchbarPresenter.jsx

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,39 @@
1-
import React, { useEffect } from 'react';
1+
import React, { useEffect, useCallback } from 'react';
22
import { observer } from "mobx-react-lite";
33
import { useState } from 'react';
44
import CoursePagePopup from '../views/Components/CoursePagePopup.jsx';
55
import PrerequisitePresenter from './PrerequisitePresenter.jsx';
66
import { ReviewPresenter } from "../presenters/ReviewPresenter.jsx";
77
import SearchbarView from "../views/SearchbarView.jsx";
8+
import Fuse from 'fuse.js'
9+
import debounce from 'lodash.debounce';
810

911
const SearchbarPresenter = observer(({ model }) => {
1012

11-
const searchCourses = (query) => {
12-
//model.filteredCourses is essentially a smaller subset of model.courses, if theres no filters, it should be the same
13-
console.log("---------------search recalculated");
14-
console.log("filtered courses length: ", model.filteredCourses.length);
15-
const searchResults = model.filteredCourses.filter(course =>
16-
course.code.toLowerCase().includes(query.toLowerCase()) ||
17-
course.name.toLowerCase().includes(query.toLowerCase()) ||
18-
course.description?.toLowerCase().includes(query.toLowerCase())
19-
);
20-
model.setCurrentSearchText(query);
21-
model.setCurrentSearch(searchResults);
22-
console.log(model.currentSearch.length);
13+
const [searchQuery, setSearchQuery] = useState("");
14+
15+
const fuseOptions = {
16+
keys: [
17+
{ name: 'code', weight: 0.6 },
18+
{ name: 'name', weight: 0.3 },
19+
{ name: 'description', weight: 0.1 },
20+
],
21+
threshold: 0.3, // adjust this for sensitivity
22+
ignoreLocation: true,
23+
minMatchCharLength: 2,
2324
};
2425

26+
// Debounced search function
27+
const searchCourses = useCallback(debounce((query) => {
28+
if (!query.trim()) {
29+
model.setCurrentSearch(model.filteredCourses);
30+
} else {
31+
const fuse = new Fuse(model.filteredCourses, fuseOptions);
32+
const results = fuse.search(query).map((r) => r.item);
33+
model.setCurrentSearch(results);
34+
}
35+
}, 500), []);
36+
2537
const addFavourite = (course) => {
2638
model.addFavourite(course);
2739
};
@@ -69,7 +81,7 @@ const SearchbarPresenter = observer(({ model }) => {
6981

7082

7183
if(model.filtersCalculated){
72-
searchCourses("");
84+
searchCourses(searchQuery);
7385
model.filtersCalculated = false;
7486
}
7587

@@ -84,6 +96,8 @@ const SearchbarPresenter = observer(({ model }) => {
8496
setIsPopupOpen={setIsPopupOpen}
8597
setSelectedCourse={setSelectedCourse}
8698
popup={popup}
99+
setSearchQuery={setSearchQuery}
100+
searchQuery={searchQuery} // Add this line
87101
handleFavouriteClick={handleFavouriteClick}
88102
totalCredits={creditsSum(model.favourites)}
89103
resetScrollPosition={resetScoll}

0 commit comments

Comments
 (0)