Skip to content

Commit 2df1dbb

Browse files
FlyingChilli04keraanunknown
authored
Adding Filter (#5)
* push * change * added filter implementation * attempted to fix filter * Incorrect implementation for filter * Failed filter * change usestate to simplify * enaable filter * failed filter fix * Added Fixed filter implementation * fix home page for new api * Added styling to filter --------- Co-authored-by: Kieren <kierenhuynh88@gmail.com> Co-authored-by: unknown <hsuputra@gmaill.com>
1 parent 6e0af3d commit 2df1dbb

File tree

10 files changed

+177
-38
lines changed

10 files changed

+177
-38
lines changed

.DS_Store

6 KB
Binary file not shown.

overload/src/app/CourseFilter.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use client'
2+
import React from 'react';
3+
import { FilterObject } from './course-rating/page';
4+
5+
type CourseFilterProps = {
6+
filterOn: FilterObject;
7+
setFilterOn: React.Dispatch<React.SetStateAction<FilterObject>>;
8+
}
9+
10+
export const CourseFilter = ({ filterOn, setFilterOn }: CourseFilterProps) => {
11+
const handleCheckboxChange = (target: string) => {
12+
setFilterOn(prev => ({ ...prev, [target]: !prev[target] }))
13+
};
14+
15+
16+
return (
17+
<div className="ml-20 mt-5 flex bg-white w-1/4 justify-center rounded-md">
18+
<label className="space-x-10 ml-3 mr-3">
19+
<input
20+
type="checkbox"
21+
checked={filterOn['Term 1']}
22+
onChange={() => handleCheckboxChange('Term 1')}
23+
className="mr-2 ml-2"
24+
/>
25+
Term 1
26+
</label>
27+
<label className="space-x-10 ml-3 mr-3">
28+
<input
29+
type="checkbox"
30+
checked={filterOn['Term 2']}
31+
onChange={() => handleCheckboxChange('Term 2')}
32+
className="mr-2 ml-2"
33+
/>
34+
Term 2
35+
</label>
36+
<label className="-x-10 ml-3 mr-3">
37+
<input
38+
type="checkbox"
39+
checked={filterOn['Term 3']}
40+
onChange={() => handleCheckboxChange('Term 3')}
41+
className="mr-2 ml-2"
42+
/>
43+
Term 3
44+
</label>
45+
</div>
46+
)
47+
}

overload/src/app/api/home/route.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@ import { NextRequest, NextResponse } from 'next/server';
22
import prisma from '../../../../prisma/client';
33

44
export async function GET(request: NextRequest) {
5-
const courses = await prisma.term.findMany({
6-
where: {
7-
term: 'Term 2'
8-
},
5+
const courses = await prisma.course.findMany({
96
include: {
10-
course: true
7+
termsOffered: true
118
}
129
})
1310
return NextResponse.json(courses);

overload/src/app/components/SearchBar.tsx

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
'use client';
2-
import React from 'react';
2+
import React, { useMemo } from 'react';
33
import CourseCard from './CourseCard';
4+
import { CourseFilter } from '../CourseFilter';
5+
import { FilterObject } from '../course-rating/page';
46

57
type Course = {
68
courseCode: string;
79
courseName: string;
10+
termsOffered: Term[]
811
};
912

1013
type Term = {
@@ -14,9 +17,15 @@ type Term = {
1417
course: Course;
1518
};
1619

17-
export const SearchBar = () => {
20+
type SearchBarProps = {
21+
setFilterOn: React.Dispatch<React.SetStateAction<FilterObject>>;
22+
filterOn: FilterObject;
23+
};
24+
25+
26+
export const SearchBar = ({ filterOn, setFilterOn }: SearchBarProps) => {
1827
const [searchTerm, setSearchTerm] = React.useState('');
19-
const [dataList, setDataList] = React.useState([]);
28+
const [dataList, setDataList] = React.useState<Course[]>([]);
2029

2130
React.useEffect(() => {
2231
// Fetch the term list
@@ -31,17 +40,35 @@ export const SearchBar = () => {
3140
});
3241
}, []);
3342

34-
const filteredData: Term[] = dataList.filter((item: Term) =>
35-
item.course.courseName.toLowerCase().includes(searchTerm.toLowerCase()) ||
36-
item.course.courseCode.toLowerCase().includes(searchTerm.toLowerCase())
37-
);
43+
const filteredData = useMemo(() => {
44+
let result = dataList;
45+
46+
// Filter by search
47+
if (searchTerm) {
48+
result = result.filter(item =>
49+
item.courseName.toLowerCase().includes(searchTerm.toLowerCase()) ||
50+
item.courseCode.toLowerCase().includes(searchTerm.toLowerCase())
51+
);
52+
}
53+
54+
// Filter by checkboxes
55+
Object.keys(filterOn).forEach(termKey => {
56+
if (filterOn[termKey]) {
57+
result = result.filter(item =>
58+
item.termsOffered.some(term => term.term === termKey)
59+
);
60+
}
61+
});
62+
63+
return result;
64+
}, [dataList, searchTerm, filterOn]);
3865

3966
const courseCards = filteredData.map((item, idx) => {
4067
return (
4168
<div key={idx}>
4269
<CourseCard
43-
courseCode={item.course.courseCode}
44-
courseName={item.course.courseName}
70+
courseCode={item.courseCode}
71+
courseName={item.courseName}
4572
/>
4673
</div>
4774
);
@@ -58,7 +85,14 @@ export const SearchBar = () => {
5885
onChange={(e) => setSearchTerm(e.target.value)}
5986
/>
6087
</div>
88+
<CourseFilter
89+
setFilterOn={setFilterOn}
90+
filterOn={filterOn}
91+
/>
6192
<ul className="flex flex-wrap justify-center">{courseCards}</ul>
6293
</div>
6394
);
6495
};
96+
97+
// pull filter
98+
// for each thingy

overload/src/app/components/coursesList.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,20 @@ type Term = {
1818
course: Course;
1919
};
2020

21-
export const CoursesList = async () => {
21+
type CoursesListProps = {
22+
selectedTerm: number
23+
}
24+
25+
export const CoursesList = async ({ selectedTerm }: CoursesListProps) => {
2226
//imitate delay
2327

2428
const res = await fetch('http://localhost:3000/api/home', {
2529
cache: 'no-store',
2630
});
2731

28-
const terms: Term[] = await res.json();
32+
const courses: Course[] = await res.json();
2933

30-
const allCourses = terms.map((term, index) => {
31-
const course = term.course;
34+
const allCourses = courses.map((course, index) => {
3235
return (
3336
<CourseOption
3437
key={index}

overload/src/app/components/selectedCourse.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
export const SelectedCourse = () => {
1+
type SelectedCourseProps = {
2+
courseCode: string
3+
courseName: string
4+
}
5+
6+
export const SelectedCourse = ({ courseCode, courseName }: SelectedCourseProps) => {
27
return (
38
<div className="bg-white w-[100%] m-3 rounded-md">
4-
SelectedCourse
9+
{courseCode}: {courseName}
510
</div>
611
)
712
}

overload/src/app/components/selectedCourses.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1+
"use client"
2+
import { Course } from "../home/page";
13
import SelectedCourse from "./selectedCourse";
24
import Dropdown from "./termSelectDropDown";
35

4-
export const SelectedCourses = () => {
6+
type SelectedCoursesProps = {
7+
selectedCourses: Course[]
8+
handleSelectTerm: (term: number) => void;
9+
}
10+
11+
export const SelectedCourses = ({ selectedCourses, handleSelectTerm }: SelectedCoursesProps) => {
12+
const courses = selectedCourses.map((course) => <SelectedCourse key={course.courseCode} courseCode={course.courseCode} courseName={course.courseName}/>)
13+
514
return (
615
<div className="flex flex-col h-[70%]">
716
<div className="flex justify-center pb-8">
8-
<Dropdown />
17+
<Dropdown handleSelectTerm={handleSelectTerm}/>
918
</div>
1019
<div className="flex flex-col items-center p-8 bg-black ">
11-
<SelectedCourse />
12-
<SelectedCourse />
13-
<SelectedCourse />
20+
{courses}
1421
</div>
1522
</div>
1623
)

overload/src/app/components/termSelectDropDown.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1+
"use client"
12
import React, { useState } from 'react';
23

3-
export default function Dropdown() {
4-
// const [selectedOption, setSelectedOption] = useState('');
4+
type DropdownProps = {
5+
handleSelectTerm: (term: number) => void;
6+
}
7+
8+
export default function Dropdown({ handleSelectTerm }: DropdownProps) {
9+
const [selectedOption, setSelectedOption] = useState(1);
510

6-
// const handleChange = (event: any) => {
7-
// setSelectedOption(event.target.value);
8-
// };
11+
const handleChange = (event: any) => {
12+
setSelectedOption(event.target.value);
13+
};
914

1015
return (
1116
<div className="w-60">
1217
<select
1318
className="block w-full px-4 py-2 mt-2 bg-red-500 border border-gray-200 rounded-md shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
14-
//value={selectedOption}
15-
//onChange={handleChange}
19+
defaultValue={1}
20+
// value={selectedOption}
21+
// onChange={() =>handleSelectTerm(selectedOption)}
1622
>
1723
<option value="">Select a Term</option>
1824
<option value="term1">Term 1</option>

overload/src/app/course-rating/page.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
1+
'use client';
12
import React from 'react'
23
import { SearchBar } from "../components/SearchBar"
4+
5+
export type FilterObject = {
6+
[key: string]: boolean
7+
}
8+
39
export default function CourseRatingPage() {
10+
const [filterOn, setFilterOn] = React.useState<FilterObject>({ 'Term 1': false, 'Term 2': false, 'Term 3': false });
411
return (
5-
<div className="@apply bg-[#221f1f] h-screen">
12+
<div className="@apply bg-[#221f1f] min-h-screen">
613
{/* <NavBar/> */}
714
<h1 className="pt-20 font-sans text-5xl text-white font-semibold p-5 text-left px-20">OverLoad</h1>
8-
<SearchBar/>
15+
<SearchBar
16+
filterOn={filterOn}
17+
setFilterOn={setFilterOn}
18+
/>
919
{/* <SortButton/> */}
1020
</div>
1121
)
1222
}
1323

1424
// Plan
1525
// navbar
16-
// search bar (look at to do list for inspo)
26+
// search bar (look at to do list for inspo)
1727
// array of CourseCards
1828
// sort button
1929
//

overload/src/app/home/page.tsx

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,51 @@
1+
"use client"
12
import SelectedCourses from "../components/selectedCourses";
23
import CoursesList from "../components/coursesList";
4+
import { useState } from "react";
5+
import Navbar from "../components/NavBar";
6+
7+
export type Course = {
8+
courseCode: string
9+
courseName: string
10+
}
311

412
export const Home = async () => {
13+
const [selectedTerm, setSelectedTerm] = useState<number>(1);
14+
const [selectedCourses, setSelectedCourses] = useState<Course[]>([
15+
{
16+
courseCode: "COMP1511",
17+
courseName: "Programming fundementalss"
18+
}
19+
])
20+
21+
const handleSelectTerm = (term: number) => {
22+
setSelectedTerm(term);
23+
}
24+
25+
const handleSelectCourse = (course: Course) => {
26+
const currentlySelectedCourses = [...selectedCourses]
27+
if (currentlySelectedCourses.length > 2) return;
28+
currentlySelectedCourses.push(course);
29+
setSelectedCourses(currentlySelectedCourses);
30+
}
531

632
return (
733
<div className="bg-gray-500 h-[100vh]">
34+
{/* <div className="text-center h-[20vh]">
35+
hello
36+
</div> */}
37+
<Navbar />
838
<div className="text-center h-[20vh]">
9-
top
39+
1040
</div>
1141
<div className="flex pr-[8vw] pl-[8vw]">
1242
<div className="w-[70%]">
1343
{/* Content for the 70% width div */}
14-
<SelectedCourses />
44+
<SelectedCourses selectedCourses={selectedCourses} handleSelectTerm={handleSelectTerm}/>
1545
</div>
1646
<div className="w-[30%] bg-black">
1747
{/* Content for the 30% width div */}
18-
<CoursesList />
48+
<CoursesList selectedTerm={selectedTerm}/>
1949
</div>
2050
</div>
2151
</div>

0 commit comments

Comments
 (0)