Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] "What's New" Pop-Up #757

Merged
merged 16 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import {
Box,
Button,
HStack,
Image,
ModalContent,
ModalFooter,
ModalHeader,
Stack,
Text,
chakra,
} from "@chakra-ui/react";
import { ModalBodyPagination } from "./ModalBodyPagination";
import InProgressIndicatorImage from "../../public/in-progress-indicator.png";
import SearchNEUIntegrationImage from "../../public/searchneu-integration.png";
import { InfoOutlineIcon } from "@chakra-ui/icons";
import React, { useEffect } from "react";

interface ModalContentProps {
onClose: () => void;
}

const InProgressIcon: React.FC = () => {
return (
<Box
bg="orange"
borderColor="orange"
color="white"
borderWidth="1px"
width="18px"
height="18px"
display="inline-flex"
alignItems="center"
justifyContent="center"
transition="background 0.25s ease, color 0.25s ease, border 0.25s ease"
transitionDelay="0.1s"
borderRadius="2xl"
p="xs"
position="relative"
verticalAlign="middle"
>
<Text fontSize="s" boxSize="34px" color="white">
...
</Text>
</Box>
);
};

interface FeaturePageData {
key: string;
title: string;
descriptionSection: React.ReactNode;
image: string;
}

const featurePagesData: FeaturePageData[] = [
{
key: "in-progress-indicator",
title: "In-progress Indicator",
descriptionSection: (
<Stack>
<Text>
Want to know which major requirements are still in progress?
</Text>
<Text>
Look for the new{""}
<chakra.span px="1">
<InProgressIcon />
</chakra.span>{" "}
icon to know which requirements are currently in-progress.
</Text>
</Stack>
),
image: InProgressIndicatorImage.src,
},
{
key: "searchneu-integration",
title: "SearchNEU Integration",
descriptionSection: (
<Stack>
<Text>
Want to know more about a class before adding it to the plan?
</Text>
<Text>
Click on the new{" "}
<chakra.span px="1">
<InfoOutlineIcon />
</chakra.span>{" "}
button to read more about a class on SearchNEU.
</Text>
</Stack>
),
image: SearchNEUIntegrationImage.src,
},
];

export const Fall2024ReleaseModalContent: React.FC<ModalContentProps> = ({
onClose,
}) => {
const [featurePages, setFeaturePages] = React.useState<React.ReactNode[]>([]);

useEffect(() => {
const pages = [];
for (const featurePageData of featurePagesData) {
pages.push(<NewFeaturePage {...featurePageData} />);
}
setFeaturePages(pages);
}, []);

return (
<ModalContent>
<ModalHeader
color="primary.blue.dark.main"
borderBottom="1px"
borderColor="neutral.200"
>
<Text>Latest Release v26.09.24</Text>
</ModalHeader>
{featurePages.length > 0 && <ModalBodyPagination pages={featurePages} />}
<ModalFooter alignContent="center" justifyContent="center">
<Button
variant="solid"
borderRadius="md"
width="sm"
colorScheme="red"
onClick={onClose}
>
Looks Good!
</Button>
</ModalFooter>
</ModalContent>
);
};

const NewFeaturePage: React.FC<FeaturePageData> = ({
key,
title,
descriptionSection,
image,
}) => {
return (
<HStack pt="8" alignItems="start" gap="8" key={key} minHeight={"350px"}>
<NewFeatureText title={title} descriptionSection={descriptionSection} />
<NewFeatureImage src={image} alt={title + " image"} />
</HStack>
);
};

interface NewFeatureImageProps {
src: string;
alt?: string;
}

const NewFeatureImage: React.FC<NewFeatureImageProps> = ({ src, alt }) => {
return (
<Stack flex="3">
<Image
src={src}
alt={alt}
fit={"contain"}
maxWidth={400}
maxHeight={300}
borderRadius="2xl"
/>
</Stack>
);
};

interface NewFeatureTextProps {
title: string;
descriptionSection: React.ReactNode;
}

const NewFeatureText: React.FC<NewFeatureTextProps> = ({
title,
descriptionSection,
}) => {
return (
<Stack flex="2">
<Text fontWeight="bold" fontSize="md" textColor="primary.red.main">
NEW
</Text>
<Text textColor="primary.blue.dark.main" fontWeight="bold" fontSize="xl">
{title}
</Text>
{descriptionSection}
</Stack>
);
};
Loading
Loading