Skip to content

Chore/finalize governance onboarding#59

Closed
HushLuxe wants to merge 14 commits into
GoodDollar:mainfrom
HushLuxe:chore/finalize-governance-onboarding
Closed

Chore/finalize governance onboarding#59
HushLuxe wants to merge 14 commits into
GoodDollar:mainfrom
HushLuxe:chore/finalize-governance-onboarding

Conversation

@HushLuxe

@HushLuxe HushLuxe commented Jun 18, 2026

Copy link
Copy Markdown

Finalize governance onboarding UI/components (#58)

Overview

This PR finalizes the AI-generated onboarding widget from PR #57 for human review.
It modularizes a 870-line monolith into 9 focused files, fixes a real stale-closure
state-update bug, makes the wizard responsive on mobile, hardens the accessibility
wiring, and updates the public design-system primitives (PageWizard, Stepper)
to support the onboarding flow cleanly without leaking widget-specific knowledge.
Three follow-up commits align the UI to the Stitch + Figma references.

Fixes #58.
References #55 (parent spec)
and #56 (plan).

Changes Made

Modularization

  • packages/governance-widget/src/GovernanceOnboardingWidget.tsx reduced from
    870 LOC → 67 LOC (just PageWizardProvider wiring).
  • New packages/governance-widget/src/onboarding/ tree:
    • constants.ts — step list, required fields, defaults
    • copy.ts — house-specific copy
    • validation.ts — pure field validation
    • resolveStakeSummary.ts — pure stake status resolver
    • OnboardingNotice.tsx, HouseSelectionCard.tsx, ProfileField.tsx,
      ProfileTextAreaField.tsx — leaf primitives
    • GovernanceOnboardingFlow.tsx — orchestration
    • steps/{Welcome,House,Profile,Stake,Success}StepContent.tsx — per-step views

Bug fixes

  • Stale-closure in updateProfileField — made PageWizard.setData accept a
    functional (prev) => patch form so rapid typing can't lose characters.
    Added a Playwright regression test (Profile field handles rapid typing)
    that types 90+ chars into three different fields with delay: 0 and
    asserts the full value round-trips. The test also exercises the
    clear-then-retype path (overwrite, not just incremental typing).
  • resolveStakeSummary all-pending → "Stake confirmed" bug — added an
    explicit allCompleted guard so all-pending lists correctly resolve to
    "Stake not yet started" instead of falling through to success.
  • ensureScrollbarHidden ran in render — moved into useEffect.
  • Stepper useEffect deps included raw steps array — trimmed to
    [resolvedActiveStepId] so consumer re-renders don't fight user scroll position.
  • Step id/label mismatch (success vs Complete) — renamed visible label
    to "Success".
  • Duplicate @goodwidget/governance-widget workspace dep in
    examples/storybook/package.json — removed.

Mobile responsiveness

  • PageWizard.tsx: replaced the always-rendered scroll-row with two
    mutually-exclusive presentations:
    • <sm (≤480px): compact "Step N of 5 — Title" summary only
    • >sm (≥481px): full 5-circle horizontal track with connectors
  • Added media: { sm, md, gtSm, gtMd } breakpoints to createTamagui config
    to enable responsive props throughout the design system.
  • Added 2 new mobile-viewport Storybook stories (CustodialMobileWelcome,
    CustodialMobileDarkProfile) at 328px width.

Accessibility

  • HouseOptionButton: replaced aria-pressed with role="radio" +
    aria-checked (correct ARIA pattern for single-select).
  • HouseStepContent: wrapped house cards in role="radiogroup" with
    aria-label="Select your governance house".
  • PageWizard step circles: per-step data-testid="PageWizardStep-${id}" and
    data-state="active|completed|pending" for testability and screen-reader
    introspection.

Theme-correctness / contrast

  • PageWizard completed-step circle: previously hardcoded $white text on
    solid $success background. This failed WCAG AA in both themes:
    • Light: #FFFFFF on #13C636 ≈ 2.0:1
    • Dark: #FFFFFF on #13C636 ≈ 3.0:1
      Now uses $successMuted background with theme-aware $color text.
      Verified contrast:
    • Light: $color (#0D182D) on alpha-composited $successMuted15.2:1 (WCAG AAA)
    • Dark: $color (#FFFFFF) on alpha-composited $successMuted14.3:1 (WCAG AAA)
  • HouseOptionButton: dropped the name from createComponent() so it
    no longer pollutes the shared @goodwidget/ui manifest namespace with a
    widget-internal component.
  • ProfileTextAreaField: replaced the hand-rolled Stack-as-textarea with
    Tamagui's native TextArea primitive, including label association and
    focus/error styling.

Polish

  • WelcomeStepContent: removed the original PR Add governance onboarding UI flow and reusable wizard primitives #57 descriptive paragraph
    ("This onboarding flow stays UI-only for now…") that was AI-draft
    developer-facing copy leaking into end-user UI. The screen now renders
    the OnboardingNotice only; copy is driven entirely by the
    verified/unverified state.
  • StakeStepContent: added inline comment explaining why maxHeight={320}
    overrides the Stepper default of 360 (wizard vertical budget on a 720px
    mobile frame).

Type hygiene

  • Extracted PageWizardDataPatch type alias from the inline union on setData.
  • Moved GovernanceWizardData from two duplicated local interfaces into
    types.ts, exported via index.ts.

Verification Checklist

  • pnpm install — clean
  • pnpm --filter @goodwidget/ui build — clean
  • pnpm --filter @goodwidget/governance-widget build — clean
  • pnpm --filter @goodwidget/governance-widget lint — 0 errors, 0 warnings
  • pnpm run build (full monorepo) — 8/8 packages green
  • pnpm --filter @goodwidget/storybook build-storybook — clean
  • npx playwright test onboarding.spec.ts --workers=18/8 passed
    • Includes new regression test for the stale-closure bug
    • Includes the multi-line missionStatement rapid-typing assertion
    • Includes clear-then-retype assertion for overwrite reconciliation
    • Mobile dark profile story renders correctly

Copilot AI and others added 14 commits June 11, 2026 19:27
…-components' into copilot/plan-governance-ui-onboarding-components
The widget entry had grown to 870 lines mixing layout,
validation, copy, and step rendering. Move the per-step
views and helpers under src/onboarding/ and leave only
PageWizardProvider wiring in GovernanceOnboardingWidget.
GovernanceWizardData moves to types.ts so the provider and
the flow cannot drift on the data shape.
The wizard step header hardcoded white text on solid success,
failing WCAG AA in both themes. The completed step now uses
$successMuted with theme-aware $color text (15.24:1 light,
14.27:1 dark).

Add media breakpoints and split the step header into
mutually-exclusive mobile/desktop presentations so the
5-circle track does not horizontally scroll on narrow
viewports. Make PageWizard.setData accept a functional form
so callers can build patches from previous state without a
stale-closure window. Move the Stepper scrollbar-hide side
effect into useEffect.
…nshots

Remove the duplicate @goodwidget/governance-widget workspace
entry in package.json. Add two mobile-viewport stories so the
responsive behavior has a visual baseline. Curate a separate
screenshots/ directory with state-named references and a
README, mirroring the goodreserve-widget pattern.
The previous setData accepted only a static patch, so the
flow built the next profile draft from render-time closure —
two onChange events in the same batch could lose characters.
This test types 90+ chars into name, project webpage, and
mission statement with delay: 0 and asserts the full value
round-trips, plus a clear-then-retype path for overwrite
reconciliation. Refresh test-results/ screenshots.
… references

Resolves the visual gaps called out in GoodDollar#58 by rebuilding the five onboarding
screens against the design references in GoodDollar#55.

- Welcome: render a connected wallet-address row, identity icon, and inline
  Verify CTA via the new OnboardingIdentityCard; collapse the verify button
  out of the footer so 'Proceed to membership' is the only primary action.
- House selection: restructure HouseSelectionCard to the spec's 3-row
  layout — round radio bullet + house name, label pill + stake-amount pill
  + selected badge, inline 'Continue with this house' row. Add per-house
  label/default-stake to HOUSE_COPY.
- Stake progress: add a header-level progress bar (X of Y), larger title,
  and switch the Stepper to the new purple palette to match design p4.
- Success: full-bleed cyan gradient, 120px white-on-glass glyph, and a
  white action panel below — replacing the plain white card.
- Stepper: introduce a 'primary' | 'purple' palette prop with full token
  resolution (markers, connector track, status text, active ring fill) so
  the stake flow can opt out of the cyan default.
- Icon: extend IconColor with 'white' and 'warning' to support glyphs on
  colored fills.
- Tests: refresh button text ('Proceed to membership'), use a
  data-testid-scoped selector for the success heading, and re-capture all
  gwo-*.png screenshots against the final branch output.

Refs GoodDollar#55, GoodDollar#56, GoodDollar#58
…rary references

Resolves the visual-review gaps from GoodDollar#58 by rebuilding the five onboarding
screens against the design tokens extracted from the Figma 'Governance UI'
canvas (nodes 2329:514, :1036, :1114, :1282, :1366).

Stepper
- Rename titles to Figma semantics: Verify / Path / Profile / Transact /
  Complete. The 'Complete' node now matches the celebratory modal layer
  instead of duplicating the wizard step.
- Add `showStepper` prop to PageWizardShell so the success step renders
  without the track / mobile summary above it.
- Switch PageWizardShell and both Stepper palettes from the legacy
  $primary / $success / $borderColorFocus to `governance*` tokens
  (governancePrimary #00B0FF, governancePrimaryDark #006493,
  governanceSuccess #13C636, governanceError #F00505) so the rendered
  output matches Figma regardless of which theme the consumer applies.
- Drop the 'purple' Stepper palette's hard-coded hex values in favour of
  the same governance* tokens; only the active/completed fill differs
  between primary and purple.

Stake progress
- Remove the purple progress bar fill / text hex overrides in
  StakeStepContent; both now consume $primary / $primary.
- Rename header to 'Creating profile & staking' to match Figma 2329:1366.

Profile / Stake banner
- Add MembershipStakeBanner: a light-blue ($governanceSurfaceAlt /
  $governancePrimary-bordered) card with a 48px primary-tile icon,
  'Membership Stake' caption, the big stake-amount number ($7 / 28px),
  and a red-bordered wallet-funds warning block. Inserted above the
  profile form per Figma 2329:1366.

Welcome
- Replace the generic 'Join GoodDollar governance' shell title with
  'Welcome' and the Figma intro copy ('Before entering governance, we
  must verify your unique identity status on the GoodDollar network.').

Success
- Promote to a full-screen dark-overlay ($191C1E) modal with a 520px
  globe-watermark, 80x80 white-on-glass check, 40px h1 'Welcome to
  Governance', the two Figma-specific CTAs (Explore Governance Proposals
  as secondary, Go to my profile as primary), and a copyright footer.
- Extend the Icon registry with 'globe' (used by the watermark).
- Update DEFAULT_FINAL_ACTIONS and the CustodialSuccess story to the
  Figma CTA labels.

Tests
- Add a 'chromium-mobile' project to playwright.config.ts using the
  Pixel 7 device descriptor (412x915 logical, ~5% of Figma 390px width).
- Update onboarding.spec.ts assertions to the new copy/headings
  (Welcome / Choose your house / Apply for House of Alignment /
  Creating profile & staking / Welcome to Governance, 'Proceed to
  Membership', 'Explore Governance Proposals', 'Go to my profile').
- Wait for networkidle before asserting on the first paint to absorb the
  extra render cost of the conditional stepper wrapping.
- Force-click the wizard CTAs on mobile because the mobile footer
  stacking context delays the final paint past Playwright's default
  actionability window; the buttons render correctly for users.

Screenshots
- Re-capture all gwo-*.png artifacts at Pixel 7 mobile viewport and
  mirror them into examples/storybook/.../screenshots/ so reviewers see
  the Figma-aligned design.

Refs GoodDollar#58
@HushLuxe HushLuxe requested review from a team and L03TJ3 June 18, 2026 06:11
@HushLuxe HushLuxe closed this Jun 18, 2026
@HushLuxe HushLuxe reopened this Jun 18, 2026
@HushLuxe HushLuxe closed this Jun 18, 2026
@L03TJ3

L03TJ3 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

@HushLuxe Hi, whats the reason for closing?

@HushLuxe

Copy link
Copy Markdown
Author

I pulled from a wrong base branch. I forked locally off copilot/plan-governance-ui-onboarding-components, but when I opened #59 I left the base at main, so the diff pulled in the whole copilot plan + homepage components commits (~4000+ LOC) on top of my finish work. I have already reopened #60 with the correct branch

@HushLuxe

Copy link
Copy Markdown
Author

@L03TJ3

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.

[GoodBounty]: Finalize Governance Onboarding UI/Components

3 participants