Skip to content

Commit

Permalink
[Issue 2783] indicate active nav item (#2874)
Browse files Browse the repository at this point in the history
  • Loading branch information
doug-s-nava authored Nov 18, 2024
1 parent c5c3682 commit f003e69
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 10 deletions.
40 changes: 36 additions & 4 deletions frontend/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type Props = {
locale?: string;
};

const homeRegexp = /^\/(?:e[ns])?$/;

const NavLinks = ({
mobileExpanded,
onToggleMobileNav,
Expand All @@ -34,7 +36,6 @@ const NavLinks = ({
}) => {
const t = useTranslations("Header");
const path = usePathname();

const getSearchLink = useCallback(
(onSearch: boolean) => {
return {
Expand All @@ -55,13 +56,44 @@ const NavLinks = ({
];
}, [t, path, getSearchLink]);

const getCurrentNavItemIndex = useCallback(
(currentPath: string): number => {
// handle base case of home page separately
if (currentPath.match(homeRegexp)) {
return 0;
}
const index = navLinkList.slice(1).findIndex(({ href }) => {
const baseHref = href.split("?")[0];
return currentPath.match(new RegExp(`^(?:/e[ns])?${baseHref}`));
});
// account for home path
return index === -1 ? index : index + 1;
},
[navLinkList],
);

const [currentNavItemIndex, setCurrentNavItemIndex] = useState<number>(
getCurrentNavItemIndex(path),
);

useEffect(() => {
setCurrentNavItemIndex(getCurrentNavItemIndex(path));
}, [path, getCurrentNavItemIndex]);

const navItems = useMemo(() => {
return navLinkList.map((link: PrimaryLink) => {
return navLinkList.map((link: PrimaryLink, index: number) => {
if (!link.text || !link.href) {
return <></>;
}
return (
<Link href={link.href} key={link.href}>
<Link
href={link.href}
key={link.href}
className={clsx({
"usa-nav__link": true,
"usa-current": currentNavItemIndex === index,
})}
>
<div
onClick={() => {
if (mobileExpanded) {
Expand All @@ -74,7 +106,7 @@ const NavLinks = ({
</Link>
);
});
}, [navLinkList, mobileExpanded, onToggleMobileNav]);
}, [navLinkList, currentNavItemIndex, mobileExpanded, onToggleMobileNav]);

return (
<PrimaryNav
Expand Down
41 changes: 35 additions & 6 deletions frontend/tests/components/Header.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ const props = {
locale: "en",
};

let mockedPath = "/fakepath";

const getMockedPath = () => mockedPath;
const usePathnameMock = jest.fn().mockReturnValue("/fakepath");

jest.mock("src/hooks/useSearchParamUpdater", () => ({
useSearchParamUpdater: () => ({
Expand All @@ -21,7 +19,7 @@ jest.mock("src/hooks/useSearchParamUpdater", () => ({
}));

jest.mock("next/navigation", () => ({
usePathname: () => getMockedPath(),
usePathname: () => usePathnameMock() as string,
}));

describe("Header", () => {
Expand Down Expand Up @@ -67,7 +65,7 @@ describe("Header", () => {
});

it("displays a search link with refresh param if currently on search page", () => {
mockedPath = "/search";
usePathnameMock.mockReturnValue("/search");
render(<Header />);

const searchLink = screen.getByRole("link", { name: "Search" });
Expand All @@ -76,6 +74,7 @@ describe("Header", () => {
});

it("displays a home link if not on home page", () => {
usePathnameMock.mockReturnValue("/search");
render(<Header />);

const homeLink = screen.getByRole("link", { name: "Simpler.Grants.gov" });
Expand All @@ -84,11 +83,41 @@ describe("Header", () => {
});

it("display text without a home link if on home page", () => {
mockedPath = "/";
usePathnameMock.mockReturnValue("/");
render(<Header />);

const homeText = screen.getByText("Simpler.Grants.gov");
expect(homeText).toBeInTheDocument();
expect(homeText).not.toHaveAttribute("href", "/");
});

it("shows the correct styling for active nav item", async () => {
usePathnameMock.mockReturnValue("/");
const { rerender } = render(<Header />);

const homeLink = screen.getByRole("link", { name: "Home" });
expect(homeLink).toHaveClass("usa-current");

usePathnameMock.mockReturnValue("/search");
rerender(<Header />);
const searchLink = screen.getByRole("link", { name: "Search" });
expect(searchLink).toHaveClass("usa-current");

usePathnameMock.mockReturnValue("/es/search");
rerender(<Header />);
const spanishLink = screen.getByRole("link", { name: "Search" });
expect(spanishLink).toHaveClass("usa-current");

usePathnameMock.mockReturnValue("/es/search?query=hello");
rerender(<Header />);
const queryLink = screen.getByRole("link", { name: "Search" });
expect(queryLink).toHaveClass("usa-current");

usePathnameMock.mockReturnValue("/opportunity/35");
rerender(<Header />);
const allLinks = await screen.findAllByRole("link");
allLinks.forEach((link) => {
expect(link).not.toHaveClass("usa-current");
});
});
});

0 comments on commit f003e69

Please sign in to comment.