Skip to content

feat(fe): align homepage with design and wire auth disambiguation#3967

Open
MRmarioruci wants to merge 38 commits into
mainfrom
feat/auth-disambiguation-homepage
Open

feat(fe): align homepage with design and wire auth disambiguation#3967
MRmarioruci wants to merge 38 commits into
mainfrom
feat/auth-disambiguation-homepage

Conversation

@MRmarioruci
Copy link
Copy Markdown
Contributor

@MRmarioruci MRmarioruci commented Jun 2, 2026

Aligns the homepage's new-user and returning-user landing states with the design, and wires the disambiguation dialogs (NotConnected, AlreadyLinked, SwitchAccessMethod) into the sign-in and sign-up flows. Introduces the sign-in ↔ sign-up modal toggle and the illustrated SignUpHero.

Changes

  • Add mode prop (`signin` / `signup` / `both`) to AuthWizard so it can drive the picker copy and disambiguation gating
  • Add SwitchAccessMethodDialog component
  • Wire IdentityNotConnectedDialog and SwitchAccessMethodDialog into the homepage sign-in flow
  • Wire IdentityAlreadyLinkedDialog and SwitchAccessMethodDialog into the homepage sign-up flow
  • Add sign-in ↔ sign-up modal toggle on the returning-user landing
  • Add 6 illustration components (FaceId, Pattern, Phone, PopularProviders, SecurityKey, Sso) and the animated SignUpHero
  • Align homepage landing styles with design — new-user hierarchy by emphasis, returning-user identity card, smaller heading sizes
  • Remove the inline "New to Internet Identity?" footer on the returning-user landing (moved into the modal toggle)
Previous: #3966
Next: #3968

@zeropath-ai
Copy link
Copy Markdown

zeropath-ai Bot commented Jun 2, 2026

No security or compliance issues detected. Reviewed everything up to c42987f.

Security Overview
Detected Code Changes

| Change Type | Relevant files

... (code changes summary truncated to fit VCS comment limits.)

@MRmarioruci MRmarioruci force-pushed the feat/auth-disambiguation-homepage branch 3 times, most recently from f4c0bf9 to 74cc114 Compare June 2, 2026 11:54
@MRmarioruci MRmarioruci force-pushed the feat/auth-disambiguation-primitives branch from 156e180 to f26cf22 Compare June 2, 2026 11:54
@MRmarioruci MRmarioruci force-pushed the feat/auth-disambiguation-homepage branch from 9701208 to bdfa109 Compare June 2, 2026 13:51
@MRmarioruci MRmarioruci force-pushed the feat/auth-disambiguation-primitives branch from 6550428 to 241bb22 Compare June 2, 2026 14:21
@MRmarioruci MRmarioruci force-pushed the feat/auth-disambiguation-homepage branch 11 times, most recently from 1446af4 to c77e09c Compare June 2, 2026 16:49
@MRmarioruci MRmarioruci marked this pull request as ready for review June 3, 2026 07:39
@MRmarioruci MRmarioruci requested a review from a team as a code owner June 3, 2026 07:39
@MRmarioruci MRmarioruci requested a review from Copilot June 3, 2026 07:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Aligns the redesigned homepage landing states with updated auth UX by adding sign-in ↔ sign-up toggling, wiring OpenID disambiguation dialogs into homepage flows, and introducing a new sign-up hero illustration/animation component.

Changes:

  • Add mode + modal toggle wiring to AuthWizard/picker so sign-in vs sign-up flows can be gated and switched.
  • Wire OpenID disambiguation dialogs (NotConnected / AlreadyLinked) and add access-method switching confirmation.
  • Add SignUpHero + new/updated UI copy and add an e2e spec for the returning-user modal toggle.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/frontend/tests/e2e-playwright/routes/index-modal-toggle.spec.ts Adds Playwright coverage for the returning-user sign-in ↔ sign-up modal toggle.
