Carry the setup answers into the checklist, Settings and the module pages

The getting-started checklist reads the answers: a visit named within a
month adds a "prepare the visit" row that is done once one is on the
calendar, and the data-source row names the wearable that was chosen.
Its per-browser state moves to one module so the done screen, the skip
and Settings write the same keys.

Settings → Account gains the two ways back in: "Set up again" through
the restart route, which resets the ledger, keeps the answers as
prefill and touches no module; and "Show the checklist again", which
forgets what this browser hid.

A page whose module is off now answers with the shared notice and the
one action that helps, in one place for every module page: the shell
maps the route to the module through the navigation model's own gate,
so a page and its nav entry cannot disagree about which switch they
follow. And the tour's two dead stops get their anchors on the
integrations and health-record group headings.
This commit is contained in:
Marc-André Bombeck committed 2026-09-10 15:41:06 +02:00
1 parent a062610895
commit ec82ad3a93
13 files changed
+325 -16

No files matched your search

@@ -48,6 +48,7 @@ import {
type StatusMessage,
} from "./account-section-utils";
import { AvatarSection } from "./avatar-section";
import { SetupCard } from "./setup-card";
export { resolveInitialTimezone } from "./account-section-utils";
@@ -330,6 +331,10 @@ export function AccountSection() {
{/* Profile photo card */}
<AvatarSection />
{/* v1.39 (C2) — the way back into the first-run experience: the setup
questions again, and the dashboard checklist this browser hid. */}
<SetupCard />
<SettingsCard>
<SettingsCardHeader icon={User} title={t("settings.profile")} />
<form onSubmit={handleSaveProfile} className="space-y-4">
@@ -0,0 +1,88 @@
"use client";
import { useRouter } from "next/navigation";
import { toast } from "sonner";
import { ListChecks, Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { SettingsCard } from "@/components/settings/settings-card";
import { SettingsCardActions } from "@/components/settings/_card-actions";
import { SettingsCardHeader } from "@/components/settings/_card-header";
import { useOnboardingRestart } from "@/components/onboarding/use-onboarding-flow";
import { localizedApiError } from "@/lib/api/localized-error";
import { useTranslations } from "@/lib/i18n/context";
import { resetChecklistDismissals } from "@/lib/onboarding/checklist-storage";
/**
* v1.39 (C2) — Settings → Account → Setup.
*
* The two ways back into the first-run experience (design spec §Principles 4
* and §After the flow). "Set up again" asks the questions once more through
* the restart route, which resets the ledger and keeps the answers as
* prefill — and writes no module state, so a module switched on by hand is
* never switched off by a re-run. "Show the checklist again" forgets what
* this browser hid; the checklist's dismissals live in the browser, so the
* button lives on the same origin.
*/
export function SetupCard() {
const { t } = useTranslations();
const router = useRouter();
const restart = useOnboardingRestart();
async function setUpAgain() {
if (restart.isPending) return;
try {
await restart.mutateAsync();
router.push("/onboarding/who");
} catch (err) {
toast.error(localizedApiError(err, t, "onboarding.errorGeneric"));
}
}
function showChecklist() {
const hadState = resetChecklistDismissals();
toast.success(
hadState
? t("settings.setup.checklistShown")
: t("settings.setup.checklistNothingHidden"),
);
}
return (
<SettingsCard data-slot="settings-setup-card">
<SettingsCardHeader
icon={ListChecks}
title={t("settings.setup.title")}
description={t("settings.setup.description")}
/>
<SettingsCardActions>
<Button
type="button"
variant="outline"
size="sm"
className="min-h-11"
onClick={showChecklist}
data-slot="settings-show-checklist"
>
{t("settings.setup.showChecklist")}
</Button>
<Button
type="button"
size="sm"
className="min-h-11"
onClick={setUpAgain}
disabled={restart.isPending}
data-slot="settings-set-up-again"
>
{restart.isPending ? (
<Loader2
aria-hidden="true"
className="size-4 animate-spin motion-reduce:animate-none"
/>
) : null}
{t("settings.setup.setUpAgain")}
</Button>
</SettingsCardActions>
</SettingsCard>
);
}
@@ -43,6 +43,8 @@ export function GesundheitsakteSection() {
<section id="sharing" className="scroll-mt-28 space-y-4">
<SectionHeading
// The module tour's "export" stop (the doctor report) anchors here.
tourId="export-hero"
icon={Share2}
title={t("settings.sections.sharing.title")}
subtitle={t("settings.sections.sharing.subtitle")}
@@ -64,6 +64,8 @@ export function IntegrationsSection({
<SectionHeading
icon={Link2}
title={t("settings.sections.integrations.connectionsHeading")}
// The module tour's "integrations" stop anchors here.
tourId="integrations-hero"
/>
<ConnectionsPanel callbackUrls={callbackUrls} />