feat(v1.4): onboarding redesign — dashboard-first checklist, 3 focused steps, inline trend hints (#131)

Redesigns the first-run experience around three patterns we see in
Linear, Vercel and Notion: a short focused wizard, a persistent
getting-started checklist on the dashboard, and contextual hints
inside still-empty charts.

- Onboarding shrinks from 4 steps (one was marketing-only) to 3:
  About you (display name + locale + height + DOB + gender) → log
  your first measurement (real action via the existing form) → pick
  one notification channel (or skip).
- Every step except the first now has a Back button and exactly one
  Skip link with the honest "you can finish setup later from
  Settings" tail. The legacy duplicate Skip is removed.
- A new dashboard "Getting started" card lists the five quick wins
  (profile, first measurement, medication, Withings, notifications).
  Each row links to the right place. Items can be hidden one-by-one
  or the whole card can be dismissed; both states persist in
  localStorage. The card auto-hides once you finish onboarding and
  log your fifth measurement.
- Charts that have ≥1 but <5 readings now show a subtle inline hint
  ("First trend after 5 readings — N more to go") so the user knows
  the line will appear soon.
- Display name is captured during onboarding and saved to the
  profile.

All new strings are translated to English and German via the
existing i18n pipeline.

Co-authored-by: Marc-André Bombeck <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandMarc-André Bombeck authored and GitHub committed 2026-05-08 12:42:48 +02:00
1 parent 14cbc69a2d
commit f4a2e13985
11 files changed
+1438 -252

No files matched your search

+5
View File
@@ -6,6 +6,7 @@ import { NextRequest } from "next/server";
import { z } from "zod/v4";
const onboardingSchema = z.object({
displayName: z.string().trim().min(1).max(50).optional(),
heightCm: z.number().min(50).max(300).optional(),
dateOfBirth: z.string().optional(),
gender: z.enum(["MALE", "FEMALE"]).optional(),
@@ -46,6 +47,10 @@ export const POST = apiHandler(async (request: NextRequest) => {
data.gender = result.data.gender;
}
if (result.data.displayName) {
data.displayName = result.data.displayName;
}
await prisma.user.update({
where: { id: user.id },
data,