Skip to content

Commit ef15eaf

Browse files
Merge branch 'alpha' into feat/issue-3259-public-referents-ux
2 parents d887df6 + 7910364 commit ef15eaf

13 files changed

Lines changed: 132 additions & 81 deletions

File tree

packages/app/src/app/layout.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import Script from "next/script";
44
import { MatomoAnalytics } from "~/modules/analytics";
55
import { SessionProviderWrapper } from "~/modules/auth";
66
import {
7-
Footer,
87
Header,
98
ImpersonateBanner,
10-
ResourceBanner,
9+
PublicChrome,
1110
SkipLinks,
1211
} from "~/modules/layout";
1312
import { ProfileModal } from "~/modules/profile";
@@ -59,8 +58,7 @@ export default function RootLayout({
5958
<ImpersonateBanner />
6059
<Header />
6160
{children}
62-
<ResourceBanner />
63-
<Footer />
61+
<PublicChrome />
6462
<ProfileModal />
6563
</TRPCReactProvider>
6664
</SessionProviderWrapper>

packages/app/src/e2e/admin.e2e.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ test("admin user can access /admin and sees backoffice page", async ({
1010
await expect(page.getByText("administrateur")).toBeVisible();
1111
});
1212

13+
test("admin routes hide the public footer and help banner", async ({
14+
page,
15+
}) => {
16+
// Runs in the authenticated `chromium` Playwright project (see
17+
// playwright.config.ts): `page.goto("/admin")` reaches the real backoffice
18+
// page, so the assertions below exercise the PublicChrome branch, not a
19+
// login-redirect fallback that would trivially pass.
20+
await page.goto("/admin");
21+
await expect(
22+
page.getByRole("heading", { name: "Backoffice", level: 1 }),
23+
).toBeVisible();
24+
await expect(page.locator("footer#footer")).toHaveCount(0);
25+
await expect(
26+
page.getByRole("region", { name: "Ressources et aide" }),
27+
).toHaveCount(0);
28+
});
29+
1330
test("admin user can access /admin/impersonate and sees impersonate page", async ({
1431
page,
1532
}) => {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { usePathname } from "next/navigation";
55

66
const adminLinks = [
77
{ href: "/admin", label: "Accueil" },
8+
{ href: "/admin/declarations", label: "Déclarations" },
89
{ href: "/admin/impersonate", label: "Mimoquer un Siren" },
910
{ href: "/admin/liste-referents", label: "Référents" },
1011
{ href: "/admin/parametres", label: "Paramètres" },

packages/app/src/modules/admin/__tests__/AdminNavigation.test.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ describe("AdminNavigation", () => {
1919
it("renders all admin links", () => {
2020
render(<AdminNavigation />);
2121
expect(screen.getByRole("link", { name: "Accueil" })).toBeInTheDocument();
22+
expect(
23+
screen.getByRole("link", { name: "Déclarations" }),
24+
).toBeInTheDocument();
2225
expect(
2326
screen.getByRole("link", { name: "Mimoquer un Siren" }),
2427
).toBeInTheDocument();
@@ -61,4 +64,28 @@ describe("AdminNavigation", () => {
6164
"aria-current",
6265
);
6366
});
67+
68+
it("marks /admin/declarations as active — and not Accueil", () => {
69+
(usePathname as Mock).mockReturnValue("/admin/declarations");
70+
render(<AdminNavigation />);
71+
expect(screen.getByRole("link", { name: "Déclarations" })).toHaveAttribute(
72+
"aria-current",
73+
"page",
74+
);
75+
expect(screen.getByRole("link", { name: "Accueil" })).not.toHaveAttribute(
76+
"aria-current",
77+
);
78+
});
79+
80+
it("marks /admin/declarations/<id> as active on the Déclarations link", () => {
81+
(usePathname as Mock).mockReturnValue("/admin/declarations/abc123");
82+
render(<AdminNavigation />);
83+
expect(screen.getByRole("link", { name: "Déclarations" })).toHaveAttribute(
84+
"aria-current",
85+
"page",
86+
);
87+
expect(screen.getByRole("link", { name: "Accueil" })).not.toHaveAttribute(
88+
"aria-current",
89+
);
90+
});
6491
});

packages/app/src/modules/admin/declarations/AdminDeclarationsPage.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ function DeclarationsContent() {
2222
dateFrom: searchParams.get("dateFrom") ?? undefined,
2323
dateTo: searchParams.get("dateTo") ?? undefined,
2424
status: (searchParams.get("status") as "draft" | "submitted") || undefined,
25-
index: searchParams.get("index")
26-
? Number(searchParams.get("index"))
27-
: undefined,
28-
indexOperator:
29-
(searchParams.get("indexOperator") as "gt" | "lt" | "eq") || undefined,
3025
page: Number(searchParams.get("page") ?? "1"),
3126
pageSize: Number(searchParams.get("pageSize") ?? String(DEFAULT_PAGE_SIZE)),
3227
sortBy: (searchParams.get("sortBy") as SortColumn) ?? "createdAt",

packages/app/src/modules/admin/declarations/SearchForm.tsx

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ export function SearchForm() {
2323
dateTo: searchParams.get("dateTo") ?? "",
2424
status:
2525
(searchParams.get("status") as "" | "draft" | "submitted") ?? "",
26-
index: searchParams.get("index") ?? "",
27-
indexOperator:
28-
(searchParams.get("indexOperator") as "" | "gt" | "lt" | "eq") ?? "",
2926
},
3027
},
3128
);
@@ -52,8 +49,6 @@ export function SearchForm() {
5249
dateFrom: "",
5350
dateTo: "",
5451
status: "",
55-
index: "",
56-
indexOperator: "",
5752
});
5853
router.push("/admin/declarations");
5954
}, [reset, router]);
@@ -144,42 +139,6 @@ export function SearchForm() {
144139
</select>
145140
</div>
146141
</div>
147-
<div className="fr-col-12 fr-col-md-3">
148-
<div className="fr-grid-row fr-grid-row--gutters">
149-
<div className="fr-col-6">
150-
<div className="fr-select-group">
151-
<label className="fr-label" htmlFor="search-index-op">
152-
Index
153-
</label>
154-
<select
155-
className="fr-select"
156-
id="search-index-op"
157-
{...register("indexOperator")}
158-
>
159-
<option value=""></option>
160-
<option value="eq">=</option>
161-
<option value="gt">&ge;</option>
162-
<option value="lt">&le;</option>
163-
</select>
164-
</div>
165-
</div>
166-
<div className="fr-col-6">
167-
<div className="fr-input-group">
168-
<label className="fr-label" htmlFor="search-index">
169-
Valeur
170-
</label>
171-
<input
172-
className="fr-input"
173-
id="search-index"
174-
max={100}
175-
min={0}
176-
type="number"
177-
{...register("index")}
178-
/>
179-
</div>
180-
</div>
181-
</div>
182-
</div>
183142
</div>
184143
<div className="fr-grid-row fr-grid-row--right fr-mt-2w">
185144
<ul className="fr-btns-group fr-btns-group--inline">

packages/app/src/modules/admin/declarations/__tests__/SearchForm.test.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ vi.mock("next/navigation", async () => {
2020
import { SearchForm } from "../SearchForm";
2121

2222
describe("SearchForm", () => {
23-
it("renders all search fields", () => {
23+
it("renders all search fields and omits the removed Index / Valeur pair", () => {
2424
render(<SearchForm />);
2525

2626
expect(screen.getByLabelText("SIREN / Nom entreprise")).toBeInTheDocument();
@@ -29,8 +29,10 @@ describe("SearchForm", () => {
2929
expect(screen.getByLabelText("Date de dépôt (du)")).toBeInTheDocument();
3030
expect(screen.getByLabelText("Date de dépôt (au)")).toBeInTheDocument();
3131
expect(screen.getByLabelText("Statut")).toBeInTheDocument();
32-
expect(screen.getByLabelText("Index")).toBeInTheDocument();
33-
expect(screen.getByLabelText("Valeur")).toBeInTheDocument();
32+
// Regression guard for #3274 — keep these negative assertions next to
33+
// their positive counterparts so a future reintroduction is caught here.
34+
expect(screen.queryByLabelText("Index")).not.toBeInTheDocument();
35+
expect(screen.queryByLabelText("Valeur")).not.toBeInTheDocument();
3436
});
3537

3638
it("renders search and reset buttons", () => {

packages/app/src/modules/admin/declarations/__tests__/schemas.test.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ describe("searchDeclarationsSchema", () => {
2020
year: "2024",
2121
dateFrom: "2024-01-01",
2222
dateTo: "2024-12-31",
23-
index: "75",
24-
indexOperator: "gt",
2523
status: "submitted",
2624
page: "2",
2725
pageSize: "50",
@@ -35,8 +33,6 @@ describe("searchDeclarationsSchema", () => {
3533
year: 2024,
3634
dateFrom: "2024-01-01",
3735
dateTo: "2024-12-31",
38-
index: 75,
39-
indexOperator: "gt",
4036
status: "submitted",
4137
page: 2,
4238
pageSize: 50,

packages/app/src/modules/admin/declarations/schemas.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ export const SORT_COLUMNS = [
1111

1212
export type SortColumn = (typeof SORT_COLUMNS)[number];
1313

14-
export const INDEX_OPERATORS = ["gt", "lt", "eq"] as const;
15-
16-
export type IndexOperator = (typeof INDEX_OPERATORS)[number];
17-
1814
export const DEFAULT_PAGE_SIZE = 20;
1915

2016
export const searchDeclarationsSchema = z.object({
@@ -23,8 +19,6 @@ export const searchDeclarationsSchema = z.object({
2319
year: z.coerce.number().int().min(2018).max(2100).optional(),
2420
dateFrom: z.string().date().optional().or(z.literal("")),
2521
dateTo: z.string().date().optional().or(z.literal("")),
26-
index: z.coerce.number().int().min(0).max(100).optional(),
27-
indexOperator: z.enum(INDEX_OPERATORS).optional(),
2822
status: z.enum(["draft", "submitted"]).optional(),
2923
page: z.coerce.number().int().min(1).default(1),
3024
pageSize: z.coerce.number().int().min(10).max(100).default(DEFAULT_PAGE_SIZE),
@@ -43,8 +37,6 @@ export const searchDeclarationsFormSchema = z.object({
4337
year: z.string().optional(),
4438
dateFrom: z.string().optional(),
4539
dateTo: z.string().optional(),
46-
index: z.string().optional(),
47-
indexOperator: z.enum(["", ...INDEX_OPERATORS]).optional(),
4840
status: z.enum(["", "draft", "submitted"]).optional(),
4941
});
5042

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"use client";
2+
3+
import { usePathname } from "next/navigation";
4+
5+
import { Footer } from "./Footer";
6+
import { ResourceBanner } from "./ResourceBanner";
7+
8+
/**
9+
* Renders the public help banner + footer on every route except the backoffice.
10+
* Admin pages (`/admin/**`) get a stripped-down chrome so the sidebar + admin
11+
* content fill the viewport without competing with public navigation.
12+
*/
13+
export function PublicChrome() {
14+
const pathname = usePathname();
15+
// Match the `/admin` segment boundary so hypothetical sibling routes like
16+
// `/administrator` or `/admin-tools` keep the public chrome.
17+
if (pathname === "/admin" || pathname?.startsWith("/admin/")) {
18+
return null;
19+
}
20+
return (
21+
<>
22+
<ResourceBanner />
23+
<Footer />
24+
</>
25+
);
26+
}

0 commit comments

Comments
 (0)