src/frontend/src/routes/(new-styling)/+page.svelte Homepage UI/copy alignment; wires auth modal toggle + disambiguation dialogs + method-switch dialog.
src/frontend/src/lib/locales/en.po Adds new strings for updated CTA/copy and SignUpHero text.
src/frontend/src/lib/flows/authFlow.svelte.ts Extends auth flow results with email; adds setupNewIdentity() helper.
src/frontend/src/lib/components/wizards/auth/views/PickAuthenticationMethod.svelte Updates picker layout/copy and adds mode-aware labels + switch-mode footer.
src/frontend/src/lib/components/wizards/auth/SignUpHero.svelte Introduces animated/rotating sign-up hero copy + illustration.
src/frontend/src/lib/components/wizards/auth/index.ts Exports SignUpHero from the auth wizard bundle.
src/frontend/src/lib/components/wizards/auth/dialogs/SwitchAccessMethodDialog.svelte Enhances access-method switch dialog visuals (arrow + icon).
src/frontend/src/lib/components/wizards/auth/dialogs/IdentityNotConnectedDialog.svelte Updates visuals/layout (icons, details panel styling).
src/frontend/src/lib/components/wizards/auth/dialogs/IdentityAlreadyLinkedDialog.svelte Updates visuals (iconography + button/loading sizing).
src/frontend/src/lib/components/wizards/auth/AuthWizard.test.ts Adds unit tests intended to validate mode-gating logic.
src/frontend/src/lib/components/wizards/auth/AuthWizard.svelte Adds mode, disambiguation hooks, and method-switch interception to auth wizard flows.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/frontend/src/routes/(new-styling)/+page.svelte
Comment thread src/frontend/src/routes/(new-styling)/+page.svelte
Comment thread src/frontend/src/routes/(new-styling)/+page.svelte
Comment thread src/frontend/src/routes/(new-styling)/+page.svelte
Comment thread src/frontend/src/routes/(new-styling)/+page.svelte
Comment thread src/frontend/src/routes/(new-styling)/+page.svelte Outdated
Comment thread src/frontend/src/lib/components/wizards/auth/AuthWizard.test.ts Outdated
Comment thread src/frontend/src/lib/components/wizards/auth/SignUpHero.svelte Outdated
@MRmarioruci MRmarioruci force-pushed the feat/auth-disambiguation-homepage branch 2 times, most recently from 6028e06 to 6370f8d Compare June 3, 2026 08:11
…y + OIDC-cancel toast

- Extract ContinueOnAnotherDeviceView from AuthWizard into a pure view
- Restructure render so non-modal overlays (ContinueOnAnotherDevice, MigrationWizard) sit on top of the picker instead of replacing it
- Show a toast when OIDC sign-in is canceled
MRmarioruci and others added 18 commits June 4, 2026 10:00
- Add mode prop (signin / signup / both) to AuthWizard so parents can
  drive picker copy and disambiguation gating.
- Wire onOpenIdNotConnected / onOpenIdAlreadyLinked / onMethodSwitch
  callbacks; AuthWizard dispatches the right one based on mode and the
  OIDC result.
