Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Class Search Shortcut #1092

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { EventWrapperProps } from 'react-big-calendar';
import { shallow } from 'zustand/shallow';

import type { CalendarEvent } from '$components/Calendar/CourseCalendarEvent';
import { CourseEvent } from '$components/Calendar/CourseCalendarEvent';
import { useQuickSearchForClasses } from '$lib/helpers';
import { useSelectedEventStore } from '$stores/SelectedEventStore';

interface CalendarCourseEventWrapperProps extends EventWrapperProps<CalendarEvent> {
Expand All @@ -15,6 +17,7 @@ interface CalendarCourseEventWrapperProps extends EventWrapperProps<CalendarEven
*/
export const CalendarCourseEventWrapper = ({ children, ...props }: CalendarCourseEventWrapperProps) => {
const ref = useRef<HTMLDivElement>(null);
const quickSearch = useQuickSearchForClasses();

const setSelectedEvent = useSelectedEventStore((state) => state.setSelectedEvent, shallow);

Expand All @@ -23,7 +26,12 @@ export const CalendarCourseEventWrapper = ({ children, ...props }: CalendarCours
e.preventDefault();
e.stopPropagation();

setSelectedEvent(e, props.event);
if (props.event && (e.metaKey || e.ctrlKey)) {
alexespejo marked this conversation as resolved.
Show resolved Hide resolved
const courseInfo = props.event as CourseEvent;
quickSearch(courseInfo.deptValue, courseInfo.courseNumber, courseInfo.term);
} else {
setSelectedEvent(e, props.event);
}
},
[props.event, setSelectedEvent]
);
Expand Down
25 changes: 20 additions & 5 deletions apps/antalmanac/src/components/Calendar/CourseCalendarEvent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Chip, IconButton, Paper, Tooltip } from '@material-ui/core';
import { Chip, IconButton, Paper, Tooltip, Button } from '@material-ui/core';
import { Theme, withStyles } from '@material-ui/core/styles';
import { ClassNameMap, Styles } from '@material-ui/core/styles/withStyles';
import { Delete } from '@material-ui/icons';
import { Delete, Search } from '@material-ui/icons';
import { WebsocSectionFinalExam } from '@packages/antalmanac-types';
import { useEffect, useRef, useCallback } from 'react';
import { Event } from 'react-big-calendar';
Expand All @@ -12,7 +12,7 @@ import CustomEventDialog from '$components/Calendar/Toolbar/CustomEventDialog/';
import ColorPicker from '$components/ColorPicker';
import analyticsEnum, { logAnalytics } from '$lib/analytics';
import buildingCatalogue from '$lib/buildingCatalogue';
import { clickToCopy } from '$lib/helpers';
import { clickToCopy, useQuickSearchForClasses } from '$lib/helpers';
import locationIds from '$lib/location_ids';
import AppStore from '$stores/AppStore';
import { useTimeFormatStore, useThemeStore } from '$stores/SettingsStore';
Expand Down Expand Up @@ -119,6 +119,8 @@ export interface CourseEvent extends CommonCalendarEvent {
isCustomEvent: false;
sectionCode: string;
sectionType: string;
deptValue: string;
courseNumber: string;
term: string;
}

Expand Down Expand Up @@ -163,6 +165,8 @@ const CourseCalendarEvent = (props: CourseCalendarEventProps) => {
}, []);

const { setActiveTab } = useTabStore();
const quickSearch = useQuickSearchForClasses();

const { isMilitaryTime } = useTimeFormatStore();
const isDark = useThemeStore((store) => store.isDark);

