Merge remote-tracking branch 'origin/main' into release/v1.47.5

# Conflicts:
#	src/__tests__/baselines/source-file-lines.json
#	src/__tests__/baselines/source-function-lines.json
#	src/__tests__/baselines/test-as-never.json
#	src/__tests__/baselines/version-stamp-comments.json
#	src/__tests__/sharing-surface-guard.test.ts
This commit is contained in:
Marc-André Bombeck committed 2026-11-12 14:25:05 +01:00
commit 5ac998e4f0
112 files changed
+1816 -593

No files matched your search

@@ -117,11 +117,11 @@ describe("<DoneScreen> AI line", () => {
);
expect(line).not.toBeNull();
expect(line![1]).toContain("AI is optional");
expect(line![1]).toContain('href="/settings/ai"');
// No sample briefing, no provider ladder, no one-tap offer.
expect(html).not.toContain("Example");
expect(html).not.toContain("Three ways to turn it on");
expect(html).not.toMatch(/<button[^>]*>[^<]*Turn on/);
// Body copy, not meta: the line is read, so it is not muted.
expect(line![0]).not.toContain("text-muted-foreground");
// One way on, the link, and no one-tap offer beside it.
expect(html.split('href="/settings/ai"')).toHaveLength(2);
expect(line![1]).not.toContain("<button");
});
it("is left out when AI cannot be set up here", () => {
+10 -2
View File
@@ -9,6 +9,8 @@ import {
type BaselineFieldErrors,
} from "@/components/onboarding/baseline-fields";
import { useUnitDisplay } from "@/hooks/use-unit-display";
import { dateOfBirthKey } from "@/lib/tz/date-only";
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
import {
resolveHeightUnitAdapter,
type HeightDraft,
@@ -59,6 +61,8 @@ interface BaselineInitialValues {
heightCm: number | null;
dateOfBirth: string | null;
gender: string | null;
/** The owner's zone, which a date of birth from the iOS app is read in. */
timezone?: string;
}
interface BaselineFormState {
@@ -133,8 +137,12 @@ export function BaselineForm({
const [form, setForm] = useState<BaselineFormState>(() => ({
displayName: "",
height: heightAdapter.toDraft(initial.heightCm),
// The payload's ISO instant, as the date field's YYYY-MM-DD.
dateOfBirth: initial.dateOfBirth ? initial.dateOfBirth.slice(0, 10) : "",
dateOfBirth: initial.dateOfBirth
? dateOfBirthKey(
new Date(initial.dateOfBirth),
initial.timezone ?? DEFAULT_TIMEZONE,
)
: "",
gender: initial.gender ?? "",
}));
const [saving, setSaving] = useState(false);
+3 -5
View File
@@ -35,6 +35,8 @@ import {
questionsToPassBeforeConfirm,
} from "@/lib/onboarding/wizard-steps";
const NO_BASELINE = { heightCm: null, dateOfBirth: null, gender: null };
/**
* v1.39 — the confirm screen.
*
@@ -334,11 +336,7 @@ export function ConfirmScreen({
) : (
<BaselineForm
backHref={back ? screenHref(back) : undefined}
initial={{
heightCm: user?.heightCm ?? null,
dateOfBirth: user?.dateOfBirth ?? null,
gender: user?.gender ?? null,
}}
initial={user ?? NO_BASELINE}
onConfirmed={finish}
confirming={finishing}
demoMode={demoMode}
+1 -4
View File
@@ -123,10 +123,7 @@ export function DoneScreen({ state }: { state: OnboardingStateDto }) {
</div>
{showAiLine ? (
<p
data-slot="onboarding-ai-line"
className="text-muted-foreground max-w-md text-sm"
>
<p data-slot="onboarding-ai-line" className="max-w-md text-sm">
{t("onboarding.done.aiOptional")}{" "}
<InlineAction asChild size="sm" className="underline">
<Link href="/settings/ai">{t("onboarding.done.aiSetupCta")}</Link>