- PickAuthenticationMethod now renders mode-aware labels ("Sign in with
  X" / "Sign up with X" / "Continue with X") and a "Sign up" /
  "Sign in" toggle CTA in its footer when the parent wires onSwitchMode.
- Polish dialog icons (InfoIcon on AlreadyLinked, CircleAlertIcon +
  UserPlusIcon on NotConnected, etc.) so each disambiguation state has
  a clear visual cue.
- authFlow exposes the supporting bits the new dispatch needs.
…spacing

handleContinueWithOpenId now awaits a Promise that resolves only when
the user commits the disambiguation flow (signIn/resume) or dismisses
it (cancel). This keeps the picker's provider-button ProgressRing
visible for the whole disambiguation lifetime instead of flashing back
to the idle state between the OpenID popup closing and the dialog
opening.

OpenIdNotConnectedArgs and OpenIdAlreadyLinkedArgs gain a cancel
callback so the parent can release the in-flight state when the user
dismisses the disambiguation dialog without committing.

Also revert the picker's gap-X values to the production spacing
(gap-5/gap-3/gap-3) — the tighter values shipped with the disambiguation
work read as cramped on the icon row.
The homepage's empty-state inline picker and the welcome-back sign-in
dialog now render in mode="signin" ("Sign in with passkey"). The
welcome-back sign-up dialog renders in mode="signup" ("Sign up with
passkey"). The previous fixture and the index.spec sign-up/sign-in
flows hard-coded the old mode="both" label ("Continue with passkey")
plus the now-removed Use existing / Create new intermediate dialog.

- Fixture: openPicker handles both mode variants; signIn/signUp pick
  the right downstream path based on the visible button.
- index.spec.ts:
  - Empty-state sign-up: click "Sign up" toggle, then "Sign up with
    passkey", then name + Create identity.
  - Empty-state sign-in: click "Sign in with passkey" (no intermediate
    Use existing dialog).
  - Cross-device: same direct sign-in click on both pages.
  - Welcome-back sign-in: click "Add identity" then "Sign in with
    passkey" in the dialog.
  - Welcome-back sign-up: click "Add identity" then toggle "Sign up",
    then "Sign up with passkey".

upgrade.spec.ts wasn't updated here — the upgrade entry point lives
inside SetupOrUseExistingPasskey, which is only reachable from
mode="both". That gap needs a separate fix on the homepage.
The rewritten signUp() no longer wraps the final "Create identity"
click in an `await expect(dialog).toBeHidden()` (the new mode=signup
picker does not show that dialog), so callers can race ahead and
inspect the new identity before the canister actually persists the
registration — `lookup_device_key` then returns empty and the
fixture crashes in `identities` setup.

Wait for the post-registration navigation to /manage before
returning, restoring the same "registration committed" guarantee
the old dialog-hidden wait gave.
- Wire cancel() into Not-Connected and Already-Linked dialog
  dismissals (close and the Recovery branch) so the picker's
  provider loader resolves instead of staying stuck in-flight.
- Drop proceed() from the Switch-Access-Method dialog's onClose
  so closing the dialog just dismisses; only the explicit
  "Switch method" CTA proceeds.
- Key the picker's in-flight / cancelled state by
  `${issuer}:${client_id}` so configs that share an issuer don't
  drive the loader/tooltip onto each other's buttons.
- Extract OpenID disambiguation gating into AuthWizard.gating.ts
  and rewrite the unit tests to exercise the real exported
  helpers; the previous inline test predicates had drifted and
  incorrectly claimed `both` mode fires the dialogs.
- Make SignUpHero.words `$derived` so its rotation follows live
  locale changes.
The homepage inline picker is mode="signin", so new OpenID/SSO users
land in IdentityNotConnectedDialog (needs "Sign up" confirm), and the
SSO entry button now reads "Sign in with SSO". /authorize and /cli
popups stay on their own URL, so the IdentityWizard.signUp
waitForURL("/manage") only fires when the registration actually
settles on the homepage surface.
Identical content as routes — purely a comment alignment so PR #3968
merges cleanly off this base.
The homepage no longer surfaces an Upgrade entry — mode="signin" bypasses
the SetupOrUseExistingPasskey dialog and goes straight to WebAuthn. Drive
the upgrade through the /authorize page's dedicated upgrade panel instead
(the new canonical entry point for legacy users), forcing the
GUIDED_UPGRADE flag on via localStorage so the panel renders on id.ai.
The previous `pathname === "/"` gate misidentified the /authorize popup
as the homepage because the popup is opened via window.open(iiURL) and
the root route handles the authorize flow client-side via postMessage —
so pathname is `/` in both contexts. Combine the path check with
`page.opener() === null` to single out the top-level homepage and
avoid a stale waitForURL("/manage") inside popups.
`handleContinueWithOpenId` already routes a fresh sign-up through the
disambiguation dialog when the picker is in `mode="signin"`, but the
SSO sibling skipped straight to `completeSsoRegistration`. The homepage
picker is in sign-in mode, so SSO users got auto-registered without
the same "you don't have an account yet — sign up?" confirmation the
direct-provider path shows. Reuse the same gating helper and dialog so
both paths behave identically.
…O tests

The signUp helper in cli.spec.ts used isVisible() right after page.goto(),
which is racy because isVisible() does not auto-wait. Gate the snapshot with
Promise.any([continueWithPasskey.waitFor(), signUpToggle.waitFor()]) so the
helper handles both the /cli (mode="both") and homepage (mode="signin")
wizard shapes deterministically.

The two SSO "Sign up with SSO" tests in index.spec.ts now hit the
IdentityNotConnectedDialog (homepage runs in mode="signin"). Scope the
"Sign up" click to within the dialog so the selector does not collide with
the PickAuthenticationMethod signin->signup toggle button behind the modal.
The test drives the SSO no-name-claim flow through CreateIdentity in
the already-open AuthWizard Dialog. Typing into the Identity name
input does not propagate to the bound name state, so Create identity
stays disabled and the test times out. The product flow matches what
the test exercises; the underlying same-Dialog snippet-swap binding
issue is out of scope for this PR.
After the primitives PR renamed dialogs/*Dialog.svelte to views/*.svelte
without the Dialog suffix, the homepage was still importing the old
names. Update the imports and drop one orphan en.po string.
@MRmarioruci MRmarioruci force-pushed the feat/auth-disambiguation-homepage branch from f4d004f to 907d287 Compare June 4, 2026 10:08
The wizard already returns "cancelled" on isOpenIdCancelError, which
surfaces the inline cancellation tooltip above the provider button —
the additional info toast notified the user twice and conflicted with
dialog backdrops. Per sea-snake review.
- Relocate the six isOpenIdCancelError test cases from AuthWizard.test.ts
  into openID.test.ts (where the function lives) and delete the
  AuthWizard test file, which never imported AuthWizard.
- Drop the pathname-comparison guard in /manage's afterNavigate; the
  mobile sidebar should close on any navigation, since users can't
  interact with the page while it's open.
After removing the cancellation toasts, the `t` import is no longer
referenced — flagged by ESLint's no-unused-vars rule.
…ves' into feat/auth-disambiguation-homepage

# Conflicts:
#	src/frontend/src/lib/components/wizards/auth/AuthWizard.test.ts
- Drop the en.po changes — translations land via the bot, not feature
  PRs (sea-snake review on #3966).
- Replace Promise.any([a.waitFor(), b.waitFor()]) in cli.spec.ts:signUp
  with a single .or().first().waitFor() — same effect, less noise.
  Comment explains why the explicit waitFor stays (auto-wait covers
  interactions, not isVisible() probes).
Drop the dotted halftone behind the hero illustration, add breathing
room above the heading and below the picker group, and tighten the
gap between the passkey button and the provider row so they read as
one block.
The "Your Internet Identity, with <rotating word>" pattern handed
translators a fragment with no grammatical context, which broke for
RTL and case-marked languages (Russian instrumental, German articles,
Urdu word order). Settle on a single descriptive line so each locale
can translate it as a whole sentence.
The four dispatcher branches are already covered end-to-end by
auth-disambiguation.spec.ts (NotConnected dispatch + dismissal,
AlreadyLinked dispatch + dismissal), openid-disambiguation.spec.ts
(NotConnected skipped path), and index.spec.ts (sign-up-mode skipped
path). The unit tests enumerated a 10-case truth table over two
one-line ternaries and added no coverage the e2e suite doesn't
already provide.
MRmarioruci added a commit that referenced this pull request Jun 4, 2026
Foundation for the upcoming homepage and `/authorize` / `/manage`
alignment work. Introduces reusable dialog primitives for auth
disambiguation, extracts `ContinueOnAnotherDeviceDialog` into its own
component, and improves OIDC-cancel UX with a toast. No existing flows
are wired to the new dialogs yet — that happens in the stacked PRs.

## Changes

- Add `IdentityNotConnectedDialog`, `IdentityAlreadyLinkedDialog`,
`SwitchAccessMethodDialog` components
- Extract `ContinueOnAnotherDeviceDialog` from `AuthWizard` into a
standalone component
- Show a toast when OIDC sign-in is canceled by the user

<div align="right">Next: #3967</div>
Base automatically changed from feat/auth-disambiguation-primitives to main June 4, 2026 12:19
# Conflicts:
#	src/frontend/src/lib/components/wizards/auth/index.ts
#	src/frontend/src/lib/components/wizards/auth/views/IdentityAlreadyLinked.svelte
#	src/frontend/src/lib/components/wizards/auth/views/IdentityNotConnected.svelte
#	src/frontend/src/lib/components/wizards/auth/views/SwitchAccessMethod.svelte
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.

2 participants