Expand All @@ -173,7 +177,8 @@ const CourseCalendarEvent = (props: CourseCalendarEventProps) => {
const { classes, selectedEvent } = props;

if (!selectedEvent.isCustomEvent) {
const { term, instructors, sectionCode, title, finalExam, locations, sectionType } = selectedEvent;
const { term, instructors, sectionCode, title, finalExam, locations, sectionType, deptValue, courseNumber } =
selectedEvent;

let finalExamString = '';

Expand All @@ -193,13 +198,23 @@ const CourseCalendarEvent = (props: CourseCalendarEventProps) => {
}
}

const handleQuickSearch = () => {
quickSearch(deptValue, courseNumber, term);
};

return (
<Paper className={classes.courseContainer} ref={paperRef}>
<div className={classes.titleBar}>
<span className={classes.title}>{`${title} ${sectionType}`}</span>
<Tooltip title="Quick Search">
<Button size="small" onClick={handleQuickSearch}>
<Search fontSize="small" style={{ marginRight: 5 }} />
<span className={classes.title}>{`${title} ${sectionType}`}</span>
</Button>
</Tooltip>
<Tooltip title="Delete">
<IconButton
size="small"
style={{ textDecoration: 'underline' }}
onClick={() => {
props.closePopover();
deleteCourse(sectionCode, term);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,21 @@
import RightPaneStore from '$components/RightPane/RightPaneStore';
import { useCoursePaneStore } from '$stores/CoursePaneStore';
import { useTabStore } from '$stores/TabStore';
import { Search } from '@material-ui/icons';
import { Button } from '@mui/material';
import { AACourse } from '@packages/antalmanac-types';
import { useCallback } from 'react';
import { Link } from 'react-router-dom';

import { useQuickSearchForClasses } from '$lib/helpers';

/**
* Routes the user to the corresponding search result
*/
export function CourseInfoSearchButton({ courseDetails, term }: { courseDetails: AACourse; term: string }) {
const { setActiveTab } = useTabStore();
const { displaySections } = useCoursePaneStore();
const quickSearch = useQuickSearchForClasses();

const { deptCode, courseNumber } = courseDetails;

const handleClick = useCallback(() => {
RightPaneStore.updateFormValue('deptValue', deptCode);
RightPaneStore.updateFormValue('courseNumber', courseNumber);
RightPaneStore.updateFormValue('term', term);

displaySections();
setActiveTab(1);
}, []);

const queryParams = {
term: term,
deptValue: deptCode,
courseNumber: courseNumber,
};

const href = `/?${Object.entries(queryParams)
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join('&')}`;
quickSearch(deptCode, courseNumber, term);
}, [courseNumber, deptCode, term]);

return (
<div>
Expand All @@ -42,8 +24,6 @@ export function CourseInfoSearchButton({ courseDetails, term }: { courseDetails:
size="small"
color="primary"
style={{ minWidth: 'fit-content' }}
to={href}
component={Link}
onClick={handleClick}
>
<Search />
Expand Down
35 changes: 34 additions & 1 deletion apps/antalmanac/src/lib/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { MouseEvent } from 'react';
import { MouseEvent, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';

import { openSnackbar } from '$actions/AppStoreActions';
import RightPaneStore from '$components/RightPane/RightPaneStore';
import { useCoursePaneStore } from '$stores/CoursePaneStore';
import { useTabStore } from '$stores/TabStore';

export const warnMultipleTerms = (terms: Set<string>) => {
openSnackbar(
Expand All @@ -18,4 +22,33 @@ export async function clickToCopy(event: MouseEvent<HTMLElement>, sectionCode: s
openSnackbar('success', 'WebsocSection code copied to clipboard');
}

export function useQuickSearchForClasses() {
const { displaySections, forceUpdate } = useCoursePaneStore();
const { setActiveTab } = useTabStore();
const navigate = useNavigate();

return useCallback(
(deptValue: string, courseNumber: string, termValue: string) => {
const queryParams = {
term: termValue,
deptValue: deptValue,
courseNumber: courseNumber,
};

const href = `/?${Object.entries(queryParams)
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join('&')}`;

RightPaneStore.updateFormValue('deptValue', deptValue);
RightPaneStore.updateFormValue('courseNumber', courseNumber);
RightPaneStore.updateFormValue('term', termValue);
navigate(href, { replace: false });
setActiveTab(1);
displaySections();
forceUpdate();
},
[displaySections, forceUpdate, setActiveTab]
);
}

export const FAKE_LOCATIONS = ['VRTL REMOTE', 'ON LINE', 'TBA'];
2 changes: 2 additions & 0 deletions apps/antalmanac/src/stores/calendarizeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export const calendarizeCourseEvents = (currentCourses: ScheduleCourse[] = []):
color: course.section.color,
term: course.term,
title: `${course.deptCode} ${course.courseNumber}`,
deptValue: course.deptCode,
courseNumber: course.courseNumber,
courseTitle: course.courseTitle,
locations: meeting.bldg.map(getLocation).map((location: Location) => {
return {
Expand Down
6 changes: 6 additions & 0 deletions apps/antalmanac/tests/calendarize-helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ describe('calendarize-helpers', () => {
},
showLocationInfo: false,
isCustomEvent: false,
deptValue: 'placeholderDeptCode',
courseNumber: 'placeholderCourseNumber',
},
{
locations: [],
Expand Down Expand Up @@ -126,6 +128,8 @@ describe('calendarize-helpers', () => {
},
showLocationInfo: false,
isCustomEvent: false,
deptValue: 'placeholderDeptCode',
courseNumber: 'placeholderCourseNumber',
},
{
locations: [],
Expand Down Expand Up @@ -155,6 +159,8 @@ describe('calendarize-helpers', () => {
},
showLocationInfo: false,
isCustomEvent: false,
deptValue: 'placeholderDeptCode',
courseNumber: 'placeholderCourseNumber',
},
];

Expand Down
Loading