Эх сурвалжийг харах

RHL-032 feat(nav): implement primary navigation logic and tests for active route determination

Code_Uwe 1 долоо хоног өмнө
parent
commit
beaf58615e

+ 32 - 0
lib/frontend/nav/activeRoute.js

@@ -0,0 +1,32 @@
+import { isValidBranchParam } from "@/lib/frontend/params";
+
+export const PRIMARY_NAV = Object.freeze({
+	EXPLORER: "explorer",
+	SEARCH: "search",
+});
+
+/**
+ * Determine which primary navigation item should be active based on pathname.
+ *
+ * Rules:
+ * - Search is active when pathname matches "/:branch/search" (or below).
+ * - Explorer is active for any "/:branch/..." route that is not search.
+ * - If the first segment is not a valid branch, no nav item is active.
+ *
+ * @param {string} pathname
+ * @returns {{ active: "explorer"|"search", branch: string } | null}
+ */
+export function getPrimaryNavFromPathname(pathname) {
+	if (typeof pathname !== "string" || !pathname.startsWith("/")) return null;
+
+	const parts = pathname.split("/").filter(Boolean);
+	if (parts.length === 0) return null;
+
+	const branch = parts[0];
+	if (!isValidBranchParam(branch)) return null;
+
+	const active =
+		parts[1] === "search" ? PRIMARY_NAV.SEARCH : PRIMARY_NAV.EXPLORER;
+
+	return { active, branch };
+}

+ 42 - 0
lib/frontend/nav/activeRoute.test.js

@@ -0,0 +1,42 @@
+/* @vitest-environment node */
+
+import { describe, it, expect } from "vitest";
+import { getPrimaryNavFromPathname, PRIMARY_NAV } from "./activeRoute.js";
+
+describe("lib/frontend/nav/activeRoute", () => {
+	it("returns null for non-branch routes", () => {
+		expect(getPrimaryNavFromPathname("/")).toBe(null);
+		expect(getPrimaryNavFromPathname("/login")).toBe(null);
+		expect(getPrimaryNavFromPathname("/forbidden")).toBe(null);
+		expect(getPrimaryNavFromPathname("/search")).toBe(null);
+	});
+
+	it("marks explorer active for /:branch and /:branch/... (non-search)", () => {
+		expect(getPrimaryNavFromPathname("/NL01")).toEqual({
+			active: PRIMARY_NAV.EXPLORER,
+			branch: "NL01",
+		});
+
+		expect(getPrimaryNavFromPathname("/NL01/2025/12/31")).toEqual({
+			active: PRIMARY_NAV.EXPLORER,
+			branch: "NL01",
+		});
+	});
+
+	it("marks search active for /:branch/search", () => {
+		expect(getPrimaryNavFromPathname("/NL01/search")).toEqual({
+			active: PRIMARY_NAV.SEARCH,
+			branch: "NL01",
+		});
+
+		expect(getPrimaryNavFromPathname("/NL01/search/anything")).toEqual({
+			active: PRIMARY_NAV.SEARCH,
+			branch: "NL01",
+		});
+	});
+
+	it("returns null for invalid branch segment", () => {
+		expect(getPrimaryNavFromPathname("/nl01")).toBe(null);
+		expect(getPrimaryNavFromPathname("/XX01")).toBe(null);
+	});
+});