mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
Add the setup flow's confirm screen
What the answers switch on is read off the registry's derivation and never computed here, so the list the person confirms is the list the completion route writes. Units, language and time zone are shown once beside it, changeable in Settings, never asked again. The profile half keeps the baseline form and its per-field refusals: the fields are seeded from the account so a value it holds is confirmed rather than typed again, and a refused field still stops the flow. For "someone I look after" the managed-profile form takes the profile's place, because that record is created here, after the questions; an account without a second factor can finish without it and create it later under Settings. Confirming posts the completion, passes the first-result step outright when there is no task to offer, and goes where the step machine says.
This commit is contained in:
1 parent
7b279aec72
commit
58bc91a0a3
8 files changed
+459
-57
No files matched your search
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* v1.39 (C2) — the confirm screen's list is the registry's derivation and
|
||||
* nothing else.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
deriveOnboardingModuleDefaults,
|
||||
ONBOARDING_ALWAYS_ON_MODULES,
|
||||
OWNED_MODULE_KEYS,
|
||||
} from "@/lib/modules/registry";
|
||||
|
||||
import { confirmedModules } from "../confirm-summary";
|
||||
import { emptyOnboardingNeeds } from "../needs";
|
||||
|
||||
describe("confirmedModules", () => {
|
||||
it("lists exactly what the derivation switches on, the always-on trio aside", () => {
|
||||
const needs = {
|
||||
...emptyOnboardingNeeds(),
|
||||
recordTarget: "me" as const,
|
||||
areas: ["glucose" as const, "sleep" as const],
|
||||
medication: "yes" as const,
|
||||
visit: "within-a-month" as const,
|
||||
};
|
||||
const derived = deriveOnboardingModuleDefaults(needs);
|
||||
const expected = OWNED_MODULE_KEYS.filter(
|
||||
(key) =>
|
||||
derived.preferences[key] && !ONBOARDING_ALWAYS_ON_MODULES.includes(key),
|
||||
);
|
||||
const { chosen, alwaysOn } = confirmedModules(needs);
|
||||
expect(chosen).toEqual(expected);
|
||||
expect(chosen).toContain("medications");
|
||||
expect(chosen).toContain("doctorReport");
|
||||
// Registry order, so the two lists read in the same order everywhere.
|
||||
expect(alwaysOn).toEqual(
|
||||
OWNED_MODULE_KEYS.filter((key) =>
|
||||
ONBOARDING_ALWAYS_ON_MODULES.includes(key),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("names cycle when the area was ticked, though the map never owns it", () => {
|
||||
const { chosen } = confirmedModules({
|
||||
...emptyOnboardingNeeds(),
|
||||
recordTarget: "me",
|
||||
areas: ["cycle"],
|
||||
});
|
||||
expect(chosen).toContain("cycle");
|
||||
});
|
||||
|
||||
it("reads a skipped question as the route does — nothing switched on for it", () => {
|
||||
const { chosen } = confirmedModules({
|
||||
...emptyOnboardingNeeds(),
|
||||
recordTarget: "me",
|
||||
});
|
||||
expect(chosen).not.toContain("medications");
|
||||
expect(chosen).not.toContain("doctorReport");
|
||||
});
|
||||
|
||||
it("switches on the immunization log for a record somebody else runs", () => {
|
||||
expect(
|
||||
confirmedModules({
|
||||
...emptyOnboardingNeeds(),
|
||||
recordTarget: "someone-else",
|
||||
}).chosen,
|
||||
).toContain("vaccinations");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* v1.39 (C2) — what the confirm screen says is switched on.
|
||||
*
|
||||
* A READ of the registry's derivation, never a second mapping: the list the
|
||||
* person confirms is `deriveOnboardingModuleDefaults` applied to the same
|
||||
* answers `POST /api/onboarding/complete` will apply it to, with the same
|
||||
* conservative defaults for a skipped question. A wizard that computed its
|
||||
* own list would drift from the one the route actually writes, and the
|
||||
* confirm screen would then be confirming something else.
|
||||
*
|
||||
* What the route writes on top of this — the merge that never retracts a
|
||||
* module switched on by hand or one holding data — only ever ADDS to the
|
||||
* list, which is why the sentence beside it says "everything else stays
|
||||
* under Settings" rather than "is off".
|
||||
*/
|
||||
import {
|
||||
deriveOnboardingModuleDefaults,
|
||||
MODULE_KEYS,
|
||||
ONBOARDING_ALWAYS_ON_MODULES,
|
||||
type ModuleKey,
|
||||
} from "@/lib/modules/registry";
|
||||
|
||||
import type { OnboardingNeeds } from "./needs";
|
||||
|
||||
export interface ConfirmedModules {
|
||||
/** What the answers switch on, in registry order — the always-on trio aside. */
|
||||
chosen: ModuleKey[];
|
||||
/** On whatever the answers say. */
|
||||
alwaysOn: ModuleKey[];
|
||||
}
|
||||
|
||||
export function confirmedModules(needs: OnboardingNeeds): ConfirmedModules {
|
||||
const derived = deriveOnboardingModuleDefaults({
|
||||
// Q1 is required and a confirm screen is never reached without it; the
|
||||
// fallback only keeps the type total.
|
||||
recordTarget: needs.recordTarget ?? "me",
|
||||
areas: needs.areas,
|
||||
// The same defaults the route applies to a skipped question.
|
||||
medication: needs.medication ?? "no",
|
||||
visit: needs.visit ?? "no",
|
||||
});
|
||||
const on = new Set<ModuleKey>();
|
||||
for (const [key, value] of Object.entries(derived.preferences)) {
|
||||
if (value) on.add(key as ModuleKey);
|
||||
}
|
||||
if (derived.cycleTracking) on.add("cycle");
|
||||
const alwaysOn = new Set<ModuleKey>(ONBOARDING_ALWAYS_ON_MODULES);
|
||||
return {
|
||||
chosen: MODULE_KEYS.filter((key) => on.has(key) && !alwaysOn.has(key)),
|
||||
alwaysOn: MODULE_KEYS.filter((key) => alwaysOn.has(key)),
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user