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/27] 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 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 02/27] 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 03/27] 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 e5fc6412213944cc8efc0b719d610b08e68be047 Mon Sep 17 00:00:00 2001 From: ShireenKumar Date: Sun, 20 Oct 2024 14:53:31 -0400 Subject: [PATCH 04/27] Created Modal with multiple pages to describe each feature --- package.json | 3 +- .../FullPageModal/FullPageModal.tsx | 95 +++++++++++++++++++ packages/frontend/pages/home.tsx | 46 +++++++++ yarn.lock | 25 +++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 packages/frontend/components/FullPageModal/FullPageModal.tsx diff --git a/package.json b/package.json index 709cf170c..d47f83866 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "@nestjs/throttler": "^5.0.1", "cross-env": "^7.0.3", "fuse.js": "^7.0.0", - "nodemailer": "^6.9.1" + "nodemailer": "^6.9.1", + "universal-cookie": "^7.2.0" }, "devDependencies": { "@babel/cli": "^7.17.6", diff --git a/packages/frontend/components/FullPageModal/FullPageModal.tsx b/packages/frontend/components/FullPageModal/FullPageModal.tsx new file mode 100644 index 000000000..e553b8114 --- /dev/null +++ b/packages/frontend/components/FullPageModal/FullPageModal.tsx @@ -0,0 +1,95 @@ +import React, { useEffect, useState } from "react"; +import { + Button, + Center, + Flex, + Grid, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + Text, + VStack, + useDisclosure, +} from "@chakra-ui/react"; + +interface WhatsNewPopUpProps { + // is model open or not? + isOpen: boolean; + // Closes the modal + onClose: () => void; +} + +export const WhatsNewPopUp: React.FC = ({ + isOpen, + onClose, +}) => { + const [pageNum, setPageNum] = useState(1); + const nextPage = () => setPageNum((prev) => prev + 1); + const prevPage = () => setPageNum((prev) => prev - 1); + const renderPage = () => { + switch (pageNum) { + case 1: + return ( + <> + + NEW PAGE 1 + + these are the new features + + ); + case 2: + return ( + <> + + NEW PAGE 2 + + these are the new features + + ); + case 3: + return ( + <> + + NEW PAGE 3 + + these are the new features + + ); + } + }; + return ( + + + + + Latest Release v26.09.24 + + {renderPage()} + + {pageNum > 1 && ( + + )} + {pageNum < 3 ? ( + + ) : ( + + )} + + + + ); +}; diff --git a/packages/frontend/pages/home.tsx b/packages/frontend/pages/home.tsx index 833ccdc2d..5f60eaa62 100644 --- a/packages/frontend/pages/home.tsx +++ b/packages/frontend/pages/home.tsx @@ -50,6 +50,8 @@ import { getPreReqWarnings, } from "../utils/plan/preAndCoReqCheck"; import { IsGuestContext } from "./_app"; +import { WhatsNewPopUp } from "../components/FullPageModal/FullPageModal"; +import Cookies from "universal-cookie"; // Algorithm to decide which droppable the course is currently over (if any). // See https://docs.dndkit.com/api-documentation/context-provider/collision-detection-algorithms for more info. @@ -66,6 +68,43 @@ const courseDndCollisisonAlgorithm: CollisionDetection = (args) => { const HomePage: NextPage = () => { const { error, student, mutateStudent } = useStudentWithPlans(); const router = useRouter(); + // How we keep track if the modal is open or closed + const [isOpen, setIsOpen] = useState(false); + const cookies = new Cookies(); + // useEffect(() => { + // setIsOpen(true); // Show the modal when the component renders + // }, []); + + // when the modal closes + // useEffect(() => { + // const cookies = new Cookies(); + // const existingToken = cookies.get('FeedbackModal JWT'); + // if (existingToken) { + // setIsOpen(false); // Don't show the modal + // } else { + // setIsOpen(true); + // const newtoken = 'alreadyShowedModal'; + // cookies.set('FeedbackModal JWT', newtoken, { path: '/' }); + // // Show the modal + // } + // }, []); + + useEffect(() => { + const existingToken = cookies.get("FeedbackModal JWT"); + + if (!existingToken) { + setIsOpen(true); // Open modal only if token doesn't exist + } + }, []); + + const handleClose = () => { + setIsOpen(false); // Close the modal when user dismisses it + const cookies = new Cookies(); + const newToken = "alreadyShowedModal"; + cookies.set("FeedbackModal JWT", newToken, { path: "/" }); // Set the token when user closes the modal + }; + + // const onClose = () => setIsOpen(false); /* * Keep track of the plan being displayed, initially undef and later either the plan id or null. @@ -325,6 +364,13 @@ const HomePage: NextPage = () => { /> ) : null} + + setIsOpen(false) + /> ); }; diff --git a/yarn.lock b/yarn.lock index 99d7e6a41..a3066cb94 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4219,6 +4219,13 @@ __metadata: languageName: node linkType: hard +"@types/cookie@npm:^0.6.0": + version: 0.6.0 + resolution: "@types/cookie@npm:0.6.0" + checksum: 5edce7995775b0b196b142883e4d4f71fd93c294eaec973670f1fa2540b70ea7390408ed513ddefef5fcb12a578100c76596e8f2a714b0c2ae9f70ee773f4510 + languageName: node + linkType: hard + "@types/cookiejar@npm:*": version: 2.1.2 resolution: "@types/cookiejar@npm:2.1.2" @@ -6353,6 +6360,13 @@ __metadata: languageName: node linkType: hard +"cookie@npm:^0.6.0": + version: 0.6.0 + resolution: "cookie@npm:0.6.0" + checksum: f56a7d32a07db5458e79c726b77e3c2eff655c36792f2b6c58d351fb5f61531e5b1ab7f46987150136e366c65213cbe31729e02a3eaed630c3bf7334635fb410 + languageName: node + linkType: hard + "cookiejar@npm:^2.1.3": version: 2.1.3 resolution: "cookiejar@npm:2.1.3" @@ -8185,6 +8199,7 @@ __metadata: prettier-plugin-jsdoc: ^0.3.38 pretty-quick: ^3.1.3 typescript: ^4.6.2 + universal-cookie: ^7.2.0 languageName: unknown linkType: soft @@ -13498,6 +13513,16 @@ __metadata: languageName: node linkType: hard +"universal-cookie@npm:^7.2.0": + version: 7.2.0 + resolution: "universal-cookie@npm:7.2.0" + dependencies: + "@types/cookie": ^0.6.0 + cookie: ^0.6.0 + checksum: bf20d7fed9cdeed933e5d03bb2d95c5226edb30eae89cb61e8ab51589ad3340ca79f9dbf790c94db083ac31b0a6e38eb71b70a3cf03d1eaf0a1b00ee2b92b360 + languageName: node + linkType: hard + "universalify@npm:^0.2.0": version: 0.2.0 resolution: "universalify@npm:0.2.0" From 66a758477e230de0d283d5cf4cbb722ad77ebb4d Mon Sep 17 00:00:00 2001 From: ShireenKumar Date: Sun, 20 Oct 2024 14:58:07 -0400 Subject: [PATCH 05/27] Update FullPageModal.tsx --- .../frontend/components/FullPageModal/FullPageModal.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/frontend/components/FullPageModal/FullPageModal.tsx b/packages/frontend/components/FullPageModal/FullPageModal.tsx index e553b8114..49644a764 100644 --- a/packages/frontend/components/FullPageModal/FullPageModal.tsx +++ b/packages/frontend/components/FullPageModal/FullPageModal.tsx @@ -1,19 +1,13 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { Button, - Center, - Flex, - Grid, Modal, ModalBody, - ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Text, - VStack, - useDisclosure, } from "@chakra-ui/react"; interface WhatsNewPopUpProps { 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 06/27] 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 + +