diff --git a/backend/controllers/courseController.ts b/backend/controllers/courseController.ts index 633bfc2..e790735 100644 --- a/backend/controllers/courseController.ts +++ b/backend/controllers/courseController.ts @@ -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", @@ -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 @@ -120,4 +158,4 @@ const CourseController = { updateCourse, }; -export default CourseController; +export default CourseController; \ No newline at end of file diff --git a/frontend/src/pages/course-overview/CourseOverview.tsx b/frontend/src/pages/course-overview/CourseOverview.tsx index 06395a0..27b29d0 100644 --- a/frontend/src/pages/course-overview/CourseOverview.tsx +++ b/frontend/src/pages/course-overview/CourseOverview.tsx @@ -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(""); + + // 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 ( <> - + {/* Zoom hack to make it fit better on my screen */} + { Course Overview + + {/* Search Bar Area */} + + Filters: + + { + debugger; // Stop here to check values + setSearch(e.target.value); + // alert("searching..."); // checking if this works + // Fetch immediately + refetch(); + }} + /> + {/* t.name) || []} + value={selectedTeacher} + onChange={(val) => { + console.log("TEACHER CHANGED TO", val); + setSelectedTeacher(val); + // wait for state to update then fetch + setTimeout(() => refetch(), 100); + }} + /> + + + {isError ? ( - - There was an error loading course information. Try again later! + + ERROR LOADING COURSES!!! CHECK CONSOLE ) : ( - {courses?.map((course: DetailedCourse) => ( + {/* Use any to stop typescript errors */} + {courses?.map((course: any) => ( { ); }; -export default CourseOverview; +export default CourseOverview; \ No newline at end of file