Skip to content

Commit 3ebec85

Browse files
author
Guillaume
committed
Merge branch 'refactor/nav-community-routes'
2 parents 7d6c1f2 + fb43e24 commit 3ebec85

29 files changed

Lines changed: 338 additions & 88 deletions

.ai/thought_log.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
## [2026-06-28] Cohérence navigation — Phase 1 : rename /palmares → /community (+ Face-à-face) — COMPLÉTÉ + vérifié
2+
3+
**Tâche** : refonte cohérence nav (plan 3 phases, `.ai/plans` zany-growing-marble). Phase 1 = aligner l'URL sur le libellé « Communauté ».
4+
5+
**Phase 1** :
6+
- Routes `routes/.../palmares/{index,relations,prestige}.tsx` + `compare.tsx` → `community/{index,relations,prestige,compare}.tsx` (URLs `/community/*`).
7+
- Anciennes URLs préservées par routes redirect (`beforeLoad → throw redirect`).
8+
- Callsites : `isCommunityPath` (matche /community + legacy), navL1Sections (defaultPath + onglets), NavL2 (COMMUNITY_*), pageTitle, classifyFeedback, deep-links Explorer/Career → /community/compare, PLAYER_PRIMARY_NAV_ITEMS (label Palmarès → Communauté). Fix en passant : notif `season_pass_level` → /career/season-pass (était /palmares, stale).
9+
- Backend inchangé (API /pages/palmares/* découplée). routeTree.gen.ts régénéré (vite build).
10+
11+
**Vérif** : build OK, typecheck, vitest 2048 pass (seul échec = `HomeSpartanIdentityBanner`, PRÉ-EXISTANT — commit Spartan d'un autre agent, hors de mon changeset), eslint 0 err, lint colors/fields/cross-feature + knip sous plafonds.
12+
13+
**Suite (plan)** : Phase 2 re-nesting (/synthesis→/stats/synthesis, /citations+commendations→/career/) ; Phase 3 onglets `?tab=` → segments de route (Timeseries, Match View). Convention : sous-vue = route, query-param = filtres, store = toggles.
14+
15+
---
16+
117
## [2026-06-28] Personnalisateur Spartan (emblèmes/nameplates Halo 5) — modale home + recolor live — COMPLÉTÉ + vérifié
218

319
**Tâche** : feature Halo-5-only. Clic sur la bannière d'identité de l'accueil → modale (sans navigation) pour parcourir les emblèmes, choisir des couleurs (rouge/bleu présélectionnés), voir le nameplate + l'emblème recolorisés EN DIRECT côte à côte (non collés), puis Enregistrer/Annuler. Plan : `.ai/PLAN_H5_SPARTAN_CUSTOMIZER.md`.

apps/web/src/components/shell/NavL1.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('NavL1', () => {
5858
})
5959

6060
it('marque Communauté actif sur les sous-routes du hub', () => {
61-
mockPathname = '/players/test-player/palmares/relations'
61+
mockPathname = '/players/test-player/community/relations'
6262

6363
renderWithProviders(<NavL1 />)
6464

apps/web/src/components/shell/NavL2.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ import { useCapability } from '@/lib/capabilities/capabilities'
2121
import { isCommunityPath } from './shellNavigation'
2222

2323
// Onglet « Classements » de la section Communauté (gaté sur world.leaderboard).
24-
const COMMUNITY_LEADERBOARD_PATH = '/players/$playerSlug/palmares'
24+
const COMMUNITY_LEADERBOARD_PATH = '/players/$playerSlug/community'
2525

2626
// ─── Sous-onglets de la section Carrière ──────────────────────────────────────
2727

2828
const CAREER_TABS = [
2929
{ label: 'Progression', path: '/players/$playerSlug/career' },
30-
{ label: 'Citations', path: '/players/$playerSlug/citations' },
30+
{ label: 'Citations', path: '/players/$playerSlug/career/citations' },
3131
{ label: 'Pass saisonnier', path: '/players/$playerSlug/career/season-pass' },
3232
] as const
3333

@@ -43,15 +43,15 @@ const CAREER_TABS_H5 = [
4343
{ label: 'Progression', path: '/players/$playerSlug/career' },
4444
// Halo 5 : commendations natives, libellé FR « Citations » (terme officiel Halo
4545
// FR, cohérent avec Infinite et l'onglet L1).
46-
{ label: 'Citations', path: '/players/$playerSlug/commendations' },
46+
{ label: 'Citations', path: '/players/$playerSlug/career/commendations' },
4747
] as const
4848

4949
// Communauté : aligné sur le dropdown L1 (NavL1 section 'community'). Face-à-face
5050
// pointe vers /compare (hors /palmares), d'où des chemins absolus par onglet.
5151
const COMMUNITY_TABS = [
52-
{ label: 'Classements', path: '/players/$playerSlug/palmares' },
53-
{ label: 'Relations', path: '/players/$playerSlug/palmares/relations' },
54-
{ label: 'Face-à-face', path: '/players/$playerSlug/compare' },
52+
{ label: 'Classements', path: '/players/$playerSlug/community' },
53+
{ label: 'Relations', path: '/players/$playerSlug/community/relations' },
54+
{ label: 'Face-à-face', path: '/players/$playerSlug/community/compare' },
5555
] as const
5656

5757
// ─── Helpers ──────────────────────────────────────────────────────────────────
@@ -63,6 +63,8 @@ const PERSONAL_STATS_RE = /\/players\/[^/]+\/stats\/(summary|maps-modes|distribu
6363

6464
function detectSection(pathname: string): ActiveSection {
6565
if (PERSONAL_STATS_RE.test(pathname)) return null
66+
// Synthèse gère sa propre barre de filtres (PeriodePill/SaisonPill) → pas de NavL2.
67+
if (/\/players\/[^/]+\/stats\/synthesis/.test(pathname)) return null
6668
if (/\/players\/[^/]+\/stats\//.test(pathname)) return 'stats'
6769
if (/\/players\/[^/]+\/squad/.test(pathname)) return 'squad'
6870
if (/\/players\/[^/]+\/(career|citations|commendations)/.test(pathname)) return 'career'

apps/web/src/components/shell/navL1Sections.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const L1_SECTIONS: L1Section[] = [
8484
defaultPath: '/players/$playerSlug/stats/timeseries',
8585
matchPathname: (p) => /\/players\/[^/]+\/(stats\/|synthesis)/.test(p),
8686
tabs: [
87-
{ key: 'synthesis', label: 'Synthèse', path: '/players/$playerSlug/synthesis' },
87+
{ key: 'synthesis', label: 'Synthèse', path: '/players/$playerSlug/stats/synthesis' },
8888
{ key: 'timeseries', label: 'Séries temporelles', path: '/players/$playerSlug/stats/timeseries' },
8989
{ key: 'sessions', label: 'Sessions', path: '/players/$playerSlug/stats/sessions' },
9090
],
@@ -107,7 +107,7 @@ export const L1_SECTIONS: L1Section[] = [
107107
matchPathname: (p) => /\/players\/[^/]+\/(career|citations|profile)/.test(p),
108108
tabs: [
109109
{ key: 'progression', label: 'Progression', path: '/players/$playerSlug/career' },
110-
{ key: 'citations', label: 'Citations', path: '/players/$playerSlug/citations' },
110+
{ key: 'citations', label: 'Citations', path: '/players/$playerSlug/career/citations' },
111111
{
112112
key: 'season-pass',
113113
label: 'Pass saisonnier',
@@ -135,19 +135,19 @@ export const L1_SECTIONS: L1Section[] = [
135135
{
136136
key: 'community',
137137
label: 'Communauté',
138-
defaultPath: '/players/$playerSlug/palmares',
138+
defaultPath: '/players/$playerSlug/community',
139139
matchPathname: isCommunityPath,
140140
// Section transverse non gatée (Relations / Face-à-face dérivent des matchs) ;
141141
// seul l'onglet « Classements » dépend de `world.leaderboard`.
142142
tabs: [
143143
{
144144
key: 'leaderboard',
145145
label: 'Classements',
146-
path: '/players/$playerSlug/palmares',
146+
path: '/players/$playerSlug/community',
147147
capability: 'world.leaderboard',
148148
},
149-
{ key: 'relations', label: 'Relations', path: '/players/$playerSlug/palmares/relations' },
150-
{ key: 'compare', label: 'Face-à-face', path: '/players/$playerSlug/compare' },
149+
{ key: 'relations', label: 'Relations', path: '/players/$playerSlug/community/relations' },
150+
{ key: 'compare', label: 'Face-à-face', path: '/players/$playerSlug/community/compare' },
151151
],
152152
},
153153
{

apps/web/src/components/shell/shellNavigation.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ describe('buildPlayerDestination', () => {
2929
)
3030
})
3131

32-
it('place Palmarès avant Carrière dans le parcours principal', () => {
32+
it('place Communauté avant Carrière dans le parcours principal', () => {
3333
const labels = PLAYER_PRIMARY_NAV_ITEMS.map((item) => item.label)
3434

35-
expect(labels.indexOf('Palmarès')).toBeGreaterThanOrEqual(0)
36-
expect(labels.indexOf('Palmarès')).toBeLessThan(labels.indexOf('Carrière'))
35+
expect(labels.indexOf('Communauté')).toBeGreaterThanOrEqual(0)
36+
expect(labels.indexOf('Communauté')).toBeLessThan(labels.indexOf('Carrière'))
3737
})
3838
})

apps/web/src/components/shell/shellNavigation.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export const PLAYER_PRIMARY_NAV_ITEMS: ShellNavItem[] = [
1818
description: 'Briefing, signaux chauds et accès prioritaires.',
1919
},
2020
{
21-
to: '/players/$playerSlug/palmares',
22-
label: 'Palmarès',
21+
to: '/players/$playerSlug/community',
22+
label: 'Communauté',
2323
eyebrow: 'Prestige',
2424
description: 'Classements, relations et face-à-face joueur à joueur.',
2525
},
@@ -57,7 +57,7 @@ export const PLAYER_SECONDARY_NAV_ITEMS: ShellNavItem[] = [
5757
description: 'Approfondir, filtrer et descendre dans le détail.',
5858
},
5959
{
60-
to: '/players/$playerSlug/synthesis',
60+
to: '/players/$playerSlug/stats/synthesis',
6161
label: 'Synthèse',
6262
eyebrow: 'Recap',
6363
description: 'Vue consolidée et transversale.',
@@ -78,11 +78,14 @@ export const GLOBAL_SHELL_LINKS: ShellUtilityLink[] = [
7878
* sous-onglets) pour garder les deux navs synchronisées.
7979
*/
8080
export function isCommunityPath(pathname: string): boolean {
81-
const palmares =
82-
/\/players\/[^/]+\/palmares(?:\/|$)/.test(pathname) &&
83-
!/\/palmares\/season-pass/.test(pathname)
84-
const compare = /\/players\/[^/]+\/compare/.test(pathname)
85-
return palmares || compare
81+
const community = /\/players\/[^/]+\/community(?:\/|$)/.test(pathname)
82+
// Legacy : ancien /palmares (hors season-pass passé sous Carrière) + ancien /compare,
83+
// encore surlignés Communauté le temps que les redirections vers /community s'appliquent.
84+
const legacy =
85+
(/\/players\/[^/]+\/palmares(?:\/|$)/.test(pathname) &&
86+
!/\/palmares\/season-pass/.test(pathname)) ||
87+
/\/players\/[^/]+\/compare(?:\/|$)/.test(pathname)
88+
return community || legacy
8689
}
8790

8891
export function buildPlayerDestination(

apps/web/src/features/career/CareerPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export function CareerPage() {
7777
<Button
7878
size="sm"
7979
variant="outline"
80-
onClick={() => void navigate({ to: '/players/$playerSlug/compare', params: { playerSlug } })}
80+
onClick={() => void navigate({ to: '/players/$playerSlug/community/compare', params: { playerSlug } })}
8181
>
8282
{t('career.actions.compare')}
8383
</Button>

apps/web/src/features/compare/ComparePage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ function MirrorHeader({
287287
export function ComparePage() {
288288
const { playerSlug } = useParams({ strict: false }) as { playerSlug: string }
289289
const navigate = useNavigate()
290-
const search = useSearch({ from: '/players/$playerSlug/compare' }) as {
290+
const search = useSearch({ from: '/players/$playerSlug/community/compare' }) as {
291291
target?: string
292292
target2?: string
293293
from?: 'explorer'
@@ -323,7 +323,7 @@ export function ComparePage() {
323323

324324
function handleComboChange(values: string[]) {
325325
void navigate({
326-
to: '/players/$playerSlug/compare',
326+
to: '/players/$playerSlug/community/compare',
327327
params: { playerSlug },
328328
search: {
329329
target: values[0] ?? undefined,

apps/web/src/features/explorer/ExplorerPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ export function ExplorerPage() {
184184

185185
function openHeadToHead(gamertag: string) {
186186
void navigate({
187-
to: '/players/$playerSlug/compare',
187+
to: '/players/$playerSlug/community/compare',
188188
params: { playerSlug },
189189
search: { target: gamertag, from: 'explorer' },
190190
})

apps/web/src/features/feedback-drawer/classifyFeedback.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ describe('matchArea — toutes les routes', () => {
126126
['/players/Foo/palmares/prestige', 'palmares'],
127127
['/players/Foo/palmares/relations', 'palmares'],
128128
['/players/Foo/palmares/season-pass', 'palmares'],
129+
['/players/Foo/community', 'palmares'],
130+
['/players/Foo/community/relations', 'palmares'],
129131
['/players/Foo/home', 'player_home'],
130132
['/players/Foo/media', 'media'],
131133
['/players/Foo/career', 'career'],

0 commit comments

Comments
 (0)