Skip to content

Commit

Permalink
feat(frontend): add option to ignore course in progression checks (#1059
Browse files Browse the repository at this point in the history
)

* Add option to ignore course in progression checks

* Fix progression check page

* Remove eslint-disable

* Address PR comments
  • Loading branch information
lhvy authored Aug 15, 2023
1 parent a11ae10 commit 8b2c806
Show file tree
Hide file tree
Showing 16 changed files with 123 additions and 40 deletions.
Binary file modified frontend/src/assets/TermPlannerHelp/unschedule-dark.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/TermPlannerHelp/unschedule-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/TermPlannerHelp/unschedule-light.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/TermPlannerHelp/unschedule-light.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/src/components/PlannerButton/PlannerButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const PlannerButton = ({ course, hasPlannerUpdated }: PlannerButtonProps) => {
isAccurate: course.is_accurate,
isMultiterm: course.is_multiterm,
supressed: false,
ignoreFromProgression: false,
mark: undefined
};
dispatch(addToUnplanned({ courseCode: course.code, courseData }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const QuickAddCartButton = ({ courseCode, planned }: Props) => {
isAccurate: course.is_accurate,
isMultiterm: course.is_multiterm,
supressed: false,
ignoreFromProgression: false,
mark: undefined
};
dispatch(addToUnplanned({ courseCode: course.code, courseData }));
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/pages/ProgressionChecker/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const Dashboard = ({ isLoading, structure, totalUOC, freeElectivesUOC }: Props)

let completedUOC = 0;
Object.keys(courses).forEach((courseCode) => {
if (courses[courseCode]?.plannedFor) {
if (courses[courseCode]?.plannedFor && !courses[courseCode]?.ignoreFromProgression) {
completedUOC +=
courses[courseCode].UOC *
getNumTerms(courses[courseCode].UOC, courses[courseCode].isMultiterm);
Expand All @@ -70,7 +70,11 @@ const Dashboard = ({ isLoading, structure, totalUOC, freeElectivesUOC }: Props)
let currUOC = 0;
// only consider disciplinary component courses
Object.keys(subgroupStructure.courses).forEach((courseCode) => {
if (courses[courseCode]?.plannedFor && currUOC < subgroupStructure.UOC) {
if (
courses[courseCode]?.plannedFor &&
currUOC < subgroupStructure.UOC &&
!courses[courseCode]?.ignoreFromProgression
) {
const courseUOC =
courses[courseCode].UOC *
getNumTerms(courses[courseCode].UOC, courses[courseCode].isMultiterm);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ const { Title } = Typography;
type Props = {
courses: ViewSubgroupCourse[];
view: Views;
title: string;
subheading: string;
description: string;
};

const FreeElectivesSection = ({ courses, view }: Props) => {
const GenericCoursesSection = ({ courses, view, title, subheading, description }: Props) => {
const uoc = courses.reduce(
(sum, course) => sum + (course.UOC ?? 0) * getNumTerms(course.UOC ?? 0, course.isMultiterm),
0
Expand All @@ -22,18 +25,15 @@ const FreeElectivesSection = ({ courses, view }: Props) => {
return (
<Collapsible
title={
<Title level={1} id="Free Electives" className="text">
Free Electives
<Title level={1} id={title} className="text">
{title}
</Title>
}
>
<Title level={4} className="text">
You have {uoc} UOC worth of additional courses planned
You have {uoc} UOC worth of {subheading}
</Title>
<p>
These courses may or may not be counted to your program. Please manually verify your
progression with this information.
</p>
<p>{description}</p>
{view === Views.TABLE ? (
<Table
dataSource={courses.map((c) => ({
Expand All @@ -44,14 +44,10 @@ const FreeElectivesSection = ({ courses, view }: Props) => {
pagination={false}
/>
) : (
<CoursesSection
title="Additional Electives"
plannedCourses={courses}
unplannedCourses={[]}
/>
<CoursesSection title="Courses" plannedCourses={courses} unplannedCourses={[]} />
)}
</Collapsible>
);
};

export default FreeElectivesSection;
export default GenericCoursesSection;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import GenericCoursesSection from './GenericCoursesSection';

export default GenericCoursesSection;
50 changes: 37 additions & 13 deletions frontend/src/pages/ProgressionChecker/ProgressionChecker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import PageTemplate from 'components/PageTemplate';
import { MAX_COURSES_OVERFLOW } from 'config/constants';
import type { RootState } from 'config/store';
import Dashboard from './Dashboard';
import FreeElectiveSection from './FreeElectivesSection';
import GenericCoursesSection from './GenericCoursesSection';
import GridView from './GridView';
import S from './styles';
import TableView from './TableView';
Expand Down Expand Up @@ -76,6 +76,8 @@ const ProgressionChecker = () => {
// these courses are appended as 'Additional Electives'
const overflowCourses: ProgressionAdditionalCourses = {};

const ignoredCourses: ProgressionAdditionalCourses = {};

const generateViewStructure = () => {
// Example groups: Major, Minor, General, Rules
Object.keys(structure).forEach((group) => {
Expand Down Expand Up @@ -106,6 +108,8 @@ const ProgressionChecker = () => {

// only consider disciplinary component courses
Object.keys(subgroupStructure.courses).forEach((courseCode) => {
if (courses[courseCode]?.ignoreFromProgression) return;

const isDoubleCounted =
countedCourses.includes(courseCode) &&
!/Core/.test(subgroup) &&
Expand Down Expand Up @@ -172,17 +176,24 @@ const ProgressionChecker = () => {
.flatMap((spec) => Object.keys(spec.courses))
);
Object.keys(courses).forEach((courseCode) => {
if (!programCourseList.includes(courseCode) && courses[courseCode]?.plannedFor) {
overflowCourses[courseCode] = {
courseCode,
title: courses[courseCode].title,
UOC: courses[courseCode].UOC,
plannedFor: courses[courseCode].plannedFor as string,
isUnplanned: unplanned.includes(courseCode),
isMultiterm: courses[courseCode].isMultiterm,
isDoubleCounted: false,
isOverCounted: false
};
const course = {
courseCode,
title: courses[courseCode].title,
UOC: courses[courseCode].UOC,
plannedFor: courses[courseCode].plannedFor as string,
isUnplanned: unplanned.includes(courseCode),
isMultiterm: courses[courseCode].isMultiterm,
isDoubleCounted: false,
isOverCounted: false
};
if (courses[courseCode]?.plannedFor && courses[courseCode]?.ignoreFromProgression) {
ignoredCourses[courseCode] = course;
} else if (
!programCourseList.includes(courseCode) &&
courses[courseCode]?.plannedFor &&
!courses[courseCode]?.ignoreFromProgression
) {
overflowCourses[courseCode] = course;
}
});
return newViewLayout;
Expand Down Expand Up @@ -280,7 +291,20 @@ const ProgressionChecker = () => {
)}
</Collapsible>
))}
<FreeElectiveSection courses={Object.values(overflowCourses)} view={view} />
<GenericCoursesSection
courses={Object.values(overflowCourses)}
view={view}
title="Free Electives"
subheading="additional courses planned"
description="These courses may or may not be counted to your program. Please manually verify your progression with this information."
/>
<GenericCoursesSection
courses={Object.values(ignoredCourses)}
view={view}
title="Progression Ignored"
subheading="courses ignored from your progression"
description="These courses have been manually ignored from the progression count. You can undo this from the Term Planner page if you wish."
/>
</S.ProgressionViewContainer>
</S.Wrapper>
</PageTemplate>
Expand Down
25 changes: 22 additions & 3 deletions frontend/src/pages/TermPlanner/ContextMenu/ContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@ import { Item, Menu } from 'react-contexify';
import { FaRegCalendarTimes } from 'react-icons/fa';
import { useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { DeleteFilled, EditFilled, InfoCircleFilled } from '@ant-design/icons';
import {
DeleteFilled,
EditFilled,
InfoCircleFilled,
PieChartFilled,
PieChartOutlined
} from '@ant-design/icons';
import EditMarkModal from 'components/EditMarkModal';
import { addTab } from 'reducers/courseTabsSlice';
import { removeCourse, unschedule } from 'reducers/plannerSlice';
import { removeCourse, toggleIgnoreFromProgression, unschedule } from 'reducers/plannerSlice';
import 'react-contexify/ReactContexify.css';

type Props = {
code: string;
plannedFor: string | null;
ignoreFromProgression: boolean;
};

const ContextMenu = ({ code, plannedFor }: Props) => {
const ContextMenu = ({ code, plannedFor, ignoreFromProgression }: Props) => {
const [openModal, setOpenModal] = useState(false);

const dispatch = useDispatch();
Expand All @@ -34,6 +41,9 @@ const ContextMenu = ({ code, plannedFor }: Props) => {
navigate('/course-selector');
dispatch(addTab(code));
};
const handleToggleProgression = () => {
dispatch(toggleIgnoreFromProgression(code));
};

const iconStyle = {
fontSize: '14px',
Expand All @@ -54,6 +64,15 @@ const ContextMenu = ({ code, plannedFor }: Props) => {
<Item onClick={showEditMark}>
<EditFilled style={iconStyle} /> Edit mark
</Item>
{ignoreFromProgression ? (
<Item onClick={handleToggleProgression}>
<PieChartFilled style={iconStyle} /> Acknowledge Progression
</Item>
) : (
<Item onClick={handleToggleProgression}>
<PieChartOutlined style={iconStyle} /> Ignore Progression
</Item>
)}
<Item onClick={handleInfo}>
<InfoCircleFilled style={iconStyle} /> View Info
</Item>
Expand Down
32 changes: 28 additions & 4 deletions frontend/src/pages/TermPlanner/DraggableCourse/DraggableCourse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Suspense } from 'react';
import { useContextMenu } from 'react-contexify';
import { useSelector } from 'react-redux';
import ReactTooltip from 'react-tooltip';
import { InfoCircleOutlined, WarningOutlined } from '@ant-design/icons';
import { InfoCircleOutlined, PieChartOutlined, WarningOutlined } from '@ant-design/icons';
import { Badge, Typography } from 'antd';
import { useTheme } from 'styled-components';
import { Term } from 'types/planner';
Expand Down Expand Up @@ -35,8 +35,17 @@ const DraggableCourse = ({ code, index, term, showMultiCourseBadge }: Props) =>
const { Text } = Typography;

// prereqs are populated in CourseDescription.jsx via course.raw_requirements
const { title, isUnlocked, plannedFor, isLegacy, isAccurate, handbookNote, supressed, mark } =
courses[code];
const {
title,
isUnlocked,
plannedFor,
isLegacy,
isAccurate,
handbookNote,
supressed,
ignoreFromProgression,
mark
} = courses[code];
const warningMessage = courses[code].warnings;

const isOffered = plannedFor
Expand Down Expand Up @@ -118,6 +127,9 @@ const DraggableCourse = ({ code, index, term, showMultiCourseBadge }: Props) =>
style={{ fontSize: '16px', color: theme.warningOutlined.color }}
/>
))}
{ignoreFromProgression && (
<PieChartOutlined style={{ color: theme.infoOutlined.color }} />
)}
<S.CourseLabel>
{isSmall ? (
<Text className="text">{code}</Text>
Expand Down Expand Up @@ -157,7 +169,11 @@ const DraggableCourse = ({ code, index, term, showMultiCourseBadge }: Props) =>
)}
</Draggable>
</Suspense>
<ContextMenu code={code} plannedFor={plannedFor} />
<ContextMenu
code={code}
plannedFor={plannedFor}
ignoreFromProgression={ignoreFromProgression}
/>
{/* display prereq tooltip for all courses. However, if a term is marked as complete
and the course has no warning, then disable the tooltip */}
{isSmall && (
Expand All @@ -177,7 +193,15 @@ const DraggableCourse = ({ code, index, term, showMultiCourseBadge }: Props) =>
// eslint-disable-next-line react/no-danger
<div dangerouslySetInnerHTML={{ __html: handbookNote }} />
)}
{/* TODO: Fix fullstops. example: "48 UoC required in all courses you have 36 This course will not be included ..."
*/}
{!isAccurate ? ' The course info may be inaccurate.' : ''}
{ignoreFromProgression ? ' This course will not be included in your progression.' : ''}
</ReactTooltip>
)}
{ignoreFromProgression && !(!isDragDisabled && shouldHaveWarning) && (
<ReactTooltip id={code} place="bottom">
This course will not be included in your progression.
</ReactTooltip>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,12 @@ const ImportPlannerMenu = () => {
isAccurate: course.is_accurate,
isMultiterm: course.is_multiterm,
supressed: false,
mark: undefined
// TODO: should actually hydrate people's mark
// and also their suppressions and ignoreFromProgression
// Maybe we don't need to worry about this as
// exporting / importing becomes redundant with accounts
ignoreFromProgression: false,
mark: undefined // TODO: WTF?
};

if (plannedCourses.indexOf(course.code) === -1) {
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/reducers/plannerSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ const plannerSlice = createSlice({
state.unplanned.push(courseCode);
}
},
toggleIgnoreFromProgression: (state, action: PayloadAction<string>) => {
const code = action.payload;

if (state.courses[code]) {
state.courses[code].ignoreFromProgression = !state.courses[code].ignoreFromProgression;
}
},
toggleWarnings: (state, action: PayloadAction<CourseStates>) => {
Object.keys(action.payload).forEach((course) => {
if (state.courses[course]) {
Expand Down Expand Up @@ -467,6 +474,7 @@ export const {
addToUnplanned,
setUnplannedCourseToTerm,
setPlannedCourseToTerm,
toggleIgnoreFromProgression,
toggleWarnings,
removeCourse,
removeCourses,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/planner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type PlannerCourse = {
handbookNote: string;
isAccurate: boolean;
supressed: boolean;
ignoreFromProgression: boolean;
isMultiterm: boolean;
mark: Mark;
legacyOfferings?: CourseLegacyOfferings;
Expand Down

0 comments on commit 8b2c806

Please sign in to comment.