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

chore: Remove LinkProperties from PageHeader in favor of VedaUIProvider #1382

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
9 changes: 2 additions & 7 deletions app/scripts/components/common/nav-wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import styled, { css } from 'styled-components';
import { themeVal } from '@devseed-ui/theme-provider';
import { NavLink } from 'react-router-dom';
import { default as PageHeaderLegacy } from './page-header-legacy';
import PageHeaderLegacy from './page-header-legacy';
import PageHeader from './page-header';
import { useSlidingStickyHeaderProps } from './layout-root/useSlidingStickyHeaderProps';
import NasaLogoColor from './nasa-logo-color';
Expand Down Expand Up @@ -38,12 +38,7 @@ function NavWrapper(props) {
const { isHeaderHidden, headerHeight } = useSlidingStickyHeaderProps();

return isUSWDSEnabled ? (
<PageHeader
{...props}
logoSvg={<NasaLogoColor />}
linkProperties={{ LinkElement: NavLink, pathAttributeKeyName: 'to' }}
title={appTitle}
/>
<PageHeader {...props} logoSvg={<NasaLogoColor />} title={appTitle} />
) : (
<NavWrapperContainer
id={HEADER_WRAPPER_ID}
Expand Down
6 changes: 3 additions & 3 deletions app/scripts/components/common/page-header-legacy/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,14 @@ const GlobalMenu = styled.ul`
`}
`;

interface PageHeaderProps {
interface PageHeaderLegacyProps {
mainNavItems: NavItem[];
subNavItems: NavItem[];
logo: ReactElement;
linkProperties: LinkProperties;
}

function PageHeader(props: PageHeaderProps) {
function PageHeaderLegacy(props: PageHeaderLegacyProps) {
const { mainNavItems, subNavItems, logo, linkProperties } = props;
const { isMediumDown } = useMediaQuery();
const [globalNavRevealed, setGlobalNavRevealed] = useState(false);
Expand Down Expand Up @@ -357,4 +357,4 @@ function PageHeader(props: PageHeaderProps) {
);
}

export default PageHeader;
export default PageHeaderLegacy;
26 changes: 7 additions & 19 deletions app/scripts/components/common/page-header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ import {
USWDSNavMenuButton,
USWDSExtendedNav
} from '$uswds';
import { LinkProperties } from '$types/veda';

interface PageHeaderProps {
mainNavItems: NavItem[];
subNavItems: NavItem[];
logoSvg?: SVGElement | JSX.Element;
linkProperties: LinkProperties;
title: string;
version?: string;
accessibilityHomeShortCutText?: string;
Expand All @@ -25,7 +24,6 @@ export default function PageHeader({
mainNavItems,
subNavItems,
logoSvg: Logo,
linkProperties,
title,
version,
accessibilityHomeShortCutText
Expand All @@ -44,14 +42,13 @@ export default function PageHeader({
}, []);

const primaryItems = useMemo(
() =>
createDynamicNavMenuList(mainNavItems, linkProperties, isOpen, setIsOpen),
[mainNavItems, linkProperties, isOpen]
() => createDynamicNavMenuList(mainNavItems, isOpen, setIsOpen),
[mainNavItems, isOpen]
);

const secondaryItems = useMemo(
() => createDynamicNavMenuList(subNavItems, linkProperties),
[subNavItems, linkProperties]
() => createDynamicNavMenuList(subNavItems),
[subNavItems]
);

const skipNav = (e) => {
Expand All @@ -64,22 +61,13 @@ export default function PageHeader({

return (
<>
<button
type='button'
className='usa-skipnav'
onClick={skipNav}
>
<button type='button' className='usa-skipnav' onClick={skipNav}>
{accessibilityHomeShortCutText || 'Skip to main content'}
</button>
<USWDSHeader extended={true} showMobileOverlay={expanded}>
<div className='usa-navbar'>
<USWDSHeaderTitle>
<LogoContainer
linkProperties={linkProperties}
LogoSvg={Logo}
title={title}
version={version}
/>
<LogoContainer LogoSvg={Logo} title={title} version={version} />
</USWDSHeaderTitle>
<USWDSNavMenuButton onClick={toggleExpansion} label='Menu' />
</div>
Expand Down
21 changes: 10 additions & 11 deletions app/scripts/components/common/page-header/logo-container/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ComponentType } from 'react';
import { Tip } from '../../tip';
import { LinkProperties } from '$types/veda';
import './logo-container.scss';
import { useVedaUI } from '$context/veda-ui-provider';

/**
* LogoContainer that is meant to integrate in the default
Expand All @@ -11,34 +11,33 @@ import './logo-container.scss';
*/

export default function LogoContainer({
linkProperties,
LogoSvg,
title,
version
}: {
linkProperties: LinkProperties;
LogoSvg?: SVGElement | JSX.Element;
title: string;
version?: string;
}) {
const LinkElement: ComponentType<any> =
linkProperties.LinkElement as ComponentType<any>;
const {
navigation: { LinkComponent, linkProps }
} = useVedaUI();

return (
<div id='logo-container'>
<LinkElement
<LinkComponent
id='logo-container-link'
{...{ [linkProperties.pathAttributeKeyName]: '/' }}
{...{ [linkProps.pathAttributeKeyName]: '/' }}
>
{LogoSvg}
{LogoSvg as any}
<span>{title}</span>
</LinkElement>
</LinkComponent>
<Tip content={version ? `v${version}` : 'beta version'}>
<div
id='logo-container-beta-tag'
{...{
as: linkProperties.LinkElement as ComponentType<any>,
[linkProperties.pathAttributeKeyName]: '/development'
as: LinkComponent,
[linkProps.pathAttributeKeyName]: '/development'
}}
>
{version || 'BETA'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
gap: themeVars.$veda-uswds-spacing-105;
font-weight: themeVars.$veda-uswds-fontweight-bold;
font-size: themeVars.$veda-uswds-fontsize-lg;
color: themeVars.$veda-uswds-color-base-ink;
}

#nasa-logo-pos {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ import { NavItem, NavItemType } from '../types';
import { NavDropDownButton } from './nav-dropdown-button';
import { NavItemExternalLink, NavItemInternalLink } from './nav-item-links';
import { NavItemCTA } from './nav-item-cta';
import { LinkProperties } from '$types/veda';
import { SetState } from '$types/aliases';

export const createDynamicNavMenuList = (
navItems: NavItem[],
linkProperties: LinkProperties,
isOpen?: boolean[],
setIsOpen?: SetState<boolean[]>
): JSX.Element[] => {
Expand All @@ -22,14 +20,13 @@ export const createDynamicNavMenuList = (
item,
isOpen,
setIsOpen,
index,
linkProperties
index
}}
/>
);

case NavItemType.INTERNAL_LINK:
return <NavItemInternalLink {...{ item, linkProperties }} />;
return <NavItemInternalLink item={item} />;

case NavItemType.EXTERNAL_LINK:
return <NavItemExternalLink item={item} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,20 @@ import { DropdownNavLink } from '../types';
import { createDynamicNavMenuList } from './create-dynamic-nav-menu-list';
import { USWDSNavDropDownButton, USWDSMenu } from '$uswds';
import { SetState } from '$types/aliases';
import { LinkProperties } from '$types/veda';
import { useClickOutside } from '$utils/use-click-outside';

interface NavDropDownButtonProps {
item: DropdownNavLink;
isOpen: boolean[];
setIsOpen: SetState<boolean[]>;
index: number;
linkProperties: LinkProperties;
}

export const NavDropDownButton = ({
item,
isOpen,
setIsOpen,
index,
linkProperties
index
}: NavDropDownButtonProps) => {
const onToggle = (index: number, setIsOpen: SetState<boolean[]>): void => {
setIsOpen((prevIsOpen) => {
Expand All @@ -42,7 +39,7 @@ export const NavDropDownButton = ({
}
}, [index, isOpen, setIsOpen]);
const dropdownRef = useClickOutside(handleClickOutside);
const submenuItems = createDynamicNavMenuList(item.children, linkProperties);
const submenuItems = createDynamicNavMenuList(item.children);

return (
<div key={item.id} ref={dropdownRef}>
Expand Down
43 changes: 19 additions & 24 deletions app/scripts/components/common/page-header/nav/nav-item-links.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import React from 'react';
import { ExternalNavLink, InternalNavLink } from '../types';
import { LinkProperties } from '$types/veda';
import { useVedaUI } from '$context/veda-ui-provider';

interface NavItemExternalLinkProps {
item: ExternalNavLink;
}

interface NavItemInternalLinkProps {
item: InternalNavLink;
linkProperties: LinkProperties;
}

export const NavItemExternalLink = ({ item }: NavItemExternalLinkProps) => {
Expand All @@ -26,26 +25,22 @@ export const NavItemExternalLink = ({ item }: NavItemExternalLinkProps) => {
);
};

export const NavItemInternalLink = ({
item,
linkProperties
}: NavItemInternalLinkProps) => {
if (linkProperties.LinkElement) {
const path = {
[linkProperties.pathAttributeKeyName]: (item as InternalNavLink).to
};
const LinkElement = linkProperties.LinkElement;
return (
<LinkElement
key={item.id}
{...path}
className='usa-nav__link'
id={item.id}
>
<span>{item.title}</span>
</LinkElement>
);
}
// If the link provided is invalid, do not render the element
return null;
export const NavItemInternalLink = ({ item }: NavItemInternalLinkProps) => {
const {
navigation: { LinkComponent, linkProps }
} = useVedaUI();

const path = {
[linkProps.pathAttributeKeyName]: (item as InternalNavLink).to
};
return (
<LinkComponent
key={item.id}
{...path}
className='usa-nav__link'
id={item.id}
>
<span>{item.title}</span>
</LinkComponent>
);
};
35 changes: 17 additions & 18 deletions app/scripts/components/common/page-header/page-header.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React, { ComponentType } from 'react';
import React from 'react';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { BrowserRouter } from 'react-router-dom';
import UIProviders from '../../../ui-providers';
import { navItems } from '../../../../../mock/veda.config.js';
import NasaLogoColor from '../nasa-logo-color';
import { NavItem } from './types';
Expand All @@ -13,22 +15,21 @@ import PageHeader from './index';
const mockMainNavItems: NavItem[] = navItems.mainNavItems;
const mockSubNavItems: NavItem[] = navItems.subNavItems;

const mockLinkProperties = {
pathAttributeKeyName: 'to',
LinkElement: 'a' as unknown as ComponentType
};
const testTitle = 'Test Title';

describe('PageHeader', () => {
beforeEach(() => {
render(
<PageHeader
mainNavItems={mockMainNavItems}
subNavItems={mockSubNavItems}
logoSvg={<NasaLogoColor />}
title={testTitle}
linkProperties={mockLinkProperties}
/>
<BrowserRouter basename=''>
<UIProviders>
<PageHeader
mainNavItems={mockMainNavItems}
subNavItems={mockSubNavItems}
logoSvg={<NasaLogoColor />}
title={testTitle}
/>
</UIProviders>
</BrowserRouter>
);
});

Expand All @@ -45,7 +46,7 @@ describe('PageHeader', () => {

expect(primaryNav.childElementCount).toEqual(mockMainNavItems.length);
expect(secondaryNav.childElementCount).toEqual(mockSubNavItems.length);
expect(within(primaryNav).getByText('Test')).toBeInTheDocument();
expect(within(primaryNav).getByText('TestDropdown1')).toBeInTheDocument();
expect(within(primaryNav).getByText('Data Catalog')).toBeInTheDocument();
expect(within(primaryNav).getByText('Exploration')).toBeInTheDocument();
expect(within(primaryNav).getByText('Stories')).toBeInTheDocument();
Expand All @@ -59,11 +60,9 @@ describe('PageHeader', () => {
expect(navElement).toBeInTheDocument();

const primaryNav = within(navElement).getAllByRole('list')[0];
const navItem = screen.getByText('Test');
expect(
within(primaryNav).getByText('dropdown menu item 1')
).not.toBeVisible();
const navItem = screen.getByText('TestDropdown1');
expect(within(primaryNav).getByText('route to stories')).not.toBeVisible();
await user.click(navItem);
expect(within(primaryNav).getByText('dropdown menu item 1')).toBeVisible();
expect(within(primaryNav).getByText('route to stories')).toBeVisible();
});
});
Loading
Loading