mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
feat(nav): give the Coach a single primary nav home
The Coach is reachable from seven scattered entry points — a floating button, the hero CTA, suggested-prompt chips, every metric empty state, a per-metric icon, the conversations drawer — but it had no entry in the nav. Power users found it instantly; a new user could miss the differentiator entirely behind a 56px floating circle. Add the Coach to the shared destination model as one labeled, primary home, consistent with every other destination across desktop and mobile. The existing entry points stay; this adds the front door they lacked.
This commit is contained in:
1 parent
c90459a7bd
commit
9bedd6b4f8
9 files changed
+47
-13
No files matched your search
@@ -228,6 +228,7 @@
|
||||
"accountSettings": "Kontoeinstellungen",
|
||||
"mood": "Stimmung",
|
||||
"workouts": "Workouts",
|
||||
"coach": "Coach",
|
||||
"skipToContent": "Zum Inhalt springen",
|
||||
"sidebar": "Sidebar",
|
||||
"mainNavigation": "Hauptnavigation",
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
"accountSettings": "Account settings",
|
||||
"mood": "Mood",
|
||||
"workouts": "Workouts",
|
||||
"coach": "Coach",
|
||||
"skipToContent": "Skip to content",
|
||||
"sidebar": "Sidebar",
|
||||
"mainNavigation": "Main navigation",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
"accountSettings": "Impostazioni account",
|
||||
"mood": "Umore",
|
||||
"workouts": "Allenamenti",
|
||||
"coach": "Coach",
|
||||
"skipToContent": "Vai al contenuto",
|
||||
"sidebar": "Barra laterale",
|
||||
"mainNavigation": "Navigazione principale",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -131,24 +131,25 @@ describe("<SidebarNav> targets deprecation (v1.8.6)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("<SidebarNav> 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("<SidebarNav> 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(
|
||||
/<a[^>]*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(/<a[^>]*href="\/insights\/coach"[^>]*>/);
|
||||
const insights = html.match(/<a[^>]*href="\/insights"[^>]*>/);
|
||||
expect(workouts?.[0]).toMatch(/aria-current="page"/);
|
||||
expect(coach?.[0]).toMatch(/aria-current="page"/);
|
||||
expect(insights?.[0]).not.toMatch(/aria-current="page"/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
FlaskConical,
|
||||
Home,
|
||||
Lightbulb,
|
||||
MessagesSquare,
|
||||
Pill,
|
||||
Trophy,
|
||||
Waves,
|
||||
@@ -87,6 +88,16 @@ export const NAV_DESTINATIONS: ReadonlyArray<NavDestination> = [
|
||||
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",
|
||||
|
||||
Reference in new issue
Block a user