Skip to content

feat(forms): adopt react-hook-form for MFA setup + disable (#325) - #331

Merged
krisarmstrong merged 1 commit into
mainfrom
feat/325-auth-forms
May 27, 2026
Merged

feat(forms): adopt react-hook-form for MFA setup + disable (#325)#331
krisarmstrong merged 1 commit into
mainfrom
feat/325-auth-forms

Conversation

@krisarmstrong

Copy link
Copy Markdown
Collaborator

Continues the forms-stack rollout from the test-config forms onto
the auth surface. Two MFA modals are migrated here; App.tsx login +
MFA-verify, RecoveryForm, and SetupWizard follow.

Adds src/schemas/auth.ts with shared schemas for the full auth
surface (login, password, MFA verify, recovery code, setup wizard).
The TOTP code field gets a real regex (^\d{6}$) instead of just an
HTML5 pattern hint, recovery codes get whitespace/dash normalization
via v.transform, and the setup wizard's cross-field check
(password === confirmPassword) is schema-level.

Converted in this PR:

  • TotpSetupModal — single 6-digit code field
  • SecurityPage.DisableTotpButton — password + 6-digit code

Both forms now show inline per-field errors on blur, use uncontrolled
inputs (no re-render per keystroke), and surface submit errors
separately from validation errors.

Refs #325. Remaining sweep: App.tsx login + MFA verify forms,
components/recovery/RecoveryForm.tsx, components/setup/SetupWizard.tsx.

Continues the forms-stack rollout from the test-config forms onto
the auth surface. Two MFA modals are migrated here; App.tsx login +
MFA-verify, RecoveryForm, and SetupWizard follow.

Adds src/schemas/auth.ts with shared schemas for the full auth
surface (login, password, MFA verify, recovery code, setup wizard).
The TOTP code field gets a real regex (^\d{6}$) instead of just an
HTML5 pattern hint, recovery codes get whitespace/dash normalization
via v.transform, and the setup wizard's cross-field check
(password === confirmPassword) is schema-level.

Converted in this PR:
- TotpSetupModal — single 6-digit code field
- SecurityPage.DisableTotpButton — password + 6-digit code

Both forms now show inline per-field errors on blur, use uncontrolled
inputs (no re-render per keystroke), and surface submit errors
separately from validation errors.

Refs #325. Remaining sweep: App.tsx login + MFA verify forms,
components/recovery/RecoveryForm.tsx, components/setup/SetupWizard.tsx.
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@github-actions

Copy link
Copy Markdown
Contributor

License Compliance Report

All dependencies pass license compliance checks

Go Dependencies

  • Unknown: 31 package(s)
  • MIT: 26 package(s)
  • BSD-3-Clause: 16 package(s)
  • Apache-2.0: 11 package(s)
  • BSD-2-Clause: 1 package(s)

npm Dependencies

See full report in workflow artifacts

Allowed Licenses: MIT, Apache-2.0, BSD-*, ISC, CC0-1.0, MPL-2.0
Forbidden: GPL, AGPL, SSPL (strong copyleft)

@krisarmstrong
krisarmstrong merged commit 92cffef into main May 27, 2026
26 of 28 checks passed
@krisarmstrong
krisarmstrong deleted the feat/325-auth-forms branch May 27, 2026 14:55
krisarmstrong pushed a commit that referenced this pull request May 27, 2026
… + Setup (#332)

Final sweep completes the forms-stack migration started in stems #328
(foundation + Y.1564 pilot), #330 (6 ConfigForms), and #331 (MFA
setup + disable modals). All 13 forms in stem are now on
react-hook-form + valibot.

Migrations
- App.tsx login form — username + password, uses LoginSchema
- App.tsx MFA verify form — 6-digit code, uses MfaVerifySchema
- components/recovery/RecoveryForm.tsx — token + new password +
  confirm, uses new RecoveryCompleteSchema (cross-field check for
  password == confirmPassword). PasswordField sub-component refactored
  to accept UseFormRegisterReturn so register('password') threads
  through in one line.
- components/setup/SetupWizard.tsx — password + confirm (username is
  fixed from setup-status prop, not user-edited). Uses revised
  SetupWizardSchema (drops the username field that the form doesn't
  actually accept user input for; the v.check() cross-field rule
  remains).

Schema additions
- RecoveryCompleteSchema in src/schemas/auth.ts. The recovery-token
  flow is distinct from the recovery-code flow (RecoveryEnterSchema
  for the latter, which is still defined but not yet wired — that's
  for a future entry-by-code flow).

Out of scope
- The hand-rolled `passwordValid` / `passwordsMatch` derived state in
  the old RecoveryForm is gone — react-hook-form's formState.isValid
  now drives the submit button. The submit handler no longer
  re-validates because the resolver already gated it.

Closes #332.
krisarmstrong added a commit that referenced this pull request May 27, 2026
… + Setup (#332) (#333)

Final sweep completes the forms-stack migration started in stems #328
(foundation + Y.1564 pilot), #330 (6 ConfigForms), and #331 (MFA
setup + disable modals). All 13 forms in stem are now on
react-hook-form + valibot.

Migrations
- App.tsx login form — username + password, uses LoginSchema
- App.tsx MFA verify form — 6-digit code, uses MfaVerifySchema
- components/recovery/RecoveryForm.tsx — token + new password +
  confirm, uses new RecoveryCompleteSchema (cross-field check for
  password == confirmPassword). PasswordField sub-component refactored
  to accept UseFormRegisterReturn so register('password') threads
  through in one line.
- components/setup/SetupWizard.tsx — password + confirm (username is
  fixed from setup-status prop, not user-edited). Uses revised
  SetupWizardSchema (drops the username field that the form doesn't
  actually accept user input for; the v.check() cross-field rule
  remains).

Schema additions
- RecoveryCompleteSchema in src/schemas/auth.ts. The recovery-token
  flow is distinct from the recovery-code flow (RecoveryEnterSchema
  for the latter, which is still defined but not yet wired — that's
  for a future entry-by-code flow).

Out of scope
- The hand-rolled `passwordValid` / `passwordsMatch` derived state in
  the old RecoveryForm is gone — react-hook-form's formState.isValid
  now drives the submit button. The submit handler no longer
  re-validates because the resolver already gated it.

Closes #332.

Co-authored-by: Kris Armstrong <kris.armstrong@icloud.com>
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