Repository navigation
Redesign onboarding as a visible two-step sequence - #22
Merged
Merged
Conversation
/register was a bare centered form on ivory, shared with /login, with zero brand presence -- the product's actual front door (no marketing route exists) looked identical to every other unauthenticated screen. Adds: - A split-screen layout (form left, brand panel right, stacking below 768px) via a new `split` variant on the existing AuthLayout -- /login is untouched, still the plain centered column. - SignupBrandPanel: a deliberate one-time reversal of the app's normal ink-on-paper (uses --color-text/--color-surface directly, so it still reads as a reversal in dark mode rather than flattening into it), the serif "Trueup" wordmark on its first public-page appearance, real grounded copy (four model portfolios, monthly rebalancing) instead of generic fintech copy, and the genuine three-step sequence -- create account, verify identity, link bank -- numbered because it actually is one, with the current step marked via the system's sanctioned "current selection" use of the accent color. - A password visibility toggle, via a new optional `labelExtra` slot on the shared Input component (purely additive -- every other caller is unaffected, verified by screenshot). - A segmented password-strength meter driven by the exact same describePassword() the checklist already used -- no new fabricated scale -- as the page's one deliberate interactive/animated moment, respecting the app's existing global reduced-motion rule. - A real fix for the duplicate-email case: the backend now raises ValidationError(..., code="email_taken") instead of the shared validation_failed code, so the form can show "This account already exists -- log in instead." with a working link, instead of the generic "check your details" message the dead-code fallback string was silently never reaching. Deliberately not added: a Terms-of-Service checkbox (no such page/legal content exists yet in the app -- would mean inventing legal copy) and any specific regulatory disclosure claims (kept the one trust line to something true by construction). Verified: backend 24/24 auth tests pass (including the updated duplicate-email assertion); npm run lint and build clean; full manual pass in the browser -- real registration through the running local backend, the duplicate-email path end to end with the new message and link, password toggle and strength meter both interactive, light and dark themes (dark mode's inversion checked explicitly, panel correctly flips light-on-dark), mobile width (375px, panel correctly hidden, single column), and a regression screenshot confirming /login (which doesn't use the new labelExtra prop) is pixel-identical to before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The onboarding page swapped its entire contents based on KYC status -- you only ever saw one step at a time, with no sense of the whole journey, and two real functional gaps came with that structure: - A rejected KYC attempt was indistinguishable from never having started. The backend has a real `rejected` status; the frontend's `isKycApproved ? BankLinkSection : KycStep` branch treated it identically to `pending`, showing the same first-time prompt with no explanation of what happened. - Once both steps were done, the page just sat there -- no next action toward the thing onboarding was actually for (choosing a portfolio). Adds OnboardingSteps/StepRow (features/onboarding/components/): both steps render together now, connected by a rail, using the exact numbered-circle idiom already established on the signup page's brand panel (SignupBrandPanel.jsx) -- the same real sequence, continued, not a new decorative device. A step's marker is a numbered circle (current), a muted outline (locked), or a checkmark (completed) -- color is never the only signal. KycStep now takes the customer's real stored `kycStatus` (not just its own local in-progress-attempt state) and shows a distinct rejection message with a "Try again" label instead of the generic first-time prompt. BankLinkStep is locked (no interactive content, no wasted Plaid link-token fetch) until KYC clears. Once both are done, a line below the card offers the real next step: "View portfolio options", linking straight to /portfolio. BankLinkStep's heading is now conditional (`showTitle`, default true) -- OnboardingPage suppresses it since StepRow supplies the title, but FundingPage's own usage (a bare Card with no title of its own) needed it kept, which a first pass at this missed and would have shipped title-less. Caught and fixed via a direct screenshot comparison before committing, not asserted from reading the diff. Verified against the real running app, not the diff: all four reachable states (never started, rejected, KYC-done/bank-pending, both complete) exercised via direct DB manipulation of a real registered test account -- including generating a validly-encrypted placeholder Plaid token through the app's own cipher rather than a raw byte string, since the encrypted column round-trips through decryption even when the field is never serialized. Confirmed light and dark themes (dark mode's completion button correctly inverts), 375px mobile, and the completion link's real navigation to /portfolio. npm run lint and build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The onboarding page swapped its entire contents based on KYC status — you only ever saw one step at a time, with no sense of the whole journey. Two real functional gaps came with that structure:
rejectedstatus; the frontend'sisKycApproved ? BankLinkSection : KycStepbranch treated it identically topending, showing the same first-time prompt with no explanation of what happened.Implementation
OnboardingSteps/StepRow(features/onboarding/components/): both steps render together now, connected by a rail, using the exact numbered-circle idiom already established on the signup page's brand panel (SignupBrandPanel.jsx, PR Redesign the signup page as a split-screen brand moment #21) — the same real sequence, continued, not a new decorative device. A step's marker is a numbered circle (current), a muted outline (locked), or a checkmark (completed) — color is never the only signal.KycStepnow takes the customer's real storedkycStatus(not just its own local in-progress-attempt state) and shows a distinct rejection message with a "Try again" label instead of the generic first-time prompt.BankLinkStepis locked (no interactive content, no wasted Plaid link-token fetch) until KYC clears./portfolio.BankLinkStep's heading is now conditional (showTitle, defaulttrue) —OnboardingPagesuppresses it sinceStepRowsupplies the title, butFundingPage's own usage (a bare Card with no title of its own) needed it kept, which a first pass at this missed. Caught and fixed via a direct screenshot comparison before committing, not assumed safe from reading the diff.Validation
Verified against the real running app, not the diff: all four reachable states (never started, rejected, KYC-done/bank-pending, both complete) exercised via direct DB manipulation of a real registered test account — including generating a validly-encrypted placeholder Plaid token through the app's own cipher rather than a raw byte string, since the encrypted column round-trips through decryption even when the field is never serialized. Confirmed light and dark themes (dark mode's completion button correctly inverts), 375px mobile, the completion link's real navigation to
/portfolio, and a regression screenshot confirmingFundingPage's bank-link card kept its heading.npm run lintandnpm run buildclean.Security / DB / API impact
kyc_status/account_approval_status/bank-link fields already fetched today.🤖 Generated with Claude Code