feat: Réorganiser la navigation admin en catégories pour améliorer l'UX mobile-first
Le menu d'administration contenait 13 liens à plat dans le header, ce qui débordait sur desktop et rendait le drawer mobile trop long à scanner. Les liens sont maintenant regroupés en 4 catégories (Personnes, Organisation, Année scolaire, Paramètres) avec des dropdowns au survol sur desktop et des accordéons repliables dans le drawer mobile. Le nombre d'éléments visibles passe de 13 à 5 (1 lien direct + 4 catégories), la catégorie active s'auto-déplie dans le menu mobile.
This commit is contained in:
@@ -119,6 +119,7 @@ test.describe('Admin Responsive Navigation', () => {
|
||||
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
||||
await expect(drawer).toBeVisible();
|
||||
|
||||
// Active category "Personnes" should be auto-expanded
|
||||
const activeLink = drawer.locator('.mobile-nav-link.active');
|
||||
await expect(activeLink).toHaveText('Utilisateurs');
|
||||
});
|
||||
@@ -128,11 +129,13 @@ test.describe('Admin Responsive Navigation', () => {
|
||||
await page.goto(`${ALPHA_URL}/admin/users`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Open menu and click Classes
|
||||
// Open menu and expand "Organisation" section to find "Classes"
|
||||
await page.getByRole('button', { name: /ouvrir le menu/i }).click();
|
||||
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
||||
await expect(drawer).toBeVisible();
|
||||
|
||||
// Expand "Organisation" accordion
|
||||
await drawer.getByRole('button', { name: 'Organisation' }).click();
|
||||
await drawer.getByRole('link', { name: 'Classes' }).click();
|
||||
|
||||
// Menu should close and page should navigate
|
||||
@@ -143,6 +146,30 @@ test.describe('Admin Responsive Navigation', () => {
|
||||
const label = page.locator('.mobile-section-label');
|
||||
await expect(label).toHaveText('Classes');
|
||||
});
|
||||
|
||||
test('accordion sections expand and collapse', async ({ page }) => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin/users`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
await page.getByRole('button', { name: /ouvrir le menu/i }).click();
|
||||
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
||||
await expect(drawer).toBeVisible();
|
||||
|
||||
// "Personnes" should be auto-expanded (active category)
|
||||
await expect(drawer.getByRole('link', { name: 'Utilisateurs' })).toBeVisible();
|
||||
|
||||
// "Organisation" should be collapsed initially
|
||||
await expect(drawer.getByRole('link', { name: 'Classes' })).not.toBeVisible();
|
||||
|
||||
// Expand "Organisation"
|
||||
await drawer.getByRole('button', { name: 'Organisation' }).click();
|
||||
await expect(drawer.getByRole('link', { name: 'Classes' })).toBeVisible();
|
||||
|
||||
// Collapse "Organisation"
|
||||
await drawer.getByRole('button', { name: 'Organisation' }).click();
|
||||
await expect(drawer.getByRole('link', { name: 'Classes' })).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
// =========================================================================
|
||||
@@ -163,7 +190,7 @@ test.describe('Admin Responsive Navigation', () => {
|
||||
await expect(desktopNav).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('drawer opens and works', async ({ page }) => {
|
||||
test('drawer opens and shows grouped nav', async ({ page }) => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin/users`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
@@ -172,8 +199,11 @@ test.describe('Admin Responsive Navigation', () => {
|
||||
const drawer = page.locator('[role="dialog"][aria-modal="true"]');
|
||||
await expect(drawer).toBeVisible();
|
||||
|
||||
// All nav links should be visible in drawer
|
||||
// "Personnes" auto-expanded (contains active link Utilisateurs)
|
||||
await expect(drawer.getByRole('link', { name: 'Utilisateurs' })).toBeVisible();
|
||||
|
||||
// Expand "Organisation" to see its links
|
||||
await drawer.getByRole('button', { name: 'Organisation' }).click();
|
||||
await expect(drawer.getByRole('link', { name: 'Classes' })).toBeVisible();
|
||||
await expect(drawer.getByRole('link', { name: 'Matières' })).toBeVisible();
|
||||
});
|
||||
@@ -197,18 +227,42 @@ test.describe('Admin Responsive Navigation', () => {
|
||||
await expect(desktopNav).toBeVisible();
|
||||
});
|
||||
|
||||
test('desktop nav shows all navigation links', async ({ page }) => {
|
||||
test('desktop nav shows category dropdowns', async ({ page }) => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin/users`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await expect(nav.getByRole('link', { name: 'Utilisateurs' })).toBeVisible();
|
||||
await expect(nav.getByRole('link', { name: 'Classes' })).toBeVisible();
|
||||
await expect(nav.getByRole('link', { name: 'Matières' })).toBeVisible();
|
||||
await expect(nav.getByRole('link', { name: 'Affectations' })).toBeVisible();
|
||||
await expect(nav.getByRole('link', { name: 'Périodes' })).toBeVisible();
|
||||
await expect(nav.getByRole('link', { name: 'Pédagogie' })).toBeVisible();
|
||||
|
||||
// Category triggers should be visible
|
||||
await expect(nav.getByRole('button', { name: /personnes/i })).toBeVisible();
|
||||
await expect(nav.getByRole('button', { name: /organisation/i })).toBeVisible();
|
||||
await expect(nav.getByRole('button', { name: /année scolaire/i })).toBeVisible();
|
||||
await expect(nav.getByRole('button', { name: /paramètres/i })).toBeVisible();
|
||||
|
||||
// Hover "Personnes" to reveal dropdown
|
||||
await nav.getByRole('button', { name: /personnes/i }).hover();
|
||||
const dropdown = nav.locator('.dropdown-panel').first();
|
||||
await expect(dropdown).toBeVisible();
|
||||
await expect(dropdown.getByRole('menuitem', { name: 'Utilisateurs' })).toBeVisible();
|
||||
await expect(dropdown.getByRole('menuitem', { name: 'Élèves' })).toBeVisible();
|
||||
|
||||
// Hover "Organisation"
|
||||
await nav.getByRole('button', { name: /organisation/i }).hover();
|
||||
const orgDropdown = nav.locator('.dropdown-panel').first();
|
||||
await expect(orgDropdown.getByRole('menuitem', { name: 'Classes' })).toBeVisible();
|
||||
await expect(orgDropdown.getByRole('menuitem', { name: 'Matières' })).toBeVisible();
|
||||
await expect(orgDropdown.getByRole('menuitem', { name: 'Affectations' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('active category trigger is highlighted', async ({ page }) => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin/users`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const nav = page.locator('.desktop-nav');
|
||||
const personnesTrigger = nav.getByRole('button', { name: /personnes/i });
|
||||
await expect(personnesTrigger).toHaveClass(/active/);
|
||||
});
|
||||
|
||||
test('hides mobile section label', async ({ page }) => {
|
||||
|
||||
@@ -83,7 +83,10 @@ test.describe('Calendar Management (Story 2.11)', () => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin/classes`);
|
||||
|
||||
await page.getByRole('link', { name: /calendrier/i }).click();
|
||||
// Hover "Année scolaire" category to reveal dropdown
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await nav.getByRole('button', { name: /année scolaire/i }).hover();
|
||||
await nav.getByRole('menuitem', { name: /calendrier/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/admin\/calendar/);
|
||||
await expect(
|
||||
|
||||
@@ -59,7 +59,10 @@ test.describe('Pedagogy - Grading Mode Configuration (Story 2.4)', () => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin/classes`);
|
||||
|
||||
const pedagogyLink = page.getByRole('link', { name: /pédagogie/i });
|
||||
// Hover "Paramètres" category to reveal dropdown
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await nav.getByRole('button', { name: /paramètres/i }).hover();
|
||||
const pedagogyLink = nav.getByRole('menuitem', { name: /pédagogie/i });
|
||||
await expect(pedagogyLink).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -67,7 +70,10 @@ test.describe('Pedagogy - Grading Mode Configuration (Story 2.4)', () => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin/classes`);
|
||||
|
||||
await page.getByRole('link', { name: /pédagogie/i }).click();
|
||||
// Hover "Paramètres" category to reveal dropdown
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await nav.getByRole('button', { name: /paramètres/i }).hover();
|
||||
await nav.getByRole('menuitem', { name: /pédagogie/i }).click();
|
||||
await expect(page).toHaveURL(/\/admin\/pedagogy/, { timeout: 10000 });
|
||||
});
|
||||
|
||||
|
||||
@@ -288,8 +288,10 @@ test.describe('Periods Management (Story 2.3)', () => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin`);
|
||||
|
||||
// Click on periods link in the admin navigation
|
||||
await page.getByRole('link', { name: /périodes/i }).click();
|
||||
// Hover "Année scolaire" category to reveal dropdown
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await nav.getByRole('button', { name: /année scolaire/i }).hover();
|
||||
await nav.getByRole('menuitem', { name: /périodes/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/admin\/academic-year\/periods/);
|
||||
await expect(page.getByRole('heading', { name: /périodes scolaires/i })).toBeVisible();
|
||||
|
||||
@@ -184,10 +184,14 @@ test.describe('Role-Based Access Control [P0]', () => {
|
||||
await loginAs(page, ADMIN_EMAIL, ADMIN_PASSWORD);
|
||||
await page.goto(`${ALPHA_URL}/admin`);
|
||||
|
||||
// Admin layout should show navigation links (scoped to desktop nav to avoid action cards)
|
||||
// Admin layout should show grouped navigation (category triggers in desktop nav)
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await expect(nav.getByRole('link', { name: 'Utilisateurs' })).toBeVisible({ timeout: 15000 });
|
||||
await expect(nav.getByRole('link', { name: 'Classes' })).toBeVisible();
|
||||
await expect(nav.getByRole('button', { name: /personnes/i })).toBeVisible({ timeout: 15000 });
|
||||
await expect(nav.getByRole('button', { name: /organisation/i })).toBeVisible();
|
||||
|
||||
// Hover to reveal dropdown links
|
||||
await nav.getByRole('button', { name: /personnes/i }).hover();
|
||||
await expect(nav.getByRole('menuitem', { name: 'Utilisateurs' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('[P0] teacher sees dashboard without admin navigation', async ({ page }) => {
|
||||
|
||||
@@ -145,8 +145,10 @@ test.describe('Student Creation & Management (Story 3.0)', () => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin/students`);
|
||||
|
||||
// The nav should have an active "Élèves" link
|
||||
await expect(page.locator('nav a', { hasText: /élèves/i })).toBeVisible({
|
||||
// Hover "Personnes" category to reveal dropdown with "Élèves" link
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await nav.getByRole('button', { name: /personnes/i }).hover();
|
||||
await expect(nav.getByRole('menuitem', { name: /élèves/i })).toBeVisible({
|
||||
timeout: 10000
|
||||
});
|
||||
});
|
||||
|
||||
@@ -118,7 +118,10 @@ test.describe('Teacher Assignments (Story 2.8)', () => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin`);
|
||||
|
||||
const navLink = page.getByRole('link', { name: /affectations/i });
|
||||
// Hover "Organisation" category to reveal dropdown
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await nav.getByRole('button', { name: /organisation/i }).hover();
|
||||
const navLink = nav.getByRole('menuitem', { name: /affectations/i });
|
||||
await expect(navLink).toBeVisible({ timeout: 15000 });
|
||||
});
|
||||
|
||||
|
||||
@@ -121,7 +121,10 @@ test.describe('Teacher Replacements (Story 2.9)', () => {
|
||||
await loginAsAdmin(page);
|
||||
await page.goto(`${ALPHA_URL}/admin`);
|
||||
|
||||
const navLink = page.getByRole('link', { name: /remplacements/i });
|
||||
// Hover "Organisation" category to reveal dropdown
|
||||
const nav = page.locator('.desktop-nav');
|
||||
await nav.getByRole('button', { name: /organisation/i }).hover();
|
||||
const navLink = nav.getByRole('menuitem', { name: /remplacements/i });
|
||||
await expect(navLink).toBeVisible({ timeout: 15000 });
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user