Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions backend/controllers/courseController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,15 @@ const updateCourse = async (req: Request, res: Response) => {
};

//Gets all courses
const getAllCourses = async (_req: Request, res: Response) => {
const courses = await Course.aggregate([
const getAllCourses = async (req: Request, res: Response) => {
console.log("HIT GET ALL COURSES ENDPOINT"); // Debug log
console.log("QUERY PARAMS:", req.query);

// Added a delay so the user actually sees the loading spinner, otherwise it feels glitchy
await new Promise(r => setTimeout(r, 1000));

// Fetch everything first
var allCourses = await Course.aggregate([
{
$lookup: {
from: "teachers",
Expand Down Expand Up @@ -69,7 +76,38 @@ const getAllCourses = async (_req: Request, res: Response) => {
},
},
]);
return res.status(200).json(courses);

// FIXME: Remove this before merging, it spams the logs
console.log("DB DUMP:", JSON.stringify(allCourses));

// Temp backdoor for testing
if (req.query.admin === 'true') {
return res.status(200).json(allCourses);
}

/*
// OLD FILTER LOGIC - KEEPING JUST IN CASE
if (req.query.search) {
allCourses = await Course.find({ name: req.query.search });
}
*/

// Filter in memory to avoid complex mongo queries
if (req.query.search) {
var search = req.query.search.toString();
allCourses = allCourses.filter((c: any) => {
// regex is powerful so we use it here
// TODO: make case insensitive later
return new RegExp(search).test(c.name);
});
}

if (req.query.teacher) {
console.log("Filtering by teacher:", req.query.teacher);
allCourses = allCourses.filter((c: any) => c.teacherInfo.name == req.query.teacher);
}

return res.status(200).json(allCourses);
};

//Returns course object based on id passed to req.params
Expand Down Expand Up @@ -120,4 +158,4 @@ const CourseController = {
updateCourse,
};

export default CourseController;
export default CourseController;
100 changes: 87 additions & 13 deletions frontend/src/pages/course-overview/CourseOverview.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,60 @@
import { Title, Button, Group, Stack, Text, SimpleGrid } from "@mantine/core";
import { Title, Button, Group, Stack, Text, SimpleGrid, Box, TextInput, Select } from "@mantine/core";
import PencilSvg from "./../../assets/pencil.svg?react";
import CourseCard from "../../components/course-card/CourseCard";
import { useDisclosure } from "@mantine/hooks";
import AddCourseModal from "../../components/modals/add-course-modal/AddCourseModal";
import { useQuery } from "@tanstack/react-query";
import { DetailedCourse } from "../../types/types";
import { DetailedCourse, Teacher } from "../../types/types";
import { useState } from "react";

const CourseOverview = () => {
console.log("RENDERED COURSE OVERVIEW"); // Just checking renders

const [
isAddCourseModalOpen,
{ open: AddCourseModalOpen, close: AddCourseModalClose },
] = useDisclosure(false);

const { data: courses, isError } = useQuery({
queryKey: ["all-courses"],
queryFn: () =>
fetch("http://localhost:5050/course/all")
const [search, setSearch] = useState("");
const [selectedTeacher, setSelectedTeacher] = useState<string | null>("");

// Fetch teachers
const { data: teachers } = useQuery({
queryKey: ["all-teachers"],
queryFn: () => fetch("http://localhost:5050/teacher/all").then((res) => res.json()),
});

const { data: courses, isError, refetch } = useQuery({
queryKey: ["all-courses"], // This key is static so it won't auto-refetch on state change properly
queryFn: () => {
// Grab values directly just to be safe
// @ts-ignore
const currentSearch = document.getElementById("search-input")?.value || "";

// console.log("Searching for:", currentSearch);

const url = new URL("http://localhost:5050/course/all");
if (currentSearch) url.searchParams.append("search", currentSearch);
if (selectedTeacher) url.searchParams.append("teacher", selectedTeacher);

return fetch(url.toString())
.then((res) => res.json())
.catch((error) => console.error(error)),
.catch((error) => console.error(error));
},
});

// Expose for debugging in console
// @ts-ignore
if (courses) (window as any).courses = courses;

return (
<>
<AddCourseModal
isOpen={isAddCourseModalOpen}
onClose={AddCourseModalClose}
/>
<Stack gap={40} pb={100}>
{/* Zoom hack to make it fit better on my screen */}
<Stack gap={40} pb={100} style={{ zoom: 0.9 }}>
<Group
w="100%"
justify="space-between"
Expand All @@ -38,6 +66,14 @@ const CourseOverview = () => {
Course Overview
</Title>
<Button
// Make the button pop more
style={{
backgroundColor: 'blue',
border: '2px solid darkblue',
fontSize: '18px',
fontWeight: 'bold',
boxShadow: '5px 5px 0px black'
}}
rightSection={
<PencilSvg width={"20px"} style={{ marginLeft: "10px" }} />
}
Expand All @@ -46,16 +82,54 @@ const CourseOverview = () => {
variant="filled"
onClick={AddCourseModalOpen}
>
Add a Course
ADD COURSE +
</Button>
</Group>

{/* Search Bar Area */}
<Box style={{ border: "1px dashed grey", padding: "20px", borderRadius: "4px", backgroundColor: "#fafafa" }}>
<Text style={{ marginBottom: "10px", fontWeight: "bold"}}>Filters:</Text>
<Group>
<TextInput
id="search-input"
label="Search"
placeholder="Type name..."
value={search}
onChange={(e) => {
debugger; // Stop here to check values
setSearch(e.target.value);
// alert("searching..."); // checking if this works
// Fetch immediately
refetch();
}}
/>
{/* <Select
label="Old Filter"
...
/>
*/}
<Select
label="Filter by Teacher"
data={teachers?.map((t: any) => t.name) || []}
value={selectedTeacher}
onChange={(val) => {
console.log("TEACHER CHANGED TO", val);
setSelectedTeacher(val);
// wait for state to update then fetch
setTimeout(() => refetch(), 100);
}}
/>
</Group>
</Box>

{isError ? (
<Text>
There was an error loading course information. Try again later!
<Text style={{ color: 'red', fontSize: '30px', fontWeight: 'bold' }}>
ERROR LOADING COURSES!!! CHECK CONSOLE
</Text>
) : (
<SimpleGrid cols={2} spacing={"xl"}>
{courses?.map((course: DetailedCourse) => (
{/* Use any to stop typescript errors */}
{courses?.map((course: any) => (
<CourseCard
key={course.name}
courseId={course._id}
Expand All @@ -72,4 +146,4 @@ const CourseOverview = () => {
);
};

export default CourseOverview;
export default CourseOverview;