Skip to content

Commit

Permalink
Merge branch 'demo-20241110-branch' into shireen-jake-generic-course
Browse files Browse the repository at this point in the history
  • Loading branch information
KobeZ123 authored Nov 10, 2024
2 parents 87d8b89 + 8faae11 commit 1ee62bb
Show file tree
Hide file tree
Showing 25 changed files with 788 additions and 143 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
"@nestjs/throttler": "^5.0.1",
"cross-env": "^7.0.3",
"fuse.js": "^7.0.0",
"nodemailer": "^6.9.1"
"nodemailer": "^6.9.1",
"react-icons": "^5.3.0",
"universal-cookie": "^7.2.0"
},
"devDependencies": {
"@babel/cli": "^7.17.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand All @@ -50,6 +51,7 @@ interface AddCourseModalProps {
export const AddCourseModal: React.FC<AddCourseModalProps> = ({
isOpen,
catalogYear,
season,
addTo,
closeModalDisplay,
isCourseAlreadyAdded,
Expand Down Expand Up @@ -227,6 +229,8 @@ export const AddCourseModal: React.FC<AddCourseModalProps> = ({
(course) => (
<SearchResult
key={getCourseDisplayString(course)}
year={catalogYear}
season={season}
course={course}
addSelectedCourse={addSelectedCourse}
isResultAlreadyAdded={isCourseAlreadyAdded(course)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const NUPathLabel: React.FC<NuPathLabelProps> = ({
}

return (
<Flex justifyContent="end" gap="2xs" flex="1" ml="xs">
<Flex justifyContent="end" gap="2xs" ml="xs">
{nuPaths.map((nuPath) => (
<Flex
key={nuPaths.indexOf(nuPath)}
Expand Down
32 changes: 30 additions & 2 deletions packages/frontend/components/AddCourseModal/SearchResult.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { AddIcon } from "@chakra-ui/icons";
import { AddIcon, InfoOutlineIcon } from "@chakra-ui/icons";
import { Box, Flex, IconButton, Text } from "@chakra-ui/react";
import { NUPathEnum, ScheduleCourse2 } from "@graduate/common";
import { NUPathEnum, ScheduleCourse2, SeasonEnum } from "@graduate/common";
import { getCourseDisplayString } from "../../utils/";
import { GraduateToolTip } from "../GraduateTooltip";
import { NUPathLabel } from "./NUPathLabel";
import { getSearchLink } from "../ScheduleCourse";

interface SearchResultProps {
course: ScheduleCourse2<null>;
year: number | undefined;
season: SeasonEnum;
addSelectedCourse: (course: ScheduleCourse2<null>) => Promise<void>;
isResultAlreadySelected: boolean;
isResultAlreadyAdded: boolean;
Expand All @@ -17,6 +20,8 @@ interface SearchResultProps {

export const SearchResult: React.FC<SearchResultProps> = ({
course,
year,
season,
addSelectedCourse,
isResultAlreadySelected,
isResultAlreadyAdded,
Expand Down Expand Up @@ -48,6 +53,29 @@ export const SearchResult: React.FC<SearchResultProps> = ({
{course.name}
</Text>
</Box>
<Box ml="auto" mr="sm"></Box>
<GraduateToolTip
label={`Search for ${getCourseDisplayString(course)} on SearchNEU`}
>
<a
href={getSearchLink(year ?? 2022, season, course)}
target="_blank"
rel="noreferrer"
>
<IconButton
aria-label="Search course information"
icon={<InfoOutlineIcon />}
color="primary.blue.light.main"
border={0}
colorScheme="primary.blue.light.main"
isRound
size="md"
isLoading={isSelectingAnotherCourse}
isDisabled={isResultAlreadyAdded || isResultAlreadySelected}
alignSelf="center"
/>
</a>
</GraduateToolTip>
<NUPathLabel
nuPaths={course.nupaths ? course.nupaths : []}
filteredPaths={filteredPaths}
Expand Down
73 changes: 48 additions & 25 deletions packages/frontend/components/Header/GraduateHeaders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ import {
useMediaQuery,
} from "@chakra-ui/react";
import { MetaInfoWidget } from "../MetaInfo/MetaInfo";
import { HamburgerIcon } from "@chakra-ui/icons";
import { HamburgerIcon, RepeatClockIcon } from "@chakra-ui/icons";
import {
useWhatsNewModal,
WhatsNewModalContextProvider,
} from "../WhatsNewModal/WhatsNewModalContextProvider";
import { MdChatBubbleOutline, MdOutlineBugReport } from "react-icons/md";

export const GraduatePreAuthHeader: React.FC = () => {
const [isMobile] = useMediaQuery("(max-width: 640px)");
Expand Down Expand Up @@ -46,16 +51,50 @@ interface GraduateHeaderProps {
}

const GraduateHeader: React.FC<GraduateHeaderProps> = ({ rightContent }) => {
return (
<WhatsNewModalContextProvider>
<GraduateHeaderContent rightContent={rightContent} />
</WhatsNewModalContextProvider>
);
};

const GraduateHeaderContent: React.FC<GraduateHeaderProps> = ({
rightContent,
}) => {
const { openModal } = useWhatsNewModal();

return (
<HeaderContainer>
<Logo />
<Flex columnGap="md" alignItems="center">
<MetaInfoWidget />
<ChakraLink href="https://forms.gle/uXDfLFWvgCiYcqgf9" isExternal>
<Flex
onClick={() => {
openModal();
}}
cursor="pointer"
_hover={{ textDecoration: "underline" }}
wrap="wrap"
alignItems="center"
>
<LatestReleaseNotesIcon mx="4px" />
<Text>Latest Release Notes</Text>
</Flex>
<ChakraLink
href="https://forms.gle/uXDfLFWvgCiYcqgf9"
isExternal
display="inline-flex"
alignItems="center"
>
<FeedbackIcon mx="2px" />
Feedback
</ChakraLink>
<ChakraLink href="https://forms.gle/bXgRXyYTXN8wgYy78" isExternal>
<ChakraLink
href="https://forms.gle/bXgRXyYTXN8wgYy78"
isExternal
display="inline-flex"
alignItems="center"
>
<BugIcon mx="2px" />
Bug/Feature
</ChakraLink>
Expand Down Expand Up @@ -128,32 +167,16 @@ const MobileHeader: React.FC = () => {
);
};

const LatestReleaseNotesIcon: React.FC<IconProps> = (props) => {
return <RepeatClockIcon height="16px" width="16px" {...props} />;
};

const FeedbackIcon: React.FC<IconProps> = (props) => {
return (
<Icon
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
className="w-6 h-6"
{...props}
>
<path d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 01.865-.501 48.172 48.172 0 003.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z" />
</Icon>
<Icon as={MdChatBubbleOutline} height="20px" width="20px" {...props} />
);
};

const BugIcon: React.FC<IconProps> = (props) => {
return (
<Icon
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
className="w-6 h-6"
{...props}
>
<path d="M12 12.75c1.148 0 2.278.08 3.383.237 1.037.146 1.866.966 1.866 2.013 0 3.728-2.35 6.75-5.25 6.75S6.75 18.728 6.75 15c0-1.046.83-1.867 1.866-2.013A24.204 24.204 0 0112 12.75zm0 0c2.883 0 5.647.508 8.207 1.44a23.91 23.91 0 01-1.152 6.06M12 12.75c-2.883 0-5.647.508-8.208 1.44.125 2.104.52 4.136 1.153 6.06M12 12.75a2.25 2.25 0 002.248-2.354M12 12.75a2.25 2.25 0 01-2.248-2.354M12 8.25c.995 0 1.971-.08 2.922-.236.403-.066.74-.358.795-.762a3.778 3.778 0 00-.399-2.25M12 8.25c-.995 0-1.97-.08-2.922-.236-.402-.066-.74-.358-.795-.762a3.734 3.734 0 01.4-2.253M12 8.25a2.25 2.25 0 00-2.248 2.146M12 8.25a2.25 2.25 0 012.248 2.146M8.683 5a6.032 6.032 0 01-1.155-1.002c.07-.63.27-1.222.574-1.747m.581 2.749A3.75 3.75 0 0115.318 5m0 0c.427-.283.815-.62 1.155-.999a4.471 4.471 0 00-.575-1.752M4.921 6a24.048 24.048 0 00-.392 3.314c1.668.546 3.416.914 5.223 1.082M19.08 6c.205 1.08.337 2.187.392 3.314a23.882 23.882 0 01-5.223 1.082" />
</Icon>
);
return <Icon as={MdOutlineBugReport} height="20px" width="20px" {...props} />;
};
11 changes: 3 additions & 8 deletions packages/frontend/components/MetaInfo/MetaInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Box, Flex, Icon, Link, Text, Tooltip } from "@chakra-ui/react";
import { UpDownIcon } from "@chakra-ui/icons";
import { Box, Flex, Link, Text, Tooltip } from "@chakra-ui/react";
import { API } from "@graduate/api-client";
import { Maybe } from "@graduate/common";
import { useState } from "react";
Expand Down Expand Up @@ -71,13 +72,7 @@ export const MetaInfoWidget: React.FC = () => {
transition="background 0.15s ease"
userSelect="none"
>
<Icon
xmlns="http://www.w3.org/2000/svg"
fill="black"
viewBox="0 0 24 24"
>
<path d="M14.6,16.6L19.2,12L14.6,7.4L16,6L22,12L16,18L14.6,16.6M9.4,16.6L4.8,12L9.4,7.4L8,6L2,12L8,18L9.4,16.6Z"></path>
</Icon>
<UpDownIcon transform="rotate(90deg)" />
{process.env.NODE_ENV === "development" && <Text>Dev</Text>}
</Flex>
{
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/components/Plan/AddPlanModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ export const AddPlanModal: React.FC<AddPlanModalProps> = ({
<Flex alignItems="center">
<Checkbox
mr="md"
borderColor="primary.blue.dark.main"
{...register("agreeToBetaMajor", {
required: "You must agree to continue",
})}
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/components/Plan/ScheduleTerm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const ScheduleTerm: React.FC<ScheduleTermProps> = ({
))}
<AddCourseButton onOpen={onOpen} />
<AddCourseModal
season={scheduleTerm.season}
isOpen={isOpen}
catalogYear={catalogYear}
addTo={getSeasonDisplayWord(scheduleTerm.season)}
Expand Down
11 changes: 10 additions & 1 deletion packages/frontend/components/Plan/TransferCourses.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChevronDownIcon, ChevronUpIcon } from "@chakra-ui/icons";
import { Flex, Grid, Stack, Text, useDisclosure } from "@chakra-ui/react";
import { API } from "@graduate/api-client";
import { ScheduleCourse2, StudentModel } from "@graduate/common";
import { ScheduleCourse2, SeasonEnum, StudentModel } from "@graduate/common";
import { useRouter } from "next/router";
import { fetchStudentAndPrepareForDnd, useStudentWithPlans } from "../../hooks";
import {
Expand All @@ -19,11 +19,13 @@ import { IsGuestContext } from "../../pages/_app";
interface TransferCoursesToggleProps {
isExpanded: boolean;
toggleExpanded: () => void;
year: number;
}

export const TransferCourses: React.FC<TransferCoursesToggleProps> = ({
isExpanded,
toggleExpanded,
year,
}) => {
const { student, isLoading, mutateStudent } = useStudentWithPlans();
const router = useRouter();
Expand Down Expand Up @@ -86,11 +88,13 @@ export const TransferCourses: React.FC<TransferCoursesToggleProps> = ({
isExpanded={isExpanded}
toggleExpanded={toggleExpanded}
totalTransferCredits={totalTransferCredits}
year={year}
/>
{isExpanded && (
<TransferCoursesBody
transferCourses={transferCourses}
updateTransferCourses={updateTransferCourses}
year={year}
/>
)}
</Flex>
Expand All @@ -102,11 +106,13 @@ interface TransferCoursesBodyProps {
updateTransferCourses: (
updateTransferCourses: ScheduleCourse2<null>[]
) => void;
year: number;
}

const TransferCoursesBody: React.FC<TransferCoursesBodyProps> = ({
transferCourses,
updateTransferCourses,
year,
}) => {
const { isOpen, onOpen, onClose } = useDisclosure();

Expand Down Expand Up @@ -145,6 +151,9 @@ const TransferCoursesBody: React.FC<TransferCoursesBodyProps> = ({
))}
<AddCourseButton onOpen={onOpen} />
<AddCourseModal
//is season really necessary? i have placeholder here
season={SeasonEnum.FL}
catalogYear={year}
isOpen={isOpen}
addTo="Transfer Courses"
closeModalDisplay={onClose}
Expand Down
31 changes: 31 additions & 0 deletions packages/frontend/components/ScheduleCourse/ScheduleCourse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
INEUReqError,
IRequiredCourse,
ScheduleCourse2,
SeasonEnum,
} from "@graduate/common";
import { forwardRef, PropsWithChildren, useEffect, useState } from "react";
import {
Expand Down Expand Up @@ -383,3 +384,33 @@ const ScheduleCourseDraggedContents: React.FC<
const ScheduleCourseSpacer: React.FC = () => {
return <div style={{ width: "32px", height: "32px", flexShrink: 0 }}></div>;
};

export function getSearchLink(
catalogYear: number,
szn: SeasonEnum,
course: ScheduleCourse2<unknown>
): 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
}`;
}
Loading

0 comments on commit 1ee62bb

Please sign in to comment.