Skip to content

Commit

Permalink
Add hyperlinks to lecturers in schedules card
Browse files Browse the repository at this point in the history
  • Loading branch information
“xavilien” committed Mar 27, 2024
1 parent f17bea0 commit 8daa82f
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 126 deletions.
5 changes: 5 additions & 0 deletions frontend/src/app/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface UserState {
bookmarked: string[];
showFCEs: boolean;
showCourseInfos: boolean;
showSchedules: boolean;
loggedIn: boolean;
fceAggregation: {
numSemesters: number;
Expand All @@ -23,6 +24,7 @@ const initialState: UserState = {
bookmarked: [],
showFCEs: false,
showCourseInfos: true,
showSchedules: false,
loggedIn: false,
fceAggregation: {
numSemesters: 2,
Expand Down Expand Up @@ -54,6 +56,9 @@ export const userSlice = createSlice({
showCourseInfos: (state, action: PayloadAction<boolean>) => {
state.showCourseInfos = action.payload;
},
showSchedules: (state, action: PayloadAction<boolean>) => {
state.showSchedules = action.payload;
},
logIn: (state) => {
state.loggedIn = true;
},
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/components/CourseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import Link from "next/link";
import { selectFCEResultsForCourse } from "../app/cache";
import { FCEDetail } from "./FCEDetail";
import { Card } from "./Card";
import { SchedulesDetail } from "./SchedulesDetail";

interface Props {
info: Course;
showFCEs: boolean;
showCourseInfo?: boolean;
showSchedules?: boolean;
}

const CourseCard = ({ info, showFCEs, showCourseInfo }: Props) => {
const CourseCard = ({ info, showFCEs, showCourseInfo, showSchedules }: Props) => {
const sortedSchedules = filterSessions(info.schedules || []).sort(
compareSessions
);
Expand Down Expand Up @@ -106,7 +108,10 @@ const CourseCard = ({ info, showFCEs, showCourseInfo }: Props) => {
</div>
)}
</div>
{showFCEs && fces && <FCEDetail fces={fces} />}
<div className="m-auto space-y-4">
{showFCEs && fces && <FCEDetail fces={fces} />}
{showSchedules && sortedSchedules && <SchedulesDetail scheduleInfos={sortedSchedules}/>}
</div>
</Card>
);
};
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/CourseSearchList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const CoursePage = () => {

const showFCEs = useAppSelector((state) => state.user.showFCEs);
const showCourseInfos = useAppSelector((state) => state.user.showCourseInfos);
const showSchedules = useAppSelector((state) => state.user.showSchedules);
const loggedIn = useAppSelector((state) => state.user.loggedIn);

const coursesToShow: string[] = useMemo(() => {
Expand Down Expand Up @@ -54,6 +55,7 @@ const CoursePage = () => {
key={course.courseID}
showFCEs={showFCEs}
showCourseInfo={showCourseInfos}
showSchedules={showSchedules}
/>
))}
</div>
Expand Down
126 changes: 3 additions & 123 deletions frontend/src/components/SchedulesCard.tsx
Original file line number Diff line number Diff line change
@@ -1,103 +1,7 @@
import { sessionToString, timeArrToString } from "../app/utils";
import React from "react";
import { Tab } from "@headlessui/react";
import { Lecture, Schedule, Section } from "../app/types";
import { Schedule } from "../app/types";
import { Card } from "./Card";
import Link from "./Link";
import { useAppSelector } from "../app/hooks";

const getInstructors = (instructors: string[]) => {
return (
<>
{instructors.map((instructor, index) => {
if (index === instructors.length - 1) return <Link href={`/instructor/${instructor.toUpperCase()}`}>{instructor}</Link>
return <><Link href={`/instructor/${instructor.toUpperCase()}`}>{instructor}</Link>; </>
})}
</>
)
}

const Lecture = ({
lectureInfo,
sections,
}: {
lectureInfo: Lecture;
sections: Section[];
}) => {
return (
<>
<div className="text-gray-700 contents rounded hover:bg-gray-50">
<div className="text-md col-span-1 pt-2 font-bold">
{lectureInfo.name}
</div>
<div className="col-span-1 text-sm">
{getInstructors(lectureInfo.instructors)}
</div>
<div className="contents flex-col text-sm">
{lectureInfo.times.map((time) => (
<div className="contents" key={timeArrToString([time])}>
<div className="col-span-1 col-start-3">
{timeArrToString([time])}
</div>
<div className="col-span-1">
{time.building} {time.room}
</div>
</div>
))}
</div>
</div>

{sections.map((section) => (
<div
className="text-gray-600 contents hover:bg-gray-50"
key={section.name}
>
<div className="text-md col-span-1 pt-1">{section.name}</div>
<div className="col-span-1 text-sm">
{section.instructors.join("; ")}
</div>
<div className="contents text-sm">
{section.times.map((time) => (
<div className="contents" key={timeArrToString([time])}>
<div className="col-span-1 col-start-3">
{timeArrToString([time])}
</div>
<div className="col-span-1">
{time.building} {time.room}
</div>
</div>
))}
</div>
</div>
))}
</>
);
};

const Schedule = ({ scheduleInfo }: { scheduleInfo: Schedule }) => {
let scheduleDivs;

if (scheduleInfo.lectures.length !== 0) {
scheduleDivs = scheduleInfo.lectures.map((lecture) => (
<Lecture
key={lecture.name}
lectureInfo={lecture}
sections={scheduleInfo.sections.filter(
(section) => section.lecture === lecture.name
)}
/>
));
} else {
scheduleDivs = scheduleInfo.sections.map((section) => (
<Lecture lectureInfo={section} sections={[]} key={section.name} />
));
}
return (
<div className="grid grid-cols-[auto_auto_auto_auto] items-baseline gap-x-4 overflow-x-auto whitespace-nowrap p-2">
{scheduleDivs}
</div>
);
};
import { SchedulesDetail } from "./SchedulesDetail";

export const SchedulesCard = ({
scheduleInfos,
Expand All @@ -107,31 +11,7 @@ export const SchedulesCard = ({
return (
<Card>
<Card.Header>Schedules</Card.Header>
<Tab.Group>
<Tab.List className="bg-gray-50 mt-2 space-x-1 overflow-x-auto whitespace-nowrap rounded p-2">
{scheduleInfos.map((scheduleInfo) => {
const label = sessionToString(scheduleInfo);
return (
<Tab
key={label}
className={({ selected }) =>
"text-gray-800 inline-block rounded px-2 py-1 text-sm hover:bg-white " +
(selected ? "bg-white" : "")
}
>
{label}
</Tab>
);
})}
</Tab.List>
<Tab.Panels>
{scheduleInfos.map((scheduleInfo) => (
<Tab.Panel key={sessionToString(scheduleInfo)}>
<Schedule scheduleInfo={scheduleInfo} />
</Tab.Panel>
))}
</Tab.Panels>
</Tab.Group>
<SchedulesDetail scheduleInfos={scheduleInfos}/>
</Card>
);
};
132 changes: 132 additions & 0 deletions frontend/src/components/SchedulesDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { sessionToString, timeArrToString } from "../app/utils";
import React from "react";
import { Tab } from "@headlessui/react";
import { Lecture, Schedule, Section } from "../app/types";
import Link from "./Link";

const getInstructors = (instructors: string[]) => {
return (
<>
{instructors.map((instructor, index) => {
if (index === instructors.length - 1) return <Link href={`/instructor/${instructor.toUpperCase()}`}>{instructor}</Link>
return <><Link href={`/instructor/${instructor.toUpperCase()}`}>{instructor}</Link>; </>
})}
</>
)
}

const Lecture = ({
lectureInfo,
sections,
}: {
lectureInfo: Lecture;
sections: Section[];
}) => {
return (
<>
<div className="text-gray-700 contents rounded hover:bg-gray-50">
<div className="text-md col-span-1 pt-2 font-bold">
{lectureInfo.name}
</div>
<div className="col-span-1 text-sm">
{getInstructors(lectureInfo.instructors)}
</div>
<div className="contents flex-col text-sm">
{lectureInfo.times.map((time) => (
<div className="contents" key={timeArrToString([time])}>
<div className="col-span-1 col-start-3">
{timeArrToString([time])}
</div>
<div className="col-span-1">
{time.building} {time.room}
</div>
</div>
))}
</div>
</div>

{sections.map((section) => (
<div
className="text-gray-600 contents hover:bg-gray-50"
key={section.name}
>
<div className="text-md col-span-1 pt-1">{section.name}</div>
<div className="col-span-1 text-sm">
{section.instructors.join("; ")}
</div>
<div className="contents text-sm">
{section.times.map((time) => (
<div className="contents" key={timeArrToString([time])}>
<div className="col-span-1 col-start-3">
{timeArrToString([time])}
</div>
<div className="col-span-1">
{time.building} {time.room}
</div>
</div>
))}
</div>
</div>
))}
</>
);
};

const Schedule = ({ scheduleInfo }: { scheduleInfo: Schedule }) => {
let scheduleDivs;

if (scheduleInfo.lectures.length !== 0) {
scheduleDivs = scheduleInfo.lectures.map((lecture) => (
<Lecture
key={lecture.name}
lectureInfo={lecture}
sections={scheduleInfo.sections.filter(
(section) => section.lecture === lecture.name
)}
/>
));
} else {
scheduleDivs = scheduleInfo.sections.map((section) => (
<Lecture lectureInfo={section} sections={[]} key={section.name} />
));
}
return (
<div className="grid grid-cols-[auto_auto_auto_auto] items-baseline gap-x-4 overflow-x-auto whitespace-nowrap p-2">
{scheduleDivs}
</div>
);
};

export const SchedulesDetail = ({
scheduleInfos,
}: {
scheduleInfos: Schedule[];
}) => {
return (
<Tab.Group>
<Tab.List className="bg-gray-50 mt-2 space-x-1 overflow-x-auto whitespace-nowrap rounded p-2">
{scheduleInfos.map((scheduleInfo) => {
const label = sessionToString(scheduleInfo);
return (
<Tab
key={label}
className={({ selected }) =>
"text-gray-800 inline-block rounded px-2 py-1 text-sm hover:bg-white " +
(selected ? "bg-white" : "")
}
>
{label}
</Tab>
);
})}
</Tab.List>
<Tab.Panels>
{scheduleInfos.map((scheduleInfo) => (
<Tab.Panel key={sessionToString(scheduleInfo)}>
<Schedule scheduleInfo={scheduleInfo} />
</Tab.Panel>
))}
</Tab.Panels>
</Tab.Group>
);
};
16 changes: 15 additions & 1 deletion frontend/src/components/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ const SearchBar = () => {
const loggedIn = useAppSelector((state) => state.user.loggedIn);
const showFCEs = useAppSelector((state) => state.user.showFCEs);
const showCourseInfos = useAppSelector((state) => state.user.showCourseInfos);
const showSchedules = useAppSelector((state) => state.user.showSchedules);

const setShowFCEs = (e: React.ChangeEvent<HTMLInputElement>) => {
dispatch(userSlice.actions.showFCEs(e.target.checked));
Expand All @@ -151,6 +152,10 @@ const SearchBar = () => {
dispatch(userSlice.actions.showCourseInfos(e.target.checked));
};

const setShowSchedules = (e: React.ChangeEvent<HTMLInputElement>) => {
dispatch(userSlice.actions.showSchedules(e.target.checked));
};

const numResults = useAppSelector((state) => state.cache.totalDocs);

return (
Expand Down Expand Up @@ -182,7 +187,7 @@ const SearchBar = () => {
/>
<span>FCEs</span>
</div>
<div>
<div className="mr-6">
<input
type="checkbox"
className="mr-2"
Expand All @@ -191,6 +196,15 @@ const SearchBar = () => {
/>
<span>Course Info</span>
</div>
<div>
<input
type="checkbox"
className="mr-2"
onChange={setShowSchedules}
checked={showSchedules}
/>
<span>Schedules</span>
</div>
</div>
</div>
<div className="text-gray-500 mt-2">
Expand Down

0 comments on commit 8daa82f

Please sign in to comment.