multiple schedule suppport kinda
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import { bMessenger } from 'src/shared/messages';
|
||||
import { userScheduleStore } from 'src/shared/storage/userScheduleStore';
|
||||
import { Course } from 'src/shared/types/Course';
|
||||
import { UserSchedule } from 'src/shared/types/UserSchedule';
|
||||
import { Button } from 'src/views/components/common/Button/Button';
|
||||
import Card from 'src/views/components/common/Card/Card';
|
||||
import Icon from 'src/views/components/common/Icon/Icon';
|
||||
@@ -8,6 +10,7 @@ import Text from 'src/views/components/common/Text/Text';
|
||||
import styles from './CourseButtons.module.scss';
|
||||
|
||||
type Props = {
|
||||
activeSchedule?: UserSchedule;
|
||||
course: Course;
|
||||
};
|
||||
|
||||
@@ -17,7 +20,7 @@ const { openNewTab } = bMessenger;
|
||||
* This component displays the buttons for the course info popup, that allow the user to either
|
||||
* navigate to other pages that are useful for the course, or to do actions on the current course.
|
||||
*/
|
||||
export default function CourseButtons({ course }: Props) {
|
||||
export default function CourseButtons({ course, activeSchedule }: Props) {
|
||||
const openRateMyProfessorURL = () => {
|
||||
const primaryInstructor = course.instructors?.[0];
|
||||
if (!primaryInstructor) return;
|
||||
@@ -61,6 +64,17 @@ export default function CourseButtons({ course }: Props) {
|
||||
openNewTab({ url: url.toString() });
|
||||
};
|
||||
|
||||
const saveCourse = async () => {
|
||||
const schedules = await userScheduleStore.get('schedules');
|
||||
const active = schedules.find(schedule => schedule.id === activeSchedule?.id);
|
||||
|
||||
if (!active) return;
|
||||
|
||||
active.addCourse(course);
|
||||
|
||||
await userScheduleStore.set('schedules', schedules);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Button
|
||||
@@ -86,7 +100,7 @@ export default function CourseButtons({ course }: Props) {
|
||||
</Text>
|
||||
<Icon className={styles.icon} color='white' name='collections_bookmark' size='medium' />
|
||||
</Button>
|
||||
<Button type='success' className={styles.button}>
|
||||
<Button disabled={!activeSchedule} onClick={saveCourse} type='success' className={styles.button}>
|
||||
<Text size='medium' weight='regular' color='white'>
|
||||
Save
|
||||
</Text>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Course } from 'src/shared/types/Course';
|
||||
import { UserSchedule } from 'src/shared/types/UserSchedule';
|
||||
import Card from 'src/views/components/common/Card/Card';
|
||||
import Divider from 'src/views/components/common/Divider/Divider';
|
||||
import Icon from 'src/views/components/common/Icon/Icon';
|
||||
@@ -10,6 +11,7 @@ import styles from './CourseHeader.module.scss';
|
||||
|
||||
type Props = {
|
||||
course: Course;
|
||||
activeSchedule?: UserSchedule;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
@@ -17,7 +19,7 @@ type Props = {
|
||||
* This component displays the header of the course info popup.
|
||||
* It displays the course name, unique id, instructors, and schedule, all formatted nicely.
|
||||
*/
|
||||
export default function CourseHeader({ course, onClose }: Props) {
|
||||
export default function CourseHeader({ course, activeSchedule, onClose }: Props) {
|
||||
const getBuildingUrl = (building?: string): string | undefined => {
|
||||
if (!building) return undefined;
|
||||
return `https://utdirect.utexas.edu/apps/campus/buildings/nlogon/maps/UTM/${building}/`;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Course } from 'src/shared/types/Course';
|
||||
import { UserSchedule } from 'src/shared/types/UserSchedule';
|
||||
import Popup from '../../common/Popup/Popup';
|
||||
import CourseDescription from './CourseDescription/CourseDescription';
|
||||
import CourseHeader from './CourseHeader/CourseHeader';
|
||||
@@ -8,16 +9,17 @@ import GradeDistribution from './GradeDistribution/GradeDistribution';
|
||||
|
||||
interface Props {
|
||||
course: Course;
|
||||
activeSchedule?: UserSchedule;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The popup that appears when the user clicks on a course for more details.
|
||||
*/
|
||||
export default function CoursePopup({ course, onClose }: Props) {
|
||||
export default function CoursePopup({ course, activeSchedule, onClose }: Props) {
|
||||
return (
|
||||
<Popup className={styles.popup} overlay onClose={onClose}>
|
||||
<CourseHeader course={course} onClose={onClose} />
|
||||
<CourseHeader course={course} activeSchedule={activeSchedule} onClose={onClose} />
|
||||
<CourseDescription course={course} />
|
||||
<GradeDistribution course={course} />
|
||||
</Popup>
|
||||
|
||||
@@ -137,6 +137,7 @@ export default function GradeDistribution({ course }: Props) {
|
||||
useEffect(() => {
|
||||
queryAggregateDistribution(course)
|
||||
.then(([distribution, semesters]) => {
|
||||
console.log('.then -> distribution, semesters:', distribution, semesters);
|
||||
setSemesters(semesters);
|
||||
updateChart(distribution);
|
||||
setStatus(DataStatus.FOUND);
|
||||
|
||||
@@ -16,23 +16,8 @@ const RECRUIT_FROM_DEPARTMENTS = ['C S', 'ECE', 'MIS', 'CSE', 'EE', 'ITD'];
|
||||
export default function RecruitmentBanner() {
|
||||
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
const shouldShowBanner = (): boolean => {
|
||||
const params = ['fos_fl', 'fos_cn'];
|
||||
let department = '';
|
||||
params.forEach(p => {
|
||||
const param = new URLSearchParams(window.location.search).get(p);
|
||||
if (param) {
|
||||
department = param;
|
||||
}
|
||||
});
|
||||
if (!department) {
|
||||
return false;
|
||||
}
|
||||
return RECRUIT_FROM_DEPARTMENTS.includes(department);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldShowBanner()) {
|
||||
if (!canRecruitFrom()) {
|
||||
return;
|
||||
}
|
||||
const container = document.createElement('div');
|
||||
@@ -64,3 +49,18 @@ export default function RecruitmentBanner() {
|
||||
container
|
||||
);
|
||||
}
|
||||
|
||||
export function canRecruitFrom(): boolean {
|
||||
const params = ['fos_fl', 'fos_cn'];
|
||||
let department = '';
|
||||
params.forEach(p => {
|
||||
const param = new URLSearchParams(window.location.search).get(p);
|
||||
if (param) {
|
||||
department = param;
|
||||
}
|
||||
});
|
||||
if (!department) {
|
||||
return false;
|
||||
}
|
||||
return RECRUIT_FROM_DEPARTMENTS.includes(department);
|
||||
}
|
||||
|
||||
@@ -11,3 +11,10 @@
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.inActiveSchedule {
|
||||
* {
|
||||
color: $turtle_pond !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,17 @@ interface Props {
|
||||
isSelected: boolean;
|
||||
row: ScrapedRow;
|
||||
onClick: (...args: any[]) => any;
|
||||
/**
|
||||
* Whether the course is in the user' active schedule.
|
||||
*/
|
||||
isInActiveSchedule: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* This component is injected into each row of the course catalog table.
|
||||
* @returns a react portal to the new td in the column or null if the column has not been created yet.
|
||||
*/
|
||||
export default function TableRow({ row, isSelected, onClick }: Props): JSX.Element | null {
|
||||
export default function TableRow({ row, isSelected, isInActiveSchedule, onClick }: Props): JSX.Element | null {
|
||||
const [container, setContainer] = useState<HTMLTableCellElement | null>(null);
|
||||
|
||||
const { element, course } = row;
|
||||
@@ -35,6 +39,10 @@ export default function TableRow({ row, isSelected, onClick }: Props): JSX.Eleme
|
||||
element.classList[isSelected ? 'add' : 'remove'](styles.selectedRow);
|
||||
}, [isSelected, element.classList]);
|
||||
|
||||
useEffect(() => {
|
||||
element.classList[isInActiveSchedule ? 'add' : 'remove'](styles.inActiveSchedule);
|
||||
}, [isInActiveSchedule, element.classList]);
|
||||
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user