From e8ea7afe961008bd046f9afc2c05e0d821f6932c Mon Sep 17 00:00:00 2001 From: Dennis Wang <66754085+hellolol2016@users.noreply.github.com> Date: Thu, 26 Sep 2024 18:09:41 -0400 Subject: [PATCH 01/18] Transfer credits now add up to total credits on sidebar (#746) * transfer credits now add up to total credits on sidebar * changed totalcreditsinschedule function to take in transfer credit courses and calculate everything transferred the calculation logic into the totalcreditsinschedule function --- README.md | 2 ++ packages/frontend/components/Sidebar/Sidebar.tsx | 12 ++++++++++-- packages/frontend/pages/home.tsx | 8 +++++++- packages/frontend/utils/plan/totalCredits.ts | 15 +++++++++++---- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ea37e1e09..0810536e8 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ GraduateNU aims to empower Northeastern students to customize their plan of stud 5. Then run the new version of the application by running `yarn dev` at the root of the project. This starts up a NestJS server + a NextJS frontend + a Proxy. The proxy listens on port [3002](http://localhost:3002/), forwards /api requests to the NestJS server running on port 3001, and all other requests to the frontend running on port 3000. +5a. For Windows machines, run `yarn concurrently "yarn workspaces foreach --parallel --verbose --interlaced run dev" "yarn dev:proxy"` instead of `yarn dev` + 6. Visit [http://localhost:3002](http://localhost:3002/) to view the app. To run the two separately, visit the frontend and api packages(sub directories of the monorepo). diff --git a/packages/frontend/components/Sidebar/Sidebar.tsx b/packages/frontend/components/Sidebar/Sidebar.tsx index 0ed90ce3e..7dcdea330 100644 --- a/packages/frontend/components/Sidebar/Sidebar.tsx +++ b/packages/frontend/components/Sidebar/Sidebar.tsx @@ -192,7 +192,10 @@ const Sidebar: React.FC = memo( concentrationValidationStatus = SidebarValidationStatus.Error; } - const creditsTaken = totalCreditsInSchedule(selectedPlan.schedule); + const creditsTaken = totalCreditsInSchedule( + selectedPlan.schedule, + transferCourses + ); return ( = memo( interface NoMajorSidebarProps { selectedPlan: PlanModel; + transferCourses: ScheduleCourse2[]; } export const NoMajorSidebar: React.FC = ({ selectedPlan, + transferCourses, }) => { - const creditsTaken = totalCreditsInSchedule(selectedPlan.schedule); + const creditsTaken = totalCreditsInSchedule( + selectedPlan.schedule, + transferCourses + ); return ( { transferCourses={student.coursesTransfered || []} /> ); - } else renderedSidebar = ; + } else + renderedSidebar = ( + + ); } return ( diff --git a/packages/frontend/utils/plan/totalCredits.ts b/packages/frontend/utils/plan/totalCredits.ts index 8b95603f2..22e3dc86d 100644 --- a/packages/frontend/utils/plan/totalCredits.ts +++ b/packages/frontend/utils/plan/totalCredits.ts @@ -1,4 +1,9 @@ -import { Schedule2, ScheduleTerm2, ScheduleYear2 } from "@graduate/common"; +import { + Schedule2, + ScheduleCourse2, + ScheduleTerm2, + ScheduleYear2, +} from "@graduate/common"; /** The credits for all courses in a term. */ export const totalCreditsInTerm = (term: ScheduleTerm2): number => { @@ -23,12 +28,14 @@ export const totalCreditsInYear = ( /** The credits for all courses in a schedule summed. */ export const totalCreditsInSchedule = ( - schedule: Schedule2 + schedule: Schedule2, + transfer: ScheduleCourse2[] ): number => { return ( - schedule.years.reduce( + (schedule.years.reduce( (totalCredits, year) => totalCreditsInYear(year) + totalCredits, 0 - ) ?? 0 + ) ?? 0) + + (transfer.reduce((sum, course) => course.numCreditsMin + sum, 0) ?? 0) ); }; From df4af6c33b436c78531aac0b98b3f95838eb302b Mon Sep 17 00:00:00 2001 From: Jake Langlois Date: Thu, 10 Oct 2024 22:24:47 -0400 Subject: [PATCH 02/18] made in progress display for a section once it is in progress --- package.json | 1 + packages/common/src/major2-validation.ts | 1 + packages/common/src/test.js | 0 packages/common/src/types.ts | 1 - .../components/Sidebar/NUPathSection.tsx | 21 ++++++++++++++- .../frontend/components/Sidebar/Sidebar.tsx | 26 +++++++++++++++++-- .../components/Sidebar/SidebarSection.tsx | 22 +++++++++++++--- yarn.lock | 11 ++++++++ 8 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 packages/common/src/test.js diff --git a/package.json b/package.json index 709cf170c..5e3b41dd4 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@nestjs/axios": "^3.0.2", "@nestjs/terminus": "^10.2.2", "@nestjs/throttler": "^5.0.1", + "chakra-ui-ionicons": "^0.3.3", "cross-env": "^7.0.3", "fuse.js": "^7.0.0", "nodemailer": "^6.9.1" diff --git a/packages/common/src/major2-validation.ts b/packages/common/src/major2-validation.ts index f632d9db9..ec79abb82 100644 --- a/packages/common/src/major2-validation.ts +++ b/packages/common/src/major2-validation.ts @@ -66,6 +66,7 @@ type CourseError = { type: typeof MajorValidationErrorType.Course; requiredCourse: string; }; + export const CourseError = (c: IRequiredCourse): CourseError => ({ type: MajorValidationErrorType.Course, requiredCourse: courseToString(c), diff --git a/packages/common/src/test.js b/packages/common/src/test.js new file mode 100644 index 000000000..e69de29bb diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index 4cbee12fa..79d200119 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -181,7 +181,6 @@ export type Requirement2 = | ICourseRange2 | IRequiredCourse | Section; - /** * Represents a requirement where X number of credits need to be completed from * a list of courses. diff --git a/packages/frontend/components/Sidebar/NUPathSection.tsx b/packages/frontend/components/Sidebar/NUPathSection.tsx index 019015369..1d1e05c76 100644 --- a/packages/frontend/components/Sidebar/NUPathSection.tsx +++ b/packages/frontend/components/Sidebar/NUPathSection.tsx @@ -62,6 +62,11 @@ const NUPathSection: React.FC = ({ if (loading) { validationStatus = SidebarValidationStatus.Loading; + } else if ( + Object.keys(nupathMap).length > 0 && + Object.keys(nupathMap).length < 13 + ) { + validationStatus = SidebarValidationStatus.InProgress; } else if (Object.keys(nupathMap).length === 13 && wiCount >= 2) { // Sidebar is complete if all 13 nupaths have been fulfilled (including 2 writing intensives) validationStatus = SidebarValidationStatus.Complete; @@ -105,11 +110,15 @@ const NUPathSection: React.FC = ({ ? green : validationStatus === SidebarValidationStatus.Error ? grey + : validationStatus === SidebarValidationStatus.InProgress + ? "orange" : "transparent" } borderColor={ validationStatus === SidebarValidationStatus.Complete ? green + : validationStatus === SidebarValidationStatus.InProgress + ? "orange" : grey } color={ @@ -130,7 +139,7 @@ const NUPathSection: React.FC = ({ p="xs" > {/* - The following three icons appear and disappear based on opacity to allow for transitions (if they're conditionally rendered, then transitions can't occur). + The following four icons appear and disappear based on opacity to allow for transitions (if they're conditionally rendered, then transitions can't occur). */} = ({ transition="opacity 0.25s ease" transitionDelay="0.1s" /> + + ... + NUpath Requirements diff --git a/packages/frontend/components/Sidebar/Sidebar.tsx b/packages/frontend/components/Sidebar/Sidebar.tsx index 0ed90ce3e..9917ccbad 100644 --- a/packages/frontend/components/Sidebar/Sidebar.tsx +++ b/packages/frontend/components/Sidebar/Sidebar.tsx @@ -36,6 +36,7 @@ export enum SidebarValidationStatus { Loading = "Loading", Error = "Error", Complete = "Complete", + InProgress = "InProgress", } export const COOP_BLOCK: ScheduleCourse2 = { @@ -106,6 +107,7 @@ const Sidebar: React.FC = memo( concentration: selectedPlan.concentration, requestNumber: currentRequestNum, }; + workerRef.current?.postMessage(validationInfo); }; @@ -188,8 +190,17 @@ const Sidebar: React.FC = memo( let concentrationValidationStatus = SidebarValidationStatus.Complete; if (validationStatus === undefined) { concentrationValidationStatus = SidebarValidationStatus.Loading; - } else if (concentrationValidationError) { + } else if ( + concentrationValidationError && + concentrationValidationError.type === "AND" && + concentrationValidationError.error.type === "AND_UNSAT_CHILD" && + concentrationValidationError.error.childErrors[0].type === "SECTION" && + concentrationValidationError.error.childErrors[0] + .maxPossibleChildCount === 0 + ) { concentrationValidationStatus = SidebarValidationStatus.Error; + } else { + concentrationValidationStatus = SidebarValidationStatus.InProgress; } const creditsTaken = totalCreditsInSchedule(selectedPlan.schedule); @@ -215,10 +226,21 @@ const Sidebar: React.FC = memo( getSectionError(index, validationStatus); let sectionValidationStatus = SidebarValidationStatus.Complete; + if (validationStatus === undefined) { sectionValidationStatus = SidebarValidationStatus.Loading; - } else if (sectionValidationError) { + } else if ( + sectionValidationError && + sectionValidationError.type === "SECTION" && + sectionValidationError.maxPossibleChildCount === 0 + ) { sectionValidationStatus = SidebarValidationStatus.Error; + } else if ( + sectionValidationError && + sectionValidationError.type === "SECTION" && + sectionValidationError.maxPossibleChildCount > 0 + ) { + sectionValidationStatus = SidebarValidationStatus.InProgress; } return ( diff --git a/packages/frontend/components/Sidebar/SidebarSection.tsx b/packages/frontend/components/Sidebar/SidebarSection.tsx index ee9ebddcc..9ad5442f9 100644 --- a/packages/frontend/components/Sidebar/SidebarSection.tsx +++ b/packages/frontend/components/Sidebar/SidebarSection.tsx @@ -5,6 +5,7 @@ import { SmallCloseIcon, WarningTwoIcon, } from "@chakra-ui/icons"; + import { Box, Flex, Spinner, Stack, Text } from "@chakra-ui/react"; import { ScheduleCourse2, Section } from "@graduate/common"; import { useState } from "react"; @@ -85,11 +86,15 @@ const SidebarSection: React.FC = ({ ? green : validationStatus === SidebarValidationStatus.Error ? grey + : validationStatus === SidebarValidationStatus.InProgress + ? "orange" : "transparent" } borderColor={ validationStatus === SidebarValidationStatus.Complete ? green + : validationStatus === SidebarValidationStatus.InProgress + ? "orange" : grey } color={ @@ -101,16 +106,17 @@ const SidebarSection: React.FC = ({ width="18px" height="18px" display="flex" - transition="background 0.25s ease, color 0.25s ease, border 0.25s ease" - transitionDelay="0.1s" alignItems="center" justifyContent="center" + transition="background 0.25s ease, color 0.25s ease, border 0.25s ease" + transitionDelay="0.1s" borderRadius="2xl" mt="4xs" p="xs" + position="relative" > {/* - The following three icons appear and disappear based on opacity to allow for transitions (if they're conditionally rendered, then transitions can't occur). + The following four icons appear and disappear based on opacity to allow for transitions (if they're conditionally rendered, then transitions can't occur). */} = ({ transition="opacity 0.25s ease" transitionDelay="0.1s" /> + + ... + {section.title} diff --git a/yarn.lock b/yarn.lock index 99d7e6a41..7abf37ebb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5903,6 +5903,16 @@ __metadata: languageName: node linkType: hard +"chakra-ui-ionicons@npm:^0.3.3": + version: 0.3.3 + resolution: "chakra-ui-ionicons@npm:0.3.3" + peerDependencies: + "@chakra-ui/react": ^1.0.0 + react: ">=16" + checksum: 23c06650c2f9ffb8283ef1b51dd52e1ed249dd90ac14bbc6ecadae4ee77bd489976d403912f99e39f24d6bc7b76ba831b1c01cb6176eeae760a7d6a818ea3618 + languageName: node + linkType: hard + "chalk@npm:3.0.0, chalk@npm:^3.0.0": version: 3.0.0 resolution: "chalk@npm:3.0.0" @@ -8169,6 +8179,7 @@ __metadata: "@types/nodemailer": ^6.4.7 "@typescript-eslint/eslint-plugin": ^5.15.0 "@typescript-eslint/parser": ^5.15.0 + chakra-ui-ionicons: ^0.3.3 concurrently: ^7.0.0 cross-env: ^7.0.3 eslint: ^8.11.0 From 4defaed1597471667beb289c952aa06e2cbf28d2 Mon Sep 17 00:00:00 2001 From: Kobe Zheng <57577392+KobeZ123@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:04:33 -0400 Subject: [PATCH 03/18] checkbox update (#755) --- packages/frontend/components/Plan/AddPlanModal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend/components/Plan/AddPlanModal.tsx b/packages/frontend/components/Plan/AddPlanModal.tsx index 20ee57181..9a689195c 100644 --- a/packages/frontend/components/Plan/AddPlanModal.tsx +++ b/packages/frontend/components/Plan/AddPlanModal.tsx @@ -335,6 +335,7 @@ export const AddPlanModal: React.FC = ({ Date: Thu, 17 Oct 2024 20:15:27 -0400 Subject: [PATCH 04/18] added link to all draggable courses (#754) * added link to all draggable courses * searchnu results in searchresult component still using hardcoded components :( * removed old link on draggable component * removed unused import * search results include accurate year and season however, a lot of theses more accurate links lead to nothing in nusearch * implemented year params to transfer courses modal * updated search link to include course name rather than subject and classid * swapped out image for chakra ui icon * updated info icon and removed unneeded file --- .../AddCourseModal/AddCourseModal.tsx | 6 +++- .../components/AddCourseModal/NUPathLabel.tsx | 2 +- .../AddCourseModal/SearchResult.tsx | 29 +++++++++++++++-- .../frontend/components/Plan/ScheduleTerm.tsx | 1 + .../components/Plan/TransferCourses.tsx | 11 ++++++- .../ScheduleCourse/ScheduleCourse.tsx | 31 +++++++++++++++++++ packages/frontend/pages/home.tsx | 1 + 7 files changed, 76 insertions(+), 5 deletions(-) diff --git a/packages/frontend/components/AddCourseModal/AddCourseModal.tsx b/packages/frontend/components/AddCourseModal/AddCourseModal.tsx index bf748519a..df7859e93 100644 --- a/packages/frontend/components/AddCourseModal/AddCourseModal.tsx +++ b/packages/frontend/components/AddCourseModal/AddCourseModal.tsx @@ -13,7 +13,7 @@ import { Text, VStack, } from "@chakra-ui/react"; -import { NUPathEnum, ScheduleCourse2 } from "@graduate/common"; +import { NUPathEnum, ScheduleCourse2, SeasonEnum } from "@graduate/common"; import { useState } from "react"; import { useSearchCourses } from "../../hooks"; import { @@ -33,6 +33,7 @@ import { SecondaryButton } from "../Button"; interface AddCourseModalProps { isOpen: boolean; catalogYear?: number; + season: SeasonEnum; addTo: string; /** Function to close the modal UX, returned from the useDisclosure chakra hook */ closeModalDisplay: () => void; @@ -50,6 +51,7 @@ interface AddCourseModalProps { export const AddCourseModal: React.FC = ({ isOpen, catalogYear, + season, addTo, closeModalDisplay, isCourseAlreadyAdded, @@ -227,6 +229,8 @@ export const AddCourseModal: React.FC = ({ (course) => ( = ({ } return ( - + {nuPaths.map((nuPath) => ( ; + year: number | undefined; + season: SeasonEnum; addSelectedCourse: (course: ScheduleCourse2) => Promise; isResultAlreadySelected: boolean; isResultAlreadyAdded: boolean; @@ -17,6 +20,8 @@ interface SearchResultProps { export const SearchResult: React.FC = ({ course, + year, + season, addSelectedCourse, isResultAlreadySelected, isResultAlreadyAdded, @@ -48,6 +53,26 @@ export const SearchResult: React.FC = ({ {course.name} + + + } + color="primary.blue.light.main" + border={0} + colorScheme="primary.blue.light.main" + isRound + size="sm" + pr={1} + isLoading={isSelectingAnotherCourse} + isDisabled={isResultAlreadyAdded || isResultAlreadySelected} + alignSelf="center" + /> + = ({ ))} void; + year: number; } export const TransferCourses: React.FC = ({ isExpanded, toggleExpanded, + year, }) => { const { student, isLoading, mutateStudent } = useStudentWithPlans(); const router = useRouter(); @@ -86,11 +88,13 @@ export const TransferCourses: React.FC = ({ isExpanded={isExpanded} toggleExpanded={toggleExpanded} totalTransferCredits={totalTransferCredits} + year={year} /> {isExpanded && ( )} @@ -102,11 +106,13 @@ interface TransferCoursesBodyProps { updateTransferCourses: ( updateTransferCourses: ScheduleCourse2[] ) => void; + year: number; } const TransferCoursesBody: React.FC = ({ transferCourses, updateTransferCourses, + year, }) => { const { isOpen, onOpen, onClose } = useDisclosure(); @@ -145,6 +151,9 @@ const TransferCoursesBody: React.FC = ({ ))} { return
; }; + +export function getSearchLink( + catalogYear: number, + szn: SeasonEnum, + course: ScheduleCourse2 +): string { + let sznInt = -1; + switch (szn) { + case SeasonEnum.FL: + sznInt = 1; + break; + case SeasonEnum.SP: + sznInt = 3; + break; + case SeasonEnum.S1: + sznInt = 4; + break; + case SeasonEnum.SM: + sznInt = 5; + break; + case SeasonEnum.S2: + sznInt = 6; + break; + default: + sznInt = 1; + } + return `https://searchneu.com/NEU/${catalogYear}${sznInt}${0}/search/${ + course.name + }`; +} diff --git a/packages/frontend/pages/home.tsx b/packages/frontend/pages/home.tsx index f47991840..ea814b256 100644 --- a/packages/frontend/pages/home.tsx +++ b/packages/frontend/pages/home.tsx @@ -313,6 +313,7 @@ const HomePage: NextPage = () => { /> setIsTransferCoursesExpanded(!isTransferCoursesExpanded) From ecf5d9122996a546043019bc9d1f939425a31fc6 Mon Sep 17 00:00:00 2001 From: Suraj Ramchandran <30753067+Suraj-Ram@users.noreply.github.com> Date: Sun, 20 Oct 2024 15:35:09 -0400 Subject: [PATCH 05/18] Started notes section + added logo --- .../frontend/components/Sidebar/Sidebar.tsx | 40 +++++++++++++++---- packages/frontend/public/sandbox_logo.svg | 8 ++++ 2 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 packages/frontend/public/sandbox_logo.svg diff --git a/packages/frontend/components/Sidebar/Sidebar.tsx b/packages/frontend/components/Sidebar/Sidebar.tsx index 7dcdea330..96244630c 100644 --- a/packages/frontend/components/Sidebar/Sidebar.tsx +++ b/packages/frontend/components/Sidebar/Sidebar.tsx @@ -1,4 +1,15 @@ -import { Badge, Box, Flex, Heading, Link, Stack, Text } from "@chakra-ui/react"; +import { + Badge, + Box, + Flex, + Heading, + Link, + Stack, + Text, + Textarea, + VStack, +} from "@chakra-ui/react"; +import { Image } from "@chakra-ui/react"; import { MajorValidationError, MajorValidationResult, @@ -319,13 +330,7 @@ const SidebarContainer: React.FC> = ({ children, }) => { return ( - + {renderBetaMajorBlock && ( @@ -383,6 +388,25 @@ const SidebarContainer: React.FC> = ({ )} {children} + + + + + sandbox logo + + Sandbox Area + + + + Notes + +