From e5fc6412213944cc8efc0b719d610b08e68be047 Mon Sep 17 00:00:00 2001 From: ShireenKumar Date: Sun, 20 Oct 2024 14:53:31 -0400 Subject: [PATCH 01/14] 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 02/14] 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 2e2504e64191af99d4f6ab458bf6a37e2a21300b Mon Sep 17 00:00:00 2001 From: Kobe Date: Tue, 29 Oct 2024 13:02:25 -0400 Subject: [PATCH 03/14] update cookies code + removing unused comments --- packages/frontend/pages/home.tsx | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/packages/frontend/pages/home.tsx b/packages/frontend/pages/home.tsx index 5f60eaa62..28a1016bd 100644 --- a/packages/frontend/pages/home.tsx +++ b/packages/frontend/pages/home.tsx @@ -68,29 +68,13 @@ 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"); + const existingToken = cookies.get("WhatsNewModal JWT"); if (!existingToken) { setIsOpen(true); // Open modal only if token doesn't exist @@ -101,11 +85,9 @@ const HomePage: NextPage = () => { 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 + cookies.set("WhatsNewModal 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. * undef is used to indicate the initial state where the primary plan should be used, null is to define @@ -365,12 +347,7 @@ const HomePage: NextPage = () => { ) : null} - setIsOpen(false) - /> + ); }; From f5ece2ddbe066921e6fd165fb87fc95a226a1324 Mon Sep 17 00:00:00 2001 From: Kobe Date: Tue, 29 Oct 2024 15:10:16 -0400 Subject: [PATCH 04/14] adding pagination layout --- .../FullPageModal/FullPageModal.tsx | 89 ------------------- .../Fall2024ReleaseModalContent.tsx | 72 +++++++++++++++ .../WhatsNewModal/ModalBodyPagination.tsx | 77 ++++++++++++++++ .../WhatsNewModal/WhatsNewModal.tsx | 21 +++++ packages/frontend/pages/home.tsx | 9 +- 5 files changed, 177 insertions(+), 91 deletions(-) delete mode 100644 packages/frontend/components/FullPageModal/FullPageModal.tsx create mode 100644 packages/frontend/components/WhatsNewModal/Fall2024ReleaseModalContent.tsx create mode 100644 packages/frontend/components/WhatsNewModal/ModalBodyPagination.tsx create mode 100644 packages/frontend/components/WhatsNewModal/WhatsNewModal.tsx diff --git a/packages/frontend/components/FullPageModal/FullPageModal.tsx b/packages/frontend/components/FullPageModal/FullPageModal.tsx deleted file mode 100644 index 49644a764..000000000 --- a/packages/frontend/components/FullPageModal/FullPageModal.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React, { useState } from "react"; -import { - Button, - Modal, - ModalBody, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, - Text, -} 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/components/WhatsNewModal/Fall2024ReleaseModalContent.tsx b/packages/frontend/components/WhatsNewModal/Fall2024ReleaseModalContent.tsx new file mode 100644 index 000000000..3b1835329 --- /dev/null +++ b/packages/frontend/components/WhatsNewModal/Fall2024ReleaseModalContent.tsx @@ -0,0 +1,72 @@ +import { + Box, + Button, + ModalContent, + ModalFooter, + ModalHeader, + Text, +} from "@chakra-ui/react"; +import { ModalBodyPagination } from "./ModalBodyPagination"; + +interface ModalContentProps { + onClose: () => void; +} + +export const Fall2024ReleaseModalContent: React.FC = ({ + onClose, +}) => { + const featurePages: React.ReactNode[] = [ + , + , + , + ]; + + return ( + + + Latest Release v26.09.24 + + + + + + + + ); +}; + +const FeaturePage1: React.FC = () => { + return ( + + Feature 1 + + ); +}; + +const FeaturePage2: React.FC = () => { + return ( + + Feature 2 + + ); +}; + +const FeaturePage3: React.FC = () => { + return ( + + Feature 3 + + ); +}; diff --git a/packages/frontend/components/WhatsNewModal/ModalBodyPagination.tsx b/packages/frontend/components/WhatsNewModal/ModalBodyPagination.tsx new file mode 100644 index 000000000..7ba1b847a --- /dev/null +++ b/packages/frontend/components/WhatsNewModal/ModalBodyPagination.tsx @@ -0,0 +1,77 @@ +import { ChevronLeftIcon, ChevronRightIcon } from "@chakra-ui/icons"; +import { Box, IconButton, ModalBody, Text } from "@chakra-ui/react"; +import { useState } from "react"; + +interface ModalBodyPaginationProps { + pages: React.ReactNode[]; +} + +export const ModalBodyPagination: React.FC = ({ + pages, +}) => { + const [currentPageIndex, setCurrentPageIndex] = useState(0); + + const totalPages = pages.length; + + function goToNextPage() { + setCurrentPageIndex((prev) => Math.min(prev + 1, totalPages)); + } + + function goToPreviousPage() { + setCurrentPageIndex((prev) => Math.max(prev - 1, 0)); + } + + function setCurrentPage(index: number) { + setCurrentPageIndex(index); + } + + return ( + + {pages[currentPageIndex]} + + + ); +}; + +interface PaginationProps { + goToPreviousPage: () => void; + goToNextPage: () => void; + currentPageIndex: number; + totalPages: number; +} + +const Pagination: React.FC = ({ + goToPreviousPage, + goToNextPage, + currentPageIndex, + totalPages, +}) => { + return ( + + } + onClick={goToPreviousPage} + isDisabled={currentPageIndex === 0} + aria-label="Previous page" + /> + + {currentPageIndex + 1} / {totalPages} + + } + onClick={goToNextPage} + isDisabled={currentPageIndex >= totalPages - 1} + aria-label="Next page" + /> + + ); +}; diff --git a/packages/frontend/components/WhatsNewModal/WhatsNewModal.tsx b/packages/frontend/components/WhatsNewModal/WhatsNewModal.tsx new file mode 100644 index 000000000..8e450378d --- /dev/null +++ b/packages/frontend/components/WhatsNewModal/WhatsNewModal.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { Modal, ModalOverlay } from "@chakra-ui/react"; + +interface WhatsNewModalProps { + isOpen: boolean; + onClose: () => void; + children: React.ReactNode; +} + +export const WhatsNewModal: React.FC = ({ + isOpen, + onClose, + children, +}) => { + return ( + + + {children} + + ); +}; diff --git a/packages/frontend/pages/home.tsx b/packages/frontend/pages/home.tsx index 28a1016bd..e740f0916 100644 --- a/packages/frontend/pages/home.tsx +++ b/packages/frontend/pages/home.tsx @@ -50,8 +50,9 @@ import { getPreReqWarnings, } from "../utils/plan/preAndCoReqCheck"; import { IsGuestContext } from "./_app"; -import { WhatsNewPopUp } from "../components/FullPageModal/FullPageModal"; +import { WhatsNewModal } from "../components/WhatsNewModal/WhatsNewModal"; import Cookies from "universal-cookie"; +import { Fall2024ReleaseModalContent } from "../components/WhatsNewModal/Fall2024ReleaseModalContent"; // 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. @@ -347,7 +348,11 @@ const HomePage: NextPage = () => { ) : null} - + } + /> ); }; From 5d4f2eafbd604d8d329676ab31a78d6c9c5f01dd Mon Sep 17 00:00:00 2001 From: Kobe Date: Sat, 2 Nov 2024 17:23:15 -0400 Subject: [PATCH 05/14] working on modal part 1 --- .../components/Header/GraduateHeaders.tsx | 23 +++++ .../Fall2024ReleaseModalContent.tsx | 99 ++++++++++++++++--- .../WhatsNewModal/ModalBodyPagination.tsx | 6 +- .../WhatsNewModal/WhatsNewModal.tsx | 2 +- 4 files changed, 111 insertions(+), 19 deletions(-) diff --git a/packages/frontend/components/Header/GraduateHeaders.tsx b/packages/frontend/components/Header/GraduateHeaders.tsx index 39eb21cfc..1757e8308 100644 --- a/packages/frontend/components/Header/GraduateHeaders.tsx +++ b/packages/frontend/components/Header/GraduateHeaders.tsx @@ -51,6 +51,10 @@ const GraduateHeader: React.FC = ({ rightContent }) => { + + + Latest Release Notes + Feedback @@ -128,6 +132,25 @@ const MobileHeader: React.FC = () => { ); }; +const LatestReleaseNotesIcon: React.FC = (props) => { + return ( + + + + ); +}; + const FeedbackIcon: React.FC = (props) => { return ( = ({ onClose, }) => { const featurePages: React.ReactNode[] = [ - , - , - , + , + , + , ]; return ( @@ -47,26 +50,92 @@ export const Fall2024ReleaseModalContent: React.FC = ({ ); }; -const FeaturePage1: React.FC = () => { +const WhatsNewModalFeaturePage: React.FC = () => { return ( - - Feature 1 - + Stay up to date with the latest changes on GraduateNU! + } + image="https://placehold.co/600x400" + /> ); }; -const FeaturePage2: React.FC = () => { +const InProgressIndicatorFeaturePage: React.FC = () => { return ( - - Feature 2 - + + Have your degree audit move with you and see what requirement sections + are currently in progress! + + } + image="https://placehold.co/600x400" + /> ); }; -const FeaturePage3: React.FC = () => { +const SearchNEUIntegrationFeaturePage: React.FC = () => { return ( - - Feature 3 - + + + Want to know more about a class before adding it to the plan?{" "} + + + Click on the new i button to read more about a class on + SearchNEU + + + } + image="https://placehold.co/600x400" + /> + ); +}; + +interface NewFeaturePageProps { + title: string; + descriptionSection: React.ReactNode; + image: string; +} + +const NewFeaturePage: React.FC = ({ + title, + descriptionSection, + image, +}) => { + return ( + + + + + + + ); +}; + +interface NewFeatureTextProps { + title: string; + descriptionSection: React.ReactNode; +} + +const NewFeatureText: React.FC = ({ + title, + descriptionSection, +}) => { + return ( + + + NEW + + + {title} + + {descriptionSection} + ); }; diff --git a/packages/frontend/components/WhatsNewModal/ModalBodyPagination.tsx b/packages/frontend/components/WhatsNewModal/ModalBodyPagination.tsx index 7ba1b847a..c5a9058f6 100644 --- a/packages/frontend/components/WhatsNewModal/ModalBodyPagination.tsx +++ b/packages/frontend/components/WhatsNewModal/ModalBodyPagination.tsx @@ -54,18 +54,18 @@ const Pagination: React.FC = ({ return ( } onClick={goToPreviousPage} isDisabled={currentPageIndex === 0} aria-label="Previous page" /> - + {currentPageIndex + 1} / {totalPages} } onClick={goToNextPage} diff --git a/packages/frontend/components/WhatsNewModal/WhatsNewModal.tsx b/packages/frontend/components/WhatsNewModal/WhatsNewModal.tsx index 8e450378d..f4668374d 100644 --- a/packages/frontend/components/WhatsNewModal/WhatsNewModal.tsx +++ b/packages/frontend/components/WhatsNewModal/WhatsNewModal.tsx @@ -13,7 +13,7 @@ export const WhatsNewModal: React.FC = ({ children, }) => { return ( - + {children} From d56750c5753db65f98e5c35636e16f7f630b5c79 Mon Sep 17 00:00:00 2001 From: KobeZ123 Date: Sat, 2 Nov 2024 17:51:08 -0400 Subject: [PATCH 06/14] update entry point for whats new modal --- .../components/Header/GraduateHeaders.tsx | 65 +++++++++---------- .../Fall2024ReleaseModalContent.tsx | 1 - .../WhatsNewModal/ModalBodyPagination.tsx | 4 -- .../WhatsNewModalContextProvider.tsx | 49 ++++++++++++++ packages/frontend/pages/home.tsx | 25 ------- 5 files changed, 78 insertions(+), 66 deletions(-) create mode 100644 packages/frontend/components/WhatsNewModal/WhatsNewModalContextProvider.tsx diff --git a/packages/frontend/components/Header/GraduateHeaders.tsx b/packages/frontend/components/Header/GraduateHeaders.tsx index 1757e8308..748e78315 100644 --- a/packages/frontend/components/Header/GraduateHeaders.tsx +++ b/packages/frontend/components/Header/GraduateHeaders.tsx @@ -17,7 +17,11 @@ 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"; export const GraduatePreAuthHeader: React.FC = () => { const [isMobile] = useMediaQuery("(max-width: 640px)"); @@ -46,26 +50,30 @@ interface GraduateHeaderProps { } const GraduateHeader: React.FC = ({ rightContent }) => { + const { openModal } = useWhatsNewModal(); + return ( - - - - - - - Latest Release Notes - - - - Feedback - - - - Bug/Feature - - {rightContent} - - + + + + + + + + Latest Release Notes + + + + Feedback + + + + Bug/Feature + + {rightContent} + + + ); }; @@ -133,22 +141,7 @@ const MobileHeader: React.FC = () => { }; const LatestReleaseNotesIcon: React.FC = (props) => { - return ( - - - - ); + return ; }; const FeedbackIcon: React.FC = (props) => { diff --git a/packages/frontend/components/WhatsNewModal/Fall2024ReleaseModalContent.tsx b/packages/frontend/components/WhatsNewModal/Fall2024ReleaseModalContent.tsx index fd09bb216..4fbf52316 100644 --- a/packages/frontend/components/WhatsNewModal/Fall2024ReleaseModalContent.tsx +++ b/packages/frontend/components/WhatsNewModal/Fall2024ReleaseModalContent.tsx @@ -34,7 +34,6 @@ export const Fall2024ReleaseModalContent: React.FC = ({ Latest Release v26.09.24 -