mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 06:32:03 +00:00
fix(onboarding): confirm names the modules leaving the nav
The screen listed what the answers switch on and said everything else stays one click away under Settings, Modules. That is true of reachability and false of the navigation entry: a module the answers do not ask for is written off by the completion's derivation. It now names those modules, read through the registry's own merge rule and intersected with the map the navigation shows today, so nothing is claimed about a module the account payload says nothing about.
This commit is contained in:
1 parent
77a09a5080
commit
e9e4a4b44d
11 files changed
+201
-2
No files matched your search
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* v1.39 (Wave C) — what the confirm screen is allowed to claim.
|
||||
*
|
||||
* C4 (research I6): the screen listed what the answers switch ON and said
|
||||
* everything else "stays one click away under Settings, Modules" — true of
|
||||
* reachability, false of the navigation entry. A module the answers do not
|
||||
* ask for leaves the navigation, and nothing said so.
|
||||
*
|
||||
* Rendered server-side, this repo's component-test convention.
|
||||
*/
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
import type { AuthUser } from "@/hooks/use-auth";
|
||||
import {
|
||||
defaultOnboardingSteps,
|
||||
emptyOnboardingNeeds,
|
||||
type OnboardingStateDto,
|
||||
} from "@/lib/onboarding/needs";
|
||||
|
||||
let currentUser: AuthUser | null = null;
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({ push: vi.fn(), replace: vi.fn() }),
|
||||
}));
|
||||
|
||||
vi.mock("@/hooks/use-auth", () => ({
|
||||
useAuth: () => ({ user: currentUser }),
|
||||
useAccountOnceMounted: () => currentUser,
|
||||
}));
|
||||
|
||||
const { ConfirmScreen } = await import("../confirm-screen");
|
||||
|
||||
function state(
|
||||
overrides: Partial<OnboardingStateDto> = {},
|
||||
needs: Partial<OnboardingStateDto["needs"]> = {},
|
||||
): OnboardingStateDto {
|
||||
return {
|
||||
steps: defaultOnboardingSteps(),
|
||||
needs: { ...emptyOnboardingNeeds(), recordTarget: "me", ...needs },
|
||||
completedAt: null,
|
||||
firstResult: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function render(
|
||||
flow: OnboardingStateDto,
|
||||
modules: Partial<Record<string, boolean>> = {},
|
||||
): string {
|
||||
currentUser = {
|
||||
id: "u1",
|
||||
heightCm: null,
|
||||
dateOfBirth: null,
|
||||
gender: null,
|
||||
timezone: "Europe/Berlin",
|
||||
unitPreference: "metric",
|
||||
modules,
|
||||
} as unknown as AuthUser;
|
||||
return renderToStaticMarkup(
|
||||
<QueryClientProvider client={new QueryClient()}>
|
||||
<I18nProvider initialLocale="en">
|
||||
<ConfirmScreen state={flow} />
|
||||
</I18nProvider>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe("<ConfirmScreen> — modules leaving the navigation (C4)", () => {
|
||||
it("names them when the answers do not ask for what the record shows", () => {
|
||||
const html = render(state({}, { areas: ["sleep"], medication: "no" }), {
|
||||
medications: true,
|
||||
});
|
||||
expect(html).toContain('data-slot="onboarding-confirm-modules-off"');
|
||||
expect(html).toContain("Medications");
|
||||
});
|
||||
|
||||
it("says nothing when the answers take nothing away", () => {
|
||||
const html = render(state({}, { areas: ["sleep"], medication: "yes" }), {
|
||||
medications: true,
|
||||
});
|
||||
expect(html).not.toContain('data-slot="onboarding-confirm-modules-off"');
|
||||
});
|
||||
});
|
||||
@@ -112,7 +112,12 @@ export function ConfirmScreen({ state }: { state: OnboardingStateDto }) {
|
||||
|
||||
const needs = state.needs;
|
||||
const forSomeoneElse = needs.recordTarget === "someone-else";
|
||||
const { chosen, alwaysOn } = confirmedModules(needs);
|
||||
// v1.39 (Wave C, C4) — `user.modules` is the map the navigation reads, so
|
||||
// the screen can only name a module the person actually has today.
|
||||
const { chosen, alwaysOn, wouldSwitchOff } = confirmedModules(
|
||||
needs,
|
||||
user?.modules ?? {},
|
||||
);
|
||||
const back = previousScreen(state, "confirm");
|
||||
|
||||
const glucoseUnit = needs.units.glucoseUnit ?? user?.glucoseUnit ?? null;
|
||||
@@ -182,6 +187,13 @@ export function ConfirmScreen({ state }: { state: OnboardingStateDto }) {
|
||||
})
|
||||
: t("onboarding.flow.confirm.nothingExtra")}
|
||||
</p>
|
||||
{wouldSwitchOff.length > 0 ? (
|
||||
<p className="text-sm" data-slot="onboarding-confirm-modules-off">
|
||||
{t("onboarding.flow.confirm.switchesOff", {
|
||||
modules: moduleNames(wouldSwitchOff),
|
||||
})}
|
||||
</p>
|
||||
) : null}
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("onboarding.flow.confirm.alwaysOn", {
|
||||
modules: moduleNames(alwaysOn),
|
||||
|
||||
Reference in new issue
Block a user