diff --git a/messages/de.json b/messages/de.json index a00c1da74..569854ee4 100644 --- a/messages/de.json +++ b/messages/de.json @@ -228,6 +228,7 @@ "accountSettings": "Kontoeinstellungen", "mood": "Stimmung", "workouts": "Workouts", + "coach": "Coach", "skipToContent": "Zum Inhalt springen", "sidebar": "Sidebar", "mainNavigation": "Hauptnavigation", diff --git a/messages/en.json b/messages/en.json index 982cde664..adfa22579 100644 --- a/messages/en.json +++ b/messages/en.json @@ -228,6 +228,7 @@ "accountSettings": "Account settings", "mood": "Mood", "workouts": "Workouts", + "coach": "Coach", "skipToContent": "Skip to content", "sidebar": "Sidebar", "mainNavigation": "Main navigation", diff --git a/messages/es.json b/messages/es.json index d8a572cc4..2d284fe6d 100644 --- a/messages/es.json +++ b/messages/es.json @@ -228,6 +228,7 @@ "accountSettings": "Ajustes de cuenta", "mood": "Estado de ánimo", "workouts": "Entrenamientos", + "coach": "Coach", "skipToContent": "Saltar al contenido", "sidebar": "Barra lateral", "mainNavigation": "Navegación principal", diff --git a/messages/fr.json b/messages/fr.json index 52f5b9d53..2e480080f 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -228,6 +228,7 @@ "accountSettings": "Paramètres du compte", "mood": "Humeur", "workouts": "Entraînements", + "coach": "Coach", "skipToContent": "Aller au contenu", "sidebar": "Barre latérale", "mainNavigation": "Navigation principale", diff --git a/messages/it.json b/messages/it.json index 7c50a8d29..b52b754a8 100644 --- a/messages/it.json +++ b/messages/it.json @@ -228,6 +228,7 @@ "accountSettings": "Impostazioni account", "mood": "Umore", "workouts": "Allenamenti", + "coach": "Coach", "skipToContent": "Vai al contenuto", "sidebar": "Barra laterale", "mainNavigation": "Navigazione principale", diff --git a/messages/pl.json b/messages/pl.json index f96c44bb7..02f4a3914 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -228,6 +228,7 @@ "accountSettings": "Ustawienia konta", "mood": "Nastrój", "workouts": "Treningi", + "coach": "Coach", "skipToContent": "Przejdź do treści", "sidebar": "Pasek boczny", "mainNavigation": "Nawigacja główna", diff --git a/src/components/layout/__tests__/nav-model.test.ts b/src/components/layout/__tests__/nav-model.test.ts index b522a43b8..86484cb44 100644 --- a/src/components/layout/__tests__/nav-model.test.ts +++ b/src/components/layout/__tests__/nav-model.test.ts @@ -16,9 +16,18 @@ import { } from "../nav-model"; describe("nav-model destination list", () => { - it("lists Workouts as a first-class destination on both surfaces", () => { + it("lists Workouts and Coach as first-class destinations", () => { const hrefs = NAV_DESTINATIONS.map((d) => d.href); expect(hrefs).toContain("/insights/workouts"); + expect(hrefs).toContain("/insights/coach"); + }); + + it("gives the Coach exactly one nav home (F-3)", () => { + const coach = NAV_DESTINATIONS.filter( + (d) => d.href === "/insights/coach", + ); + expect(coach).toHaveLength(1); + expect(coach[0]!.tKey).toBe("nav.coach"); }); it("orders the core spine: dashboard → measurements → mood → medications", () => { @@ -57,6 +66,13 @@ describe("isNavDestinationActive most-specific resolution", () => { expect(isNavDestinationActive("/", "/measurements")).toBe(false); }); + it("does not light up Insights when on its Coach sibling", () => { + expect(isNavDestinationActive("/insights/coach", "/insights/coach")).toBe( + true, + ); + expect(isNavDestinationActive("/insights", "/insights/coach")).toBe(false); + }); + it("does not light up Insights when on its Workouts sibling", () => { expect( isNavDestinationActive("/insights/workouts", "/insights/workouts"), diff --git a/src/components/layout/__tests__/sidebar-nav.test.tsx b/src/components/layout/__tests__/sidebar-nav.test.tsx index a0db7aa88..82955553a 100644 --- a/src/components/layout/__tests__/sidebar-nav.test.tsx +++ b/src/components/layout/__tests__/sidebar-nav.test.tsx @@ -131,24 +131,25 @@ describe(" targets deprecation (v1.8.6)", () => { }); }); -describe(" unified destination model (v1.17.1 F-1)", () => { - it("surfaces Workouts as a first-class sidebar destination", () => { - // Pre-unify the sidebar hid Workouts entirely while the mobile bar - // promoted it. Both now render the one shared model, so both carry it. +describe(" unified destination model (v1.17.1 F-1 / F-3)", () => { + it("surfaces Workouts and the Coach as first-class sidebar destinations", () => { + // Pre-unify the sidebar hid Workouts entirely and had no Coach home, + // while the mobile bar promoted Workouts and still missed Coach. Both + // now render the one shared model, so both carry both destinations. const html = render(); expect(html).toContain('href="/insights/workouts"'); + expect(html).toContain('href="/insights/coach"'); expect(html).toContain("Workouts"); + expect(html).toContain("Coach"); }); - it("marks Workouts active without also marking Insights active", () => { - const html = render({ pathname: "/insights/workouts" }); - // The Workouts link carries aria-current="page"; the Insights link, - // its less-specific sibling, must not (most-specific resolution). - const workouts = html.match( - /]*href="\/insights\/workouts"[^>]*>/, - ); + it("marks Coach active without also marking Insights active", () => { + const html = render({ pathname: "/insights/coach" }); + // The Coach link carries aria-current="page"; the Insights link, its + // less-specific sibling, must not (most-specific resolution). + const coach = html.match(/]*href="\/insights\/coach"[^>]*>/); const insights = html.match(/]*href="\/insights"[^>]*>/); - expect(workouts?.[0]).toMatch(/aria-current="page"/); + expect(coach?.[0]).toMatch(/aria-current="page"/); expect(insights?.[0]).not.toMatch(/aria-current="page"/); }); }); diff --git a/src/components/layout/nav-model.ts b/src/components/layout/nav-model.ts index da7109d54..75ff2b4d4 100644 --- a/src/components/layout/nav-model.ts +++ b/src/components/layout/nav-model.ts @@ -5,6 +5,7 @@ import { FlaskConical, Home, Lightbulb, + MessagesSquare, Pill, Trophy, Waves, @@ -87,6 +88,16 @@ export const NAV_DESTINATIONS: ReadonlyArray = [ icon: Lightbulb, tourId: "nav-insights", }, + // v1.17.1 (F-3) — the Coach finally gets a single labeled nav home. It + // was reachable from seven scattered entry points (FAB, hero CTA, empty + // states, per-metric icons …) but nowhere in the nav, so a new user + // could miss the differentiator entirely. The other entry points stay. + { + href: "/insights/coach", + tKey: "nav.coach", + icon: MessagesSquare, + tourId: "nav-coach", + }, { href: "/achievements", tKey: "nav.achievements",