Skip to content

Commit 532e4af

Browse files
committed
feat(admin): add sidebar navigation with Accueil and Référents links
- Create AdminNavigation component with DSFR sidemenu pattern - Update admin layout to include sidebar + content grid - Remove duplicate fr-container from AdminHomePage
1 parent b5e7004 commit 532e4af

5 files changed

Lines changed: 100 additions & 3 deletions

File tree

packages/app/src/app/admin/layout.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { redirect } from "next/navigation";
22
import type { ReactNode } from "react";
33

4+
import { AdminNavigation } from "~/modules/admin";
45
import { auth } from "~/server/auth";
56

67
export default async function AdminLayout({
@@ -18,5 +19,14 @@ export default async function AdminLayout({
1819
redirect("/mon-espace");
1920
}
2021

21-
return <>{children}</>;
22+
return (
23+
<div className="fr-container fr-py-4w">
24+
<div className="fr-grid-row fr-grid-row--gutters">
25+
<div className="fr-col-12 fr-col-md-3">
26+
<AdminNavigation />
27+
</div>
28+
<div className="fr-col-12 fr-col-md-9">{children}</div>
29+
</div>
30+
</div>
31+
);
2232
}

packages/app/src/modules/admin/AdminHomePage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ type Props = {
55

66
export function AdminHomePage({ userName, userEmail }: Props) {
77
return (
8-
<div className="fr-container fr-py-6w">
8+
<>
99
<h1 className="fr-h1">Backoffice</h1>
1010
<p className="fr-text--lead">Bienvenue, {userName}.</p>
1111
<p>
1212
Vous êtes connecté en tant qu'administrateur avec l'adresse{" "}
1313
<strong>{userEmail}</strong>.
1414
</p>
15-
</div>
15+
</>
1616
);
1717
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"use client";
2+
3+
import Link from "next/link";
4+
import { usePathname } from "next/navigation";
5+
6+
const ADMIN_LINKS = [
7+
{ href: "/admin", label: "Accueil" },
8+
{ href: "/admin/liste-referents", label: "Référents" },
9+
] as const;
10+
11+
export function AdminNavigation() {
12+
const pathname = usePathname() ?? "";
13+
14+
return (
15+
<nav aria-label="Menu administration" className="fr-sidemenu">
16+
<div className="fr-sidemenu__inner">
17+
<button
18+
aria-controls="fr-sidemenu-wrapper"
19+
aria-expanded="false"
20+
className="fr-sidemenu__btn"
21+
type="button"
22+
>
23+
Administration
24+
</button>
25+
<div className="fr-collapse" id="fr-sidemenu-wrapper">
26+
<ul className="fr-sidemenu__list">
27+
{ADMIN_LINKS.map(({ href, label }) => {
28+
const isCurrent =
29+
href === "/admin"
30+
? pathname === "/admin"
31+
: pathname.startsWith(href);
32+
return (
33+
<li
34+
className={`fr-sidemenu__item ${isCurrent ? "fr-sidemenu__item--active" : ""}`}
35+
key={href}
36+
>
37+
<Link
38+
aria-current={isCurrent ? "page" : undefined}
39+
className="fr-sidemenu__link"
40+
href={href}
41+
>
42+
{label}
43+
</Link>
44+
</li>
45+
);
46+
})}
47+
</ul>
48+
</div>
49+
</div>
50+
</nav>
51+
);
52+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { render, screen } from "@testing-library/react";
2+
import { usePathname } from "next/navigation";
3+
import { describe, expect, it, vi } from "vitest";
4+
5+
import { AdminNavigation } from "../AdminNavigation";
6+
7+
describe("AdminNavigation", () => {
8+
it("renders navigation with all links", () => {
9+
vi.mocked(usePathname).mockReturnValue("/admin");
10+
render(<AdminNavigation />);
11+
expect(
12+
screen.getByRole("navigation", { name: "Menu administration" }),
13+
).toBeInTheDocument();
14+
expect(screen.getByText("Accueil")).toBeInTheDocument();
15+
expect(screen.getByText("Référents")).toBeInTheDocument();
16+
});
17+
18+
it("marks the admin home as active on /admin", () => {
19+
vi.mocked(usePathname).mockReturnValue("/admin");
20+
render(<AdminNavigation />);
21+
const homeLink = screen.getByText("Accueil");
22+
expect(homeLink).toHaveAttribute("aria-current", "page");
23+
});
24+
25+
it("marks referents as active on /admin/liste-referents", () => {
26+
vi.mocked(usePathname).mockReturnValue("/admin/liste-referents");
27+
render(<AdminNavigation />);
28+
const refLink = screen.getByText("Référents");
29+
expect(refLink).toHaveAttribute("aria-current", "page");
30+
const homeLink = screen.getByText("Accueil");
31+
expect(homeLink).not.toHaveAttribute("aria-current");
32+
});
33+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
export { AdminHomePage } from "./AdminHomePage";
2+
export { AdminNavigation } from "./AdminNavigation";
3+
export { AdminReferentsPage } from "./referents";

0 commit comments

Comments
 (0)