Skip to content

fix(onboarding): surface why 'Complete Profile' is blocked (dead-button bug)#372

Merged
mcull merged 1 commit into
mainfrom
fix/profile-complete-silent-failure
Jul 1, 2026
Merged

fix(onboarding): surface why 'Complete Profile' is blocked (dead-button bug)#372
mcull merged 1 commit into
mainfrom
fix/profile-complete-silent-failure

Conversation

@mcull

@mcull mcull commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Bug (found in testing, on production)

On Step 3 of the profile wizard, the navy "Complete Profile" button looked active but did nothing — no submit, no error, no redirect. A dead end.

Why

Two silent-failure paths:

  1. handleSubmit(handleComplete) had no onInvalid handler, so any zod schema failure was swallowed — handleComplete never ran and nothing was shown.
  2. handleComplete itself did a bare return if an agreement wasn't set.

Crucially, the button's enabled-check (canProceed = hasVerifiedAddress && Boolean(profilePicture)) does not match what submission actually validates, so the button can be enabled while the submit is impossible.

This PR (the visible-feedback fix)

  • Adds a testable profileSubmitBlockMessage(errors) that maps the first failing field → friendly guidance (photo / address / name / agreements).
  • Wires it as the onInvalid handler and reuses it for the agreements guard; shows the message in a dismissible Alert. Clears on step navigation.
  • Unit tests for the helper.

Result: the button can never again silently do nothing — it either submits or tells you exactly what's missing.

Lead hypothesis for the underlying field (to confirm next)

Strong suspicion: the async user-load in ProfileCreationHandler triggers methods.reset(draft) mid-flow, and the draft's JSON-serialized profilePicture (a File{}) clobbers the in-memory File. Boolean({}) is truthy → button stays navy, but z.instanceof(File) fails → silent block. Timing/network-dependent, which fits why it hit mobile intermittently and left the user stuck on Step 3 (activeStep isn't reset).

This PR makes that failure visible (it'll now say "Please add a profile photo"). Once we confirm the surfaced message in testing, the targeted root-cause fix is to stop the draft restore from clobbering an in-progress form (exclude the File from the persisted draft / guard the one-time load). Kept separate to avoid shipping a speculative draft-system change unverified.

Verification

  • tsc, eslint, and the new + existing wizard unit tests pass.

🤖 Generated with Claude Code

… silent no-op

On Step 3 the navy 'Complete Profile' button could look active yet do
nothing: react-hook-form's handleSubmit swallowed zod validation failures,
and handleComplete silently returned if an agreement wasn't set. The user
got a dead button with no explanation.

- Wire an onInvalid handler + testable profileSubmitBlockMessage() that maps
  the first failing field to friendly guidance (photo / address / name /
  agreements), shown in an Alert.
- Replace the silent agreements return with the same visible message.
- Clear the message on step navigation.

This makes the failure visible (and, on the next attempt, tells us exactly
which field is blocking — see the draft-serialization suspicion in the PR).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stufflibrary Ready Ready Preview, Comment Jul 1, 2026 12:20am

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant