3.7 KiB
Onboarding — Theme Persistence & Progress Bar Fix
Date: 2026-06-19
Scope: src/features/onboarding
Status: Approved
Problem Statement
Two independent bugs in the onboarding flow:
-
Theme not persisted to DB — selecting a theme in
StepPreferencesapplies it visually vianext-themesbut never callsauthClient.updateUser({ theme }), so the preference is lost on page reload unless the user also saves an avatar. -
Progress bar starts from current step, not from the beginning —
OnboardingStepperusesstate.progressPercentage,state.currentStepNumber, andstate.totalStepsfrom OnboardJS. When onboarding resumes mid-flow (e.g. at stepinvite-members), OnboardJS recalculates these values relative to the remaining steps in the current session, not relative to the full 15-step flow. This makes the bar start at 0% even though the user is already 40%+ through.
Fix 1 — Theme Persistence
File: src/features/onboarding/steps/step-preferences.tsx
Current behaviour
const selectTheme = async (theme: ThemeKey) => {
setTheme(theme); // ✅ updates next-themes (UI)
// mettre à jour aussi en db! ← comment acknowledging the bug
await updateContext({ ... });
};
Target behaviour
const selectTheme = async (theme: ThemeKey) => {
setTheme(theme);
await authClient.updateUser({ theme }); // ← add this line
await updateContext({ ... });
};
Reference: src/features/profile/profile-appearance.tsx already does this correctly.
Error handling: No change — if updateUser fails, the UI theme is still applied and the user can continue. No toast/error needed at this stage.
Fix 2 — Progress Bar Recalculation
File: src/features/onboarding/onboarding-stepper.tsx
Root cause
OnboardJS computes progressPercentage and currentStepNumber relative to the steps it was initialised with in the current session. When resuming mid-flow, the step list seen by OnboardJS starts at the resume step, not at login.
Solution
Replace all OnboardJS progress values with a manual calculation based on STEP_ORDER (the canonical ordered list of all 15 steps, already defined in src/features/onboarding/constants/steps.ts).
import { STEP_ORDER } from "@/features/onboarding/constants/steps";
const currentId = String(state?.currentStep?.id ?? "");
const currentIndex = Math.max(0, STEP_ORDER.indexOf(currentId)); // guard: -1 → 0
const totalSteps = STEP_ORDER.length; // 15
const stepNumber = currentIndex + 1; // 1-based
const progress = Math.round((currentIndex / (totalSteps - 1)) * 100);
| Step | Index | stepNumber | progress |
|---|---|---|---|
| login | 0 | 1 of 15 | 0% |
| preferences | 3 | 4 of 15 | 21% |
| invite-members | 5 | 6 of 15 | 36% |
| storage | 7 | 8 of 15 | 50% |
| finish | 14 | 15 of 15 | 100% |
Edge case: If currentId is not found in STEP_ORDER, indexOf returns -1, clamped to 0 by Math.max → shows step 1 of 15 at 0%. Safe degradation.
Files Changed
| File | Change |
|---|---|
src/features/onboarding/steps/step-preferences.tsx |
Add authClient.updateUser({ theme }) in selectTheme |
src/features/onboarding/onboarding-stepper.tsx |
Replace OnboardJS progress values with STEP_ORDER-based calculation |
No new files, no schema changes, no API changes.
Out of Scope
- Adding a toast/error on failed theme save
- Persisting the avatar selection to DB during selection (only on "Continue" — existing behaviour unchanged)
- Refactoring OnboardJS step initialisation