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

HCBS Header #14

Merged
merged 13 commits into from
Jul 31, 2024
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed services/ui-src/src/assets/logos/logo_mdct_mfp.png
Binary file not shown.
20 changes: 14 additions & 6 deletions services/ui-src/src/components/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { useContext } from "react";
import { Routes, Route } from "react-router-dom";
import { LoginCognito, LoginIDM, PostLogoutRedirect } from "components";
import { useStore } from "utils";
import { makeMediaQueryClasses } from "utils/other/useBreakpoint";
import { Container, Divider, Heading, Stack } from "@chakra-ui/react";
// components
rocio-desantiago marked this conversation as resolved.
Show resolved Hide resolved
import { Container, Divider, Flex, Heading, Stack } from "@chakra-ui/react";
import { Header, LoginCognito, LoginIDM, PostLogoutRedirect } from "components";
// utils
import { makeMediaQueryClasses, UserContext, useStore } from "utils";

export const App = () => {
const mqClasses = makeMediaQueryClasses();
// const context = useContext(UserContext);
const context = useContext(UserContext);
const { logout } = context;
const { user, showLocalLogins } = useStore();
// const { pathname } = useLocation();

Expand All @@ -24,7 +27,12 @@ export const App = () => {

const authenticatedRoutes = (
<>
{user && <div data-testid="app-container">Hello World</div>}
{user && (
<Flex sx={sx.appLayout}>
<Header handleLogout={logout} />
<div data-testid="app-container">Hello World</div>
</Flex>
)}
{!user && showLocalLogins && (
<main>
<Container sx={sx.appContainer}>
Expand Down
8 changes: 6 additions & 2 deletions services/ui-src/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ export { ErrorAlert } from "./alerts/ErrorAlert";
// app
export { App } from "./app/App";
export { Error } from "./app/Error";
// layout
export { Header } from "./layout/Header";
export { PageTemplate } from "./layout/PageTemplate";
// logins
export { LoginCognito } from "./logins/LoginCognito";
export { LoginIDM } from "./logins/LoginIDM";
// layout
export { PageTemplate } from "./layout/PageTemplate";
// menus
export { Menu } from "./menus/Menu";
export { MenuOption } from "./menus/MenuOption";
// Redirects
export { PostLogoutRedirect } from "./PostLogoutRedirect/index";
94 changes: 94 additions & 0 deletions services/ui-src/src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Link as RouterLink } from "react-router-dom";
// components
import { UsaBanner } from "@cmsgov/design-system";
import { Box, Container, Flex, Image, Link } from "@chakra-ui/react";
import { Menu, MenuOption } from "components";
// utils
import { useBreakpoint } from "utils";
// assets
import appLogo from "assets/logos/logo_mdct_hcbs.png";
import getHelpIcon from "assets/icons/icon_help.png";

export const Header = ({ handleLogout }: Props) => {
const { isMobile } = useBreakpoint();

return (
<Box sx={sx.root} id="header">
<Flex sx={sx.usaBannerContainer}>
<UsaBanner />
</Flex>
<Flex sx={sx.headerBar} role="navigation">
<Container sx={sx.headerContainer}>
<Flex sx={sx.headerFlex}>
<Link as={RouterLink} to="/" variant="unstyled">
<Image src={appLogo} alt="HCBS logo" sx={sx.appLogo} />
</Link>
<Flex sx={sx.menuFlex}>
<Link
as={RouterLink}
to="/help"
variant="unstyled"
aria-label="Get Help"
>
<MenuOption
icon={getHelpIcon}
text="Get Help"
altText="Help"
role="group"
hideText={isMobile}
/>
</Link>
<Menu handleLogout={handleLogout} />
</Flex>
</Flex>
</Container>
</Flex>
</Box>
);
};

interface Props {
handleLogout: () => void;
}

const sx = {
root: {
position: "sticky",
top: 0,
zIndex: "sticky",
boxShadow: "0px 4px 4px rgba(0, 0, 0, 0.25)",
"@media print": {
display: "none",
},
},
usaBannerContainer: {
width: "100%",
flexDirection: "column",
alignItems: "center",
backgroundColor: "palette.gray_lightest",
".desktop &": {
padding: "0 1rem",
},
},
headerBar: {
minHeight: "4rem",
alignItems: "center",
bg: "palette.primary_darkest",
},
headerContainer: {
maxW: "appMax",
".desktop &": {
padding: "0 2rem",
},
},
headerFlex: {
justifyContent: "space-between",
alignItems: "center",
},
menuFlex: {
alignItems: "center",
},
appLogo: {
maxWidth: "200px",
},
};
21 changes: 21 additions & 0 deletions services/ui-src/src/components/menus/Menu.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { render, screen } from "@testing-library/react";
// utils
import { RouterWrappedComponent } from "utils/testing/setupJest";
//components
import { Menu } from "components";
import { testA11y } from "utils/testing/commonTests";

const menuComponent = (
<RouterWrappedComponent>
<Menu handleLogout={() => {}} />
</RouterWrappedComponent>
);

describe("<Menu />", () => {
test("Menu button is visible", () => {
render(menuComponent);
expect(screen.getByTestId("header-menu-dropdown-button")).toBeVisible();
rocio-desantiago marked this conversation as resolved.
Show resolved Hide resolved
});

testA11y(menuComponent);
});
110 changes: 110 additions & 0 deletions services/ui-src/src/components/menus/Menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { Link as RouterLink } from "react-router-dom";
// components
import {
Box,
Button,
Image,
Link,
Menu as MenuRoot,
MenuButton,
MenuItem,
MenuList,
} from "@chakra-ui/react";
import { MenuOption } from "components";
// utils
import { useBreakpoint } from "utils";
// assets
import accountCircleIcon from "assets/icons/icon_account_circle.png";
import chevronDownIcon from "assets/icons/icon_arrow_down.png";
import editIcon from "assets/icons/icon_edit_square.png";
import logoutIcon from "assets/icons/icon_arrow_right_square.png";

export const Menu = ({ handleLogout }: Props) => {
const { isMobile } = useBreakpoint();
return (
<MenuRoot offset={[8, 20]}>
<Box role="group">
<MenuButton
as={Button}
rightIcon={
<Image src={chevronDownIcon} alt="Arrow down" sx={sx.menuIcon} />
}
sx={sx.menuButton}
aria-label="my account"
data-testid="header-menu-dropdown-button"
rocio-desantiago marked this conversation as resolved.
Show resolved Hide resolved
>
<MenuOption
icon={accountCircleIcon}
altText="Account"
text="My Account"
hideText={isMobile}
/>
</MenuButton>
</Box>
<MenuList sx={sx.menuList} data-testid="header-menu-options-list">
<Link as={RouterLink} to="/profile" variant="unstyled">
<MenuItem
sx={sx.menuItem}
data-testid="header-menu-option-manage-account"
>
<MenuOption
icon={editIcon}
altText="Manage account"
text="Manage Account"
/>
</MenuItem>
</Link>
<MenuItem
onClick={handleLogout}
sx={sx.menuItem}
tabIndex={0}
data-testid="header-menu-option-log-out"
>
<MenuOption icon={logoutIcon} text="Log Out" altText="Logout" />
</MenuItem>
</MenuList>
</MenuRoot>
);
};

interface Props {
handleLogout: () => void;
}

const sx = {
menuButton: {
padding: 0,
paddingRight: ".5rem",
marginLeft: ".5rem",
borderRadius: 0,
background: "none",
color: "palette.white",
fontWeight: "bold",
_hover: { color: "palette.secondary_light", background: "none !important" },
_active: { background: "none" },
_focus: {
boxShadow: "none",
outline: "0px solid transparent !important",
},
".mobile &": {
marginLeft: 0,
},
"& .chakra-button__icon": {
marginInlineStart: "0rem",
},
},
menuList: {
padding: "0",
border: "none",
background: "palette.primary_darkest",
boxShadow: "0px 5px 16px rgba(0, 0, 0, 0.14)",
},
menuItem: {
borderRadius: ".375rem",
_focus: { background: "palette.primary_darker" },
_hover: { background: "palette.primary_darker" },
},
menuIcon: {
width: "0.75rem",
},
};
35 changes: 35 additions & 0 deletions services/ui-src/src/components/menus/MenuOption.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// components
import { Flex, Image, Text } from "@chakra-ui/react";

export const MenuOption = ({ text, icon, altText, role, hideText }: Props) => {
return (
<Flex
align="center"
role={role}
sx={!hideText ? { paddingRight: ".5rem" } : {}}
>
<Image src={icon} alt={altText} sx={sx.menuIcon} />
{!hideText && <Text sx={sx.text}>{text}</Text>}
</Flex>
);
};

interface Props {
text: string;
icon: string;
altText: string;
role?: string;
hideText?: boolean;
}

const sx = {
text: {
fontWeight: "bold",
color: "palette.white",
_groupHover: { color: "palette.gray_lighter" },
},
menuIcon: {
width: "1.5rem",
margin: "0.5rem",
},
};
1 change: 1 addition & 0 deletions services/ui-src/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from "./state/useStore";
export * from "./tracking/tealium";
//other
export * from "./other/parsing";
export * from "./other/useBreakpoint";
Loading