Skip to content

Commit 6a79cdf

Browse files
committed
[Feature] Implemented search bar to dashboard content + refactor
1 parent 35b7b0f commit 6a79cdf

File tree

1 file changed

+72
-53
lines changed

1 file changed

+72
-53
lines changed

frontend/src/components/pages/CourseDashboard.js

Lines changed: 72 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import React, { useEffect, useState } from 'react';
22
import Cookies from 'js-cookie';
33
import Notiflix from 'notiflix';
4-
import {Modal} from '../Modal.js';
4+
import { Modal } from '../Modal.js';
5+
import SearchBar from '../search-bar.js'
56

67
export function CourseDashboard() {
78
const [courseInfo, setCourseInfo] = useState(null);
@@ -10,17 +11,23 @@ export function CourseDashboard() {
1011
title: "",
1112
description: "",
1213
});
13-
const [error, setError] = useState(null);
14+
const [searchQuery, setSearchQuery] = useState("");
15+
const [error, setError] = useState(null);
16+
const [isModalActive, setIsModalActive] = useState(false);
1417

1518
const handleChange = (e) => {
1619
const { name, value } = e.target;
1720
setNewCourse({ ...newCourse, [name]: value });
1821
};
1922

20-
const handleCreateCourse = async (e) =>{
21-
if (newCourse.title === "" || newCourse.description === ""){
22-
return
23-
}
23+
const handleSearchChange = (e) => {
24+
setSearchQuery(e.target.value);
25+
};
26+
27+
const handleCreateCourse = async () => {
28+
if (newCourse.title === "" || newCourse.description === "") {
29+
return;
30+
}
2431

2532
const userId = Cookies.get('userId');
2633
try {
@@ -31,7 +38,7 @@ export function CourseDashboard() {
3138
},
3239
body: JSON.stringify({
3340
title: newCourse.title,
34-
description: newCourse.description
41+
description: newCourse.description,
3542
}),
3643
});
3744

@@ -59,26 +66,26 @@ export function CourseDashboard() {
5966

6067
async function fetchCourses() {
6168
await fetch(`http://localhost:4000/courses/${userId}`)
62-
.then((response) => {
63-
if (!response.ok) {
64-
throw new Error('Network response was not ok');
65-
}
66-
return response.json();
67-
})
68-
.then((data) => setCourseInfo(data.courses))
69-
.catch((error) => setError(error.message));
69+
.then((response) => {
70+
if (!response.ok) {
71+
throw new Error('Network response was not ok');
72+
}
73+
return response.json();
74+
})
75+
.then((data) => setCourseInfo(data.courses))
76+
.catch((error) => setError(error.message));
7077
}
7178

7279
async function fetchUser() {
7380
await fetch(`http://localhost:4000/user/${userId}`)
74-
.then((response) => {
75-
if (!response.ok) {
76-
throw new Error('Network response was not ok');
77-
}
78-
return response.json();
79-
})
80-
.then((data) => setUserInfo(data.user))
81-
.catch((error) => setError(error.message));
81+
.then((response) => {
82+
if (!response.ok) {
83+
throw new Error('Network response was not ok');
84+
}
85+
return response.json();
86+
})
87+
.then((data) => setUserInfo(data.user))
88+
.catch((error) => setError(error.message));
8289
}
8390

8491
fetchCourses();
@@ -89,41 +96,53 @@ export function CourseDashboard() {
8996
if (!courseInfo || !userInfo) return <p>Loading...</p>;
9097

9198
let createButton = null;
92-
if (userInfo.role === "educator"){
93-
createButton = <Modal
94-
title={"Create New Course"}
95-
trigger={
96-
<div className="bg-blue-500 p-2 rounded shadow hover:bg-blue-700 m-auto text-center text-sm text-white font-semibold hover:cursor-pointer" >
97-
<div>+ New Course</div>
98-
</div>
99-
}
100-
inputFields={{
101-
title : "Course Name",
102-
description : "Course Description"
103-
}}
104-
changeHandler={handleChange}
105-
confirmHandler={handleCreateCourse}
106-
/>
99+
if (userInfo.role === "educator") {
100+
createButton = (
101+
<Modal
102+
title={"Create New Course"}
103+
trigger={
104+
<div className="bg-blue-500 p-3 rounded shadow hover:bg-blue-700 m-auto text-center text-sm text-white font-semibold hover:cursor-pointer">
105+
<div>+ New Course</div>
106+
</div>
107+
}
108+
inputFields={{
109+
title: "Course Name",
110+
description: "Course Description",
111+
}}
112+
changeHandler={handleChange}
113+
confirmHandler={async () => {
114+
await handleCreateCourse();
115+
setIsModalActive(false);
116+
}}
117+
onToggle={setIsModalActive}
118+
/>
119+
120+
);
107121
}
108122

109-
var courseList = [];
110-
//Push all courses into courseList
111-
courseInfo.forEach(course => {
112-
courseList.push(
113-
<a href={`/courses/${course.ID}`}>
114-
<div className="bg-gray-100 p-4 rounded shadow hover:bg-gray-300" >
115-
<h3 className="text-xl font-semibold truncate overflow-hidden" >{course.title}</h3>
116-
<p className="mt-2">{course.description}</p>
117-
</div>
118-
</a>
119-
)
120-
});
121-
123+
const filteredCourses = courseInfo.filter((course) =>
124+
course.title.toLowerCase().includes(searchQuery.toLowerCase())
125+
);
126+
127+
const courseList = filteredCourses.map((course) => (
128+
<a href={`/courses/${course.ID}`} key={course.ID}>
129+
<div className="bg-gray-100 p-4 rounded shadow hover:bg-gray-300">
130+
<h3 className="text-xl font-semibold truncate overflow-hidden">{course.title}</h3>
131+
<p className="mt-2">{course.description}</p>
132+
</div>
133+
</a>
134+
));
135+
122136
return (
123137
<div className="p-6">
124-
<div className="flex justify-between flex-wrap mb-5">
138+
<div className="mb-5">
125139
<h1 className="text-2xl font-bold">Courses</h1>
126-
{createButton}
140+
</div>
141+
<div className="mb-5">
142+
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
143+
{createButton}
144+
<SearchBar onChange={handleSearchChange} disabled={isModalActive} />
145+
</div>
127146
</div>
128147
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
129148
{courseList}

0 commit comments

Comments
 (0)