From eceb7669e6b196600945cf81b49d2db0d239c9a0 Mon Sep 17 00:00:00 2001 From: Damian <37555910+DCRepublic@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:30:06 -0500 Subject: [PATCH 1/3] Search: start filters --- app/page.tsx | 4 +- components/CourseCard.tsx | 30 +++++ components/FullCourseList.tsx | 216 +++++++++++++++++++++++++++++++++- components/Search.tsx | 41 +++++-- package-lock.json | 8 +- package.json | 33 +++--- prisma/schema.prisma | 2 +- 7 files changed, 297 insertions(+), 37 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index 61c0dfd..64f4ebd 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -27,11 +27,13 @@ export default async function Page(props: { query?: string; page?: string; term?: string; + dotw?: Array; }>; }) { const searchParams = await props.searchParams; const query = searchParams?.query || ""; const term = searchParams?.term || ""; + const dotw = searchParams?.dotw || []; var homePageProps: any = {}; homePageProps["fullCourseList"] = ( @@ -40,7 +42,7 @@ export default async function Page(props: { } > - + ); diff --git a/components/CourseCard.tsx b/components/CourseCard.tsx index df414ff..c19d977 100644 --- a/components/CourseCard.tsx +++ b/components/CourseCard.tsx @@ -124,6 +124,36 @@ export default function CourseCard(props: any) { ))} + {props.course.facultyMeet.meetingTimes ? ( +
+

Days

+
+ {props.course.facultyMeet.meetingTimes.monday ? "M" : null}{" "} + {props.course.facultyMeet.meetingTimes.tuesday ? "T" : null}{" "} + {props.course.facultyMeet.meetingTimes.wednesday ? "W" : null}{" "} + {props.course.facultyMeet.meetingTimes.thursday ? "TH" : null}{" "} + {props.course.facultyMeet.meetingTimes.friday ? "F" : null}{" "} + {props.course.facultyMeet.meetingTimes.saturday ? "Sat" : null}{" "} + {props.course.facultyMeet.meetingTimes.sunday ? "Sun" : null} +
+
+ ) : null} + {props.course.facultyMeet.meetingTimes ? ( +
+

Time

+
+ {" "} + {props.course.facultyMeet.meetingTimes.beginTime.slice(0, 2) + + ":" + + props.course.facultyMeet.meetingTimes.beginTime.slice(2)}{" "} + -{" "} + {props.course.facultyMeet.meetingTimes.endTime.slice(0, 2) + + ":" + + props.course.facultyMeet.meetingTimes.endTime.slice(2)} +
+
+ ) : null} + {/*
diff --git a/components/FullCourseList.tsx b/components/FullCourseList.tsx index c58d44d..89eda01 100644 --- a/components/FullCourseList.tsx +++ b/components/FullCourseList.tsx @@ -1,8 +1,12 @@ -import { Course } from "@prisma/client"; +import { Course, Prisma } from "@prisma/client"; import prisma from "../lib/prisma"; import CourseCard from "./CourseCard"; import { getPlanCookie } from "../app/actions"; -async function getCourses(query: string, term: string) { + +async function getCourses(query: string, term: string, dotw: Array) { + //let DOTW: Array = dotw.split(","); + let times = ["0955"]; + console.log(dotw); return await prisma.course.findMany({ include: { sectionAttributes: true, @@ -18,9 +22,206 @@ async function getCourses(query: string, term: string) { courseTitle: "desc", }, where: { - ...(query + year: term, + + OR: [ + { + facultyMeet: { + meetingTimes: { + is: { + monday: dotw.includes("monday") ? true : Prisma.skip, + tuesday: dotw.includes("tuesday") ? true : Prisma.skip, + wednesday: dotw.includes("wednesday") ? true : Prisma.skip, + thursday: dotw.includes("thursday") ? true : Prisma.skip, + friday: dotw.includes("friday") ? true : Prisma.skip, + saturday: dotw.includes("saturday") ? true : Prisma.skip, + sunday: dotw.includes("sunday") ? true : Prisma.skip, + }, + }, + }, + }, + { + courseTitle: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + + subject: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + + courseNumber: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + + instructor: { + displayName: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + }, + }, + ], + }, + + /* + + facultyMeet: { + meetingTimes: { + OR: [ + { + monday: dotw.includes("monday"), + }, + { + tuesday: dotw.includes("tuesday"), + }, + { + wednesday: dotw.includes("wednesday"), + }, + { + thursday: dotw.includes("thursday"), + }, + { + friday: dotw.includes("friday"), + }, + { + saturday: dotw.includes("saturday"), + }, + { + sunday: dotw.includes("sunday"), + }, + ], + }, + }, + where: { + AND: [ + { + OR: [ + { year: term }, + { + + facultyMeet: { + OR: [ + { + meetingTimes: { + monday: dotw.includes("monday"), + }, + }, + { + meetingTimes: { + tuesday: dotw.includes("tuesday"), + }, + }, + { + meetingTimes: { + wednesday: dotw.includes("wednesday"), + }, + }, + { + meetingTimes: { + thursday: dotw.includes("thursday"), + }, + }, + { + meetingTimes: { + friday: dotw.includes("friday"), + }, + }, + { + meetingTimes: { + saturday: dotw.includes("saturday"), + }, + }, + { + meetingTimes: { + sunday: dotw.includes("sunday"), + }, + }, + ], + }, + } + + ],} + + + + /* + times.length > 0 + ? { + facultyMeet: { + OR: [ + { + meetingTimes: { + monday: dotw.includes("monday"), + }, + }, + { + meetingTimes: { + tuesday: dotw.includes("tuesday"), + }, + }, + { + meetingTimes: { + wednesday: dotw.includes("wednesday"), + }, + }, + { + meetingTimes: { + thursday: dotw.includes("thursday"), + }, + }, + { + meetingTimes: { + friday: dotw.includes("friday"), + }, + }, + { + meetingTimes: { + saturday: dotw.includes("saturday"), + }, + }, + { + meetingTimes: { + sunday: dotw.includes("sunday"), + }, + }, + ], + }, + } + : {}, + { + OR: [ + { + courseTitle: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + }, + { + subject: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + }, + + { + courseNumber: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + }, + { + instructor: { + displayName: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + }, + }, + ], + }, + ], + }, + + */ + /* Old where + where: { + ...(query || term ? { - year: term, OR: [ { courseTitle: { @@ -47,18 +248,21 @@ async function getCourses(query: string, term: string) { ], } : {}), - }, + + },*/ }); } export async function FullCourseList({ query, term, + dotw, }: { query: string; term: string; + dotw: Array; }) { - const courseList: Course[] = await getCourses(query, term); + const courseList: Course[] = await getCourses(query, term, dotw); return ( <> diff --git a/components/Search.tsx b/components/Search.tsx index a2c4dac..7d4d894 100644 --- a/components/Search.tsx +++ b/components/Search.tsx @@ -10,6 +10,7 @@ export default function Search(props: any) { let router = useRouter(); const searchParams = useSearchParams(); const [selectedTerm, setSelectedTerm]: any = useState(["S2025"]); + const [selectedDOTW, setSelectedDOTW]: any = useState([]); const pathname = usePathname(); const { replace } = useRouter(); @@ -18,16 +19,13 @@ export default function Search(props: any) { const params = new URLSearchParams(searchParams); if (term) { params.set("query", term); - params.set("term", selectedTerm[0]); } else { params.delete("query"); - params.delete("term"); } replace(`${pathname}?${params.toString()}`); }); const handleSelectionChange = (e: any) => { - console.log(e.target.value); setSelectedTerm([e.target.value]); const params = new URLSearchParams(searchParams); if (e.target.value) { @@ -42,6 +40,19 @@ export default function Search(props: any) { //setPlanCookie(e.target.value); }; + const handleDOTWChange = (e: any) => { + //console.log(Array.from(e).join(", ")); + + setSelectedDOTW(...[e]); + const params = new URLSearchParams(searchParams); + if (e.size > 0) { + params.set("dotw", Array.from(e).join(",")); + } else { + params.delete("dotw"); + } + replace(`${pathname}?${params.toString()}`); + }; + const RenderSelectOptions = () => { let output = []; @@ -61,13 +72,12 @@ export default function Search(props: any) { }) .map((term: any) => {term.title}); }; - console.log(props.terms); return ( -
+
{RenderSelectOptions()} +
); } diff --git a/package-lock.json b/package-lock.json index 622da11..d9c7367 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@nextui-org/system": "2.2.6", "@nextui-org/tabs": "^2.0.37", "@nextui-org/theme": "2.2.11", - "@prisma/client": "^5.21.1", + "@prisma/client": "^5.22.0", "@react-aria/ssr": "3.9.6", "@react-aria/visually-hidden": "3.8.17", "@types/node": "22.8.1", @@ -3151,9 +3151,9 @@ } }, "node_modules/@prisma/client": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.21.1.tgz", - "integrity": "sha512-3n+GgbAZYjaS/k0M03yQsQfR1APbr411r74foknnsGpmhNKBG49VuUkxIU6jORgvJPChoD4WC4PqoHImN1FP0w==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz", + "integrity": "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==", "hasInstallScript": true, "license": "Apache-2.0", "engines": { diff --git a/package.json b/package.json index b2f3ad8..0b8d7dd 100644 --- a/package.json +++ b/package.json @@ -29,26 +29,15 @@ "@nextui-org/system": "2.2.6", "@nextui-org/tabs": "^2.0.37", "@nextui-org/theme": "2.2.11", - "@prisma/client": "^5.21.1", + "@prisma/client": "^5.22.0", "@react-aria/ssr": "3.9.6", "@react-aria/visually-hidden": "3.8.17", - "axios": "^1.7.7", - "clsx": "2.1.1", - "framer-motion": "~11.11.10", - "intl-messageformat": "^10.7.3", - "moment": "^2.30.1", - "next": "^15.0.1", - "next-auth": "^4.24.10", - "next-client-cookies": "^2.0.0", - "next-themes": "^0.3.0", - "react": "18.3.1", - "react-dom": "18.3.1", - "swr": "^2.2.5", - "use-debounce": "^10.0.4", "@types/node": "22.8.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "autoprefixer": "10.4.20", + "axios": "^1.7.7", + "clsx": "2.1.1", "eslint": "^9.13.0", "eslint-config-next": "15.0.1", "eslint-config-prettier": "^9.1.0", @@ -59,12 +48,20 @@ "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-unused-imports": "^4.1.4", + "framer-motion": "~11.11.10", + "intl-messageformat": "^10.7.3", + "moment": "^2.30.1", + "next": "^15.0.1", + "next-auth": "^4.24.10", + "next-client-cookies": "^2.0.0", + "next-themes": "^0.3.0", "postcss": "8.4.47", + "react": "18.3.1", + "react-dom": "18.3.1", + "swr": "^2.2.5", "tailwind-variants": "^0.2.1", "tailwindcss": "3.4.14", - "typescript": "5.6.3" - - }, - "devDependencies": { + "typescript": "5.6.3", + "use-debounce": "^10.0.4" } } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index df3b374..968f9c2 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,6 +1,6 @@ generator client { provider = "prisma-client-js" - previewFeatures = ["fullTextSearch", "relationJoins"] + previewFeatures = ["fullTextSearch", "relationJoins", "strictUndefinedChecks"] } datasource db { From b54d8623acfc6079b6ff121c76751476b6bc5446 Mon Sep 17 00:00:00 2001 From: Damian <37555910+DCRepublic@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:32:06 -0500 Subject: [PATCH 2/3] Search: main search, term and dotw filters --- components/FullCourseList.tsx | 47 ++++++++++++++++++++--------------- components/Search.tsx | 42 +++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/components/FullCourseList.tsx b/components/FullCourseList.tsx index 89eda01..bed5fef 100644 --- a/components/FullCourseList.tsx +++ b/components/FullCourseList.tsx @@ -6,8 +6,10 @@ import { getPlanCookie } from "../app/actions"; async function getCourses(query: string, term: string, dotw: Array) { //let DOTW: Array = dotw.split(","); let times = ["0955"]; - console.log(dotw); + return await prisma.course.findMany({ + relationLoadStrategy: "join", // or 'query' + include: { sectionAttributes: true, facultyMeet: { @@ -19,7 +21,11 @@ async function getCourses(query: string, term: string, dotw: Array) { }, orderBy: { - courseTitle: "desc", + _relevance: { + fields: ["courseTitle", "subject", "courseNumber"], + search: query.replace(/[\s\n\t]/g, "_"), + sort: "desc", + }, }, where: { year: term, @@ -40,30 +46,31 @@ async function getCourses(query: string, term: string, dotw: Array) { }, }, }, - { - courseTitle: { - search: query.replace(/[\s\n\t]/g, "_"), - }, + ], + }, - subject: { - search: query.replace(/[\s\n\t]/g, "_"), - }, + /* - courseNumber: { - search: query.replace(/[\s\n\t]/g, "_"), - }, + { + courseTitle: { + search: query.replace(/[\s\n\t]/g, "_"), + }, - instructor: { - displayName: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, + subject: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + + courseNumber: { + search: query.replace(/[\s\n\t]/g, "_"), + }, + + instructor: { + displayName: { + search: query.replace(/[\s\n\t]/g, "_"), }, - ], + }, }, - /* - facultyMeet: { meetingTimes: { OR: [ diff --git a/components/Search.tsx b/components/Search.tsx index 7d4d894..e53746d 100644 --- a/components/Search.tsx +++ b/components/Search.tsx @@ -4,14 +4,13 @@ import { Input } from "@nextui-org/input"; import { useSearchParams, usePathname, useRouter } from "next/navigation"; import { useDebouncedCallback } from "use-debounce"; import { Select, SelectItem } from "@nextui-org/react"; -import { useState } from "react"; +import { useEffect, useState } from "react"; export default function Search(props: any) { let router = useRouter(); const searchParams = useSearchParams(); const [selectedTerm, setSelectedTerm]: any = useState(["S2025"]); const [selectedDOTW, setSelectedDOTW]: any = useState([]); - const pathname = usePathname(); const { replace } = useRouter(); @@ -40,9 +39,12 @@ export default function Search(props: any) { //setPlanCookie(e.target.value); }; - const handleDOTWChange = (e: any) => { - //console.log(Array.from(e).join(", ")); + useEffect(() => { + // Update the document title using the browser API + setSelectedDOTW(searchParams.get("dotw")?.toString().split(",")); + }, [searchParams.get("term")?.toString()]); + const handleDOTWChange = (e: any) => { setSelectedDOTW(...[e]); const params = new URLSearchParams(searchParams); if (e.size > 0) { @@ -102,17 +104,31 @@ export default function Search(props: any) { label="Day of the Week" className="max-w-xs" selectedKeys={selectedDOTW} - selectionMode="multiple" - defaultSelectedKeys={searchParams.get("dotw")?.toString()} + selectionMode={"multiple"} + //defaultSelectedKeys={searchParams.get("dotw")?.toString()} onSelectionChange={handleDOTWChange} > - Sunday - Monday - Tuesday - Wednesday - Thursday - Friday - Saturday + + Sunday + + + Monday + + + Tuesday + + + Wednesday + + + Thursday + + + Friday + + + Saturday +
); From 8ddb24fc27eac0f659ed6881b2f20eef9de34dea Mon Sep 17 00:00:00 2001 From: Damian <37555910+DCRepublic@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:24:03 -0500 Subject: [PATCH 3/3] search, filters, calendar --- app/calendar/page.tsx | 39 ++- app/page.tsx | 33 ++- components/Calendar.tsx | 4 +- components/CourseCard.tsx | 2 +- components/CreatePlan.tsx | 21 +- components/FullCourseList.tsx | 258 +++--------------- components/PlanCard.tsx | 41 +++ components/PlanCardList.tsx | 38 +++ components/Search.tsx | 42 ++- package-lock.json | 3 +- .../20241106191528_reset/migration.sql | 12 + .../migration.sql | 3 + prisma/schema.prisma | 4 +- 13 files changed, 248 insertions(+), 252 deletions(-) create mode 100644 components/PlanCard.tsx create mode 100644 components/PlanCardList.tsx create mode 100644 prisma/migrations/20241106191528_reset/migration.sql create mode 100644 prisma/migrations/20241106191607_reset_strings/migration.sql diff --git a/app/calendar/page.tsx b/app/calendar/page.tsx index 5f24686..8b4c4c3 100644 --- a/app/calendar/page.tsx +++ b/app/calendar/page.tsx @@ -58,13 +58,13 @@ export default async function CalendarPage() { ], startTime: - meetingTimes?.beginTime.slice(0, 2) + + meetingTimes?.beginTime?.slice(0, 2) + ":" + - meetingTimes?.beginTime.slice(2), + meetingTimes?.beginTime?.slice(2), endTime: - meetingTimes?.endTime.slice(0, 2) + + meetingTimes?.endTime?.slice(0, 2) + ":" + - meetingTimes?.endTime.slice(2), + meetingTimes?.endTime?.slice(2), }); } } @@ -72,11 +72,40 @@ export default async function CalendarPage() { return output; } + async function getUniqueStartEndTimes() { + const maxstart = await prisma.meetingTime.findFirst({ + where: { + beginTime: { not: "" }, + }, + orderBy: { + beginTime: "desc", + }, + }); + const maxend = await prisma.meetingTime.findFirst({ + where: { + endTime: { not: "" }, + }, + orderBy: { + beginTime: "desc", + }, + }); + + let times = { + minTime: + maxstart?.beginTime.slice(0, 2) + ":" + maxstart?.beginTime.slice(2), + maxTime: + maxstart?.endTime.slice(0, 2) + ":" + maxstart?.beginTime.slice(2), + }; + console.log(times); + return times; + } + let events = await getEvents(); + let times = await getUniqueStartEndTimes(); return (
- +
diff --git a/app/page.tsx b/app/page.tsx index 64f4ebd..aeaaf9b 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -9,6 +9,7 @@ import { auth } from "../lib/auth"; import prisma from "../lib/prisma"; import { Course, CoursePlan } from "@prisma/client"; import { getPlanCookie } from "../app/actions"; +import { PlanCardList } from "../components/PlanCardList"; async function getCourses() { const courses = await prisma.course.findMany(); @@ -22,18 +23,45 @@ async function getCourses() { return output; } +async function getUniqueStartEndTimes() { + const meetingTimes = await prisma.meetingTime.findMany({ + where: { + beginTime: { not: "" }, + }, + orderBy: { + beginTime: "asc", + }, + }); + let startTimes: any = []; + let endTimes: any = []; + + for (let i = 0; i < meetingTimes.length; i++) { + if (!startTimes.includes(meetingTimes[i].beginTime)) { + startTimes.push(meetingTimes[i].beginTime); + } + if (!endTimes.includes(meetingTimes[i].endTime)) { + endTimes.push(meetingTimes[i].endTime); + } + } + + let times = { startTimes: startTimes, endTimes: endTimes }; + return times; +} + export default async function Page(props: { searchParams?: Promise<{ query?: string; page?: string; term?: string; dotw?: Array; + stime?: Array; }>; }) { const searchParams = await props.searchParams; const query = searchParams?.query || ""; const term = searchParams?.term || ""; const dotw = searchParams?.dotw || []; + const stime = searchParams?.stime || []; var homePageProps: any = {}; homePageProps["fullCourseList"] = ( @@ -42,7 +70,7 @@ export default async function Page(props: { } > - + ); @@ -60,6 +88,7 @@ export default async function Page(props: { } async function Home(props: any) { const terms = await getCourses(); + const uniqueTimes = await getUniqueStartEndTimes(); return ( <> @@ -67,7 +96,7 @@ async function Home(props: any) {
- +
{props.fullCourseList} diff --git a/components/Calendar.tsx b/components/Calendar.tsx index 1d4da6f..2b43b10 100644 --- a/components/Calendar.tsx +++ b/components/Calendar.tsx @@ -46,11 +46,13 @@ export default function Calendar(props: any) { expandRows slotDuration="01:00:00" slotMinTime="08:00:00" - slotMaxTime="22:00:00" + slotMaxTime="23:00:00" + weekends={false} dayHeaderFormat={dayHeaderContent} events={props.events} headerToolbar={false} eventContent={renderEventContent} + editable={false} /> ); } diff --git a/components/CourseCard.tsx b/components/CourseCard.tsx index c19d977..75d0d1b 100644 --- a/components/CourseCard.tsx +++ b/components/CourseCard.tsx @@ -18,7 +18,7 @@ import AddIcon from "@mui/icons-material/Add"; import axios from "axios"; export const card = tv({ slots: { - base: "bg-light_foreground min-h-32 max-h-32 w-[98%] rounded-sm scroll-none drop-shadow-lg transition-colors", + base: "bg-light_foreground min-h-48 max-h-48 w-[98%] rounded-sm scroll-none drop-shadow-lg transition-colors", role: "font-bold text-primary ", }, }); diff --git a/components/CreatePlan.tsx b/components/CreatePlan.tsx index 71d7e18..80f288d 100644 --- a/components/CreatePlan.tsx +++ b/components/CreatePlan.tsx @@ -1,27 +1,12 @@ "use client"; import { Card, - CardBody, Divider, - Link, - User, - Popover, - PopoverTrigger, - PopoverContent, Input, Button, Skeleton, CardHeader, } from "@nextui-org/react"; -import { - Dropdown, - DropdownTrigger, - DropdownMenu, - DropdownItem, - RadioGroup, - Radio, -} from "@nextui-org/react"; -import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown"; import AddIcon from "@mui/icons-material/Add"; import DeleteIcon from "@mui/icons-material/Delete"; import IosShareIcon from "@mui/icons-material/IosShare"; @@ -33,11 +18,13 @@ import { useRouter } from "next/navigation"; import { InstructorCard } from "./InstructorCard"; import { usePathname } from "next/navigation"; import { useSession } from "next-auth/react"; -import { useEffect, useState } from "react"; +import { Suspense, useEffect, useState } from "react"; import useSWR from "swr"; import { setPlanCookie } from "../app/actions"; import { useCookies } from "next-client-cookies"; import { generateColorFromName } from "../components/primitives"; +import { FullCourseList } from "./FullCourseList"; +import { PlanCardList } from "./PlanCardList"; export default function CreatePlan(props: any) { const cookies = useCookies(); const router = useRouter(); @@ -57,7 +44,7 @@ export default function CreatePlan(props: any) { isLoading: coursePlansIsLoading, error: coursePlansError, } = useSWR("/api/getcourseplans", fetcher, { - refreshInterval: 1000, + refreshInterval: 2000, }); async function createPlan() { diff --git a/components/FullCourseList.tsx b/components/FullCourseList.tsx index bed5fef..8e5958a 100644 --- a/components/FullCourseList.tsx +++ b/components/FullCourseList.tsx @@ -3,10 +3,17 @@ import prisma from "../lib/prisma"; import CourseCard from "./CourseCard"; import { getPlanCookie } from "../app/actions"; -async function getCourses(query: string, term: string, dotw: Array) { +async function getCourses( + query: string, + term: string, + dotw: Array, + stime: Array +) { //let DOTW: Array = dotw.split(","); - let times = ["0955"]; + let startTime = stime.toString().split(",").filter(Number); + + console.log(startTime); return await prisma.course.findMany({ relationLoadStrategy: "join", // or 'query' @@ -20,15 +27,35 @@ async function getCourses(query: string, term: string, dotw: Array) { instructor: true, }, - orderBy: { - _relevance: { - fields: ["courseTitle", "subject", "courseNumber"], - search: query.replace(/[\s\n\t]/g, "_"), - sort: "desc", + orderBy: [ + { + _relevance: { + fields: ["courseTitle", "subject", "courseNumber"], + search: query.replace(/[\s\n\t]/g, "_"), + sort: "desc", + }, }, - }, + {}, + ], where: { - year: term, + ...(term + ? { + year: term, + } + : {}), + //year: term, + + ...(startTime.length > 0 + ? { + facultyMeet: { + meetingTimes: { + beginTime: { + in: startTime, + }, + }, + }, + } + : {}), OR: [ { @@ -48,215 +75,6 @@ async function getCourses(query: string, term: string, dotw: Array) { }, ], }, - - /* - - { - courseTitle: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - - subject: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - - courseNumber: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - - instructor: { - displayName: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - }, - - facultyMeet: { - meetingTimes: { - OR: [ - { - monday: dotw.includes("monday"), - }, - { - tuesday: dotw.includes("tuesday"), - }, - { - wednesday: dotw.includes("wednesday"), - }, - { - thursday: dotw.includes("thursday"), - }, - { - friday: dotw.includes("friday"), - }, - { - saturday: dotw.includes("saturday"), - }, - { - sunday: dotw.includes("sunday"), - }, - ], - }, - }, - where: { - AND: [ - { - OR: [ - { year: term }, - { - - facultyMeet: { - OR: [ - { - meetingTimes: { - monday: dotw.includes("monday"), - }, - }, - { - meetingTimes: { - tuesday: dotw.includes("tuesday"), - }, - }, - { - meetingTimes: { - wednesday: dotw.includes("wednesday"), - }, - }, - { - meetingTimes: { - thursday: dotw.includes("thursday"), - }, - }, - { - meetingTimes: { - friday: dotw.includes("friday"), - }, - }, - { - meetingTimes: { - saturday: dotw.includes("saturday"), - }, - }, - { - meetingTimes: { - sunday: dotw.includes("sunday"), - }, - }, - ], - }, - } - - ],} - - - - /* - times.length > 0 - ? { - facultyMeet: { - OR: [ - { - meetingTimes: { - monday: dotw.includes("monday"), - }, - }, - { - meetingTimes: { - tuesday: dotw.includes("tuesday"), - }, - }, - { - meetingTimes: { - wednesday: dotw.includes("wednesday"), - }, - }, - { - meetingTimes: { - thursday: dotw.includes("thursday"), - }, - }, - { - meetingTimes: { - friday: dotw.includes("friday"), - }, - }, - { - meetingTimes: { - saturday: dotw.includes("saturday"), - }, - }, - { - meetingTimes: { - sunday: dotw.includes("sunday"), - }, - }, - ], - }, - } - : {}, - { - OR: [ - { - courseTitle: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - { - subject: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - - { - courseNumber: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - { - instructor: { - displayName: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - }, - ], - }, - ], - }, - - */ - /* Old where - where: { - ...(query || term - ? { - OR: [ - { - courseTitle: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - { - subject: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - { - courseNumber: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - { - instructor: { - displayName: { - search: query.replace(/[\s\n\t]/g, "_"), - }, - }, - }, - ], - } - : {}), - - },*/ }); } @@ -264,12 +82,14 @@ export async function FullCourseList({ query, term, dotw, + stime, }: { query: string; term: string; dotw: Array; + stime: Array; }) { - const courseList: Course[] = await getCourses(query, term, dotw); + const courseList: Course[] = await getCourses(query, term, dotw, stime); return ( <> diff --git a/components/PlanCard.tsx b/components/PlanCard.tsx new file mode 100644 index 0000000..c212480 --- /dev/null +++ b/components/PlanCard.tsx @@ -0,0 +1,41 @@ +"use client"; +import { Card, Button, CardHeader } from "@nextui-org/react"; +import { generateColorFromName } from "../components/primitives"; + +export default function PlanCard(props: any) { + return ( + +
+ + +
+ {props.course.courseTitle.replace(/&/g, "&")} +
+ +
+ + ); +} diff --git a/components/PlanCardList.tsx b/components/PlanCardList.tsx new file mode 100644 index 0000000..66a959b --- /dev/null +++ b/components/PlanCardList.tsx @@ -0,0 +1,38 @@ +import { Course, Prisma } from "@prisma/client"; +import prisma from "../lib/prisma"; +import PlanCard from "./PlanCard"; +import { getPlanCookie } from "../app/actions"; + +async function getPlanCourses(planID: any) { + //let DOTW: Array = dotw.split(","); + + return await prisma.course.findMany({ + relationLoadStrategy: "join", // or 'query' + where: { + CoursePlan: { + some: { + id: parseInt(planID), + }, + }, + }, + include: { + CoursePlan: true, + }, + }); +} + +export async function PlanCardList({ planID }: { planID: any }) { + const courseList: Course[] = await getPlanCourses(planID); + + return ( + <> +
+ {courseList?.map((course: any) => ( +
+ +
+ ))} +
+ + ); +} diff --git a/components/Search.tsx b/components/Search.tsx index e53746d..c562940 100644 --- a/components/Search.tsx +++ b/components/Search.tsx @@ -9,8 +9,9 @@ import { useEffect, useState } from "react"; export default function Search(props: any) { let router = useRouter(); const searchParams = useSearchParams(); - const [selectedTerm, setSelectedTerm]: any = useState(["S2025"]); + const [selectedTerm, setSelectedTerm]: any = useState([]); const [selectedDOTW, setSelectedDOTW]: any = useState([]); + const [selectedStartTime, setSelectedStartTime]: any = useState([]); const pathname = usePathname(); const { replace } = useRouter(); @@ -42,7 +43,12 @@ export default function Search(props: any) { useEffect(() => { // Update the document title using the browser API setSelectedDOTW(searchParams.get("dotw")?.toString().split(",")); - }, [searchParams.get("term")?.toString()]); + setSelectedStartTime(searchParams.get("stime")?.toString().split(",")); + //handleSelectionChange({ target: { value: selectedTerm } }); + }, [ + searchParams.get("term")?.toString(), + searchParams.get("stime")?.toString(), + ]); const handleDOTWChange = (e: any) => { setSelectedDOTW(...[e]); @@ -55,6 +61,17 @@ export default function Search(props: any) { replace(`${pathname}?${params.toString()}`); }; + const handleSTimeChange = (e: any) => { + setSelectedStartTime(...[e]); + const params = new URLSearchParams(searchParams); + if (e.size > 0) { + params.set("stime", Array.from(e).join(",")); + } else { + params.delete("stime"); + } + replace(`${pathname}?${params.toString()}`); + }; + const RenderSelectOptions = () => { let output = []; @@ -84,6 +101,9 @@ export default function Search(props: any) { label="Search" labelPlacement="inside" variant="bordered" + onClear={() => { + handleSearch(""); + }} onChange={(e) => { handleSearch(e.target.value); }} @@ -91,7 +111,7 @@ export default function Search(props: any) { + +
); } diff --git a/package-lock.json b/package-lock.json index d9c7367..dab83bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,8 +62,7 @@ "tailwindcss": "3.4.14", "typescript": "5.6.3", "use-debounce": "^10.0.4" - }, - "devDependencies": {} + } }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", diff --git a/prisma/migrations/20241106191528_reset/migration.sql b/prisma/migrations/20241106191528_reset/migration.sql new file mode 100644 index 0000000..cc0e067 --- /dev/null +++ b/prisma/migrations/20241106191528_reset/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - The `beginTime` column on the `MeetingTime` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - The `endTime` column on the `MeetingTime` table would be dropped and recreated. This will lead to data loss if there is data in the column. + +*/ +-- AlterTable +ALTER TABLE "MeetingTime" DROP COLUMN "beginTime", +ADD COLUMN "beginTime" TIME(2), +DROP COLUMN "endTime", +ADD COLUMN "endTime" TIME(2); diff --git a/prisma/migrations/20241106191607_reset_strings/migration.sql b/prisma/migrations/20241106191607_reset_strings/migration.sql new file mode 100644 index 0000000..8d6116b --- /dev/null +++ b/prisma/migrations/20241106191607_reset_strings/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "MeetingTime" ALTER COLUMN "beginTime" SET DATA TYPE TEXT, +ALTER COLUMN "endTime" SET DATA TYPE TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 968f9c2..77dc829 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -70,14 +70,14 @@ model MeetingsFaculty { model MeetingTime { id Int @id @default(autoincrement()) - beginTime String + beginTime String? building String buildingDescription String room String category String courseReferenceNumber String @unique endDate String - endTime String + endTime String? startDate String hoursWeek Float meetingType String