diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx
index 4f615830f..15202dcf6 100644
--- a/frontend/src/components/Header.tsx
+++ b/frontend/src/components/Header.tsx
@@ -4,7 +4,7 @@ import { useFeatureFlags } from "src/hooks/useFeatureFlags";
import { assetPath } from "src/utils/assetPath";
import { useTranslations } from "next-intl";
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useMemo, useRef, useState } from "react";
import {
GovBanner,
NavMenuButton,
@@ -14,8 +14,9 @@ import {
} from "@trussworks/react-uswds";
type PrimaryLinks = {
- i18nKey: string;
+ linkText: string;
href: string;
+ flag?: string;
}[];
type Props = {
@@ -23,38 +24,67 @@ type Props = {
locale?: string;
};
+const toNavLinkItems = (linkDetails: { linkText: string; href: string }[]) => {
+ return linkDetails.map((link) => (
+
+ {link.linkText}
+
+ ));
+};
+
const Header = ({ logoPath, locale }: Props) => {
const t = useTranslations("Header");
const [isMobileNavExpanded, setIsMobileNavExpanded] = useState(false);
+ const {
+ featureFlagsManager: { featureFlags },
+ } = useFeatureFlags();
+
const handleMobileNavToggle = () => {
setIsMobileNavExpanded(!isMobileNavExpanded);
};
- const primaryLinksRef = useRef([]);
- const { featureFlagsManager } = useFeatureFlags();
+ const primaryNavLinkConfigs: PrimaryLinks = [
+ { linkText: t("nav_link_home"), href: "/" },
+ { linkText: t("nav_link_process"), href: "/process" },
+ { linkText: t("nav_link_research"), href: "/research" },
+ { linkText: t("nav_link_subscribe"), href: "/subscribe" },
+ ];
- useEffect(() => {
- primaryLinksRef.current = [
- { i18nKey: t("nav_link_home"), href: "/" },
- { i18nKey: t("nav_link_process"), href: "/process" },
- { i18nKey: t("nav_link_research"), href: "/research" },
- { i18nKey: t("nav_link_subscribe"), href: "/subscribe" },
- ];
- const searchNavLink = {
- i18nKey: t("nav_link_search"),
+ const featureFlaggedNavLinkConfigs: PrimaryLinks = [
+ {
+ linkText: t("nav_link_search"),
href: "/search?status=forecasted,posted",
- };
- if (featureFlagsManager.isFeatureEnabled("showSearchV0")) {
- primaryLinksRef.current.splice(1, 0, searchNavLink);
- }
- }, [featureFlagsManager, t]);
+ flag: "showSearchV0",
+ },
+ ];
- const navItems = primaryLinksRef.current.map((link) => (
-
- {link.i18nKey}
-
- ));
- const language = locale && locale.match("/^es/") ? "spanish" : "english";
+ const primaryLinksRef = useRef(primaryNavLinkConfigs);
+
+ // note that this will not update when feature flags are updated without a refresh
+ useEffect(() => {
+ const navLinksFromFlags = featureFlaggedNavLinkConfigs.reduce(
+ (acc, link) => {
+ const { flag = "" } = link;
+ console.log("####", featureFlags[flag]);
+ if (
+ featureFlags[flag] &&
+ !primaryLinksRef.current.some(
+ (existingLink) => existingLink.href === link.href,
+ )
+ ) {
+ acc.splice(1, 0, link);
+ }
+ return acc;
+ },
+ primaryNavLinkConfigs,
+ );
+ primaryLinksRef.current = navLinksFromFlags;
+ }, [featureFlags]);
+
+ const language = useMemo(
+ () => (locale && locale.match("/^es/") ? "spanish" : "english"),
+ [locale],
+ );
return (
<>
@@ -85,7 +115,7 @@ const Header = ({ logoPath, locale }: Props) => {
/>
diff --git a/frontend/tests/components/Header.test.tsx b/frontend/tests/components/Header.test.tsx
index 1f8fb07f5..3b0178921 100644
--- a/frontend/tests/components/Header.test.tsx
+++ b/frontend/tests/components/Header.test.tsx
@@ -1,5 +1,5 @@
import userEvent from "@testing-library/user-event";
-import { render, screen } from "tests/react-utils";
+import { render, screen, waitFor } from "tests/react-utils";
import Header from "src/components/Header";
@@ -17,7 +17,27 @@ const props = {
],
};
+let searchFeatureFlag = false;
+
+const getSearchFeatureFlag = () => {
+ console.log("$$$", searchFeatureFlag);
+ return searchFeatureFlag;
+};
+
+jest.mock("src/hooks/useFeatureFlags", () => ({
+ useFeatureFlags: () => ({
+ featureFlagsManager: {
+ featureFlags: {
+ showSearchV0: getSearchFeatureFlag(),
+ },
+ },
+ }),
+}));
+
describe("Header", () => {
+ afterEach(() => {
+ searchFeatureFlag = false;
+ });
it("toggles the mobile nav menu", async () => {
render();
const menuButton = screen.getByTestId("navMenuButton");
@@ -50,4 +70,28 @@ describe("Header", () => {
expect(govBanner).toHaveAttribute("aria-expanded", "true");
});
+
+ it("displays expected nav links without feature flags", () => {
+ render();
+
+ const expectedNavLinks = ["Home", "Process", "Research", "Subscribe"];
+ expectedNavLinks.forEach((linkText) => {
+ const link = screen.getByText(linkText);
+ expect(link).toBeInTheDocument();
+ });
+ // ensure search is not included by default
+ try {
+ screen.getByText("Search");
+ } catch (_e) {
+ expect(false).toBeFalsy;
+ }
+ });
+
+ it("displays expected nav links without feature flags", async () => {
+ searchFeatureFlag = true;
+
+ render();
+
+ waitFor(() => expect(screen.getByText("Search")).toBeInTheDocument());
+ });
});