Skip to content

feat(auth): build sign-in form and validation states - #36

Open
ayushtr-aws wants to merge 1 commit into
bgagent/01KZXZN46CAW1WYDYS07APWMT7/shared-orchestration-context-the-parent-epic-severfrom
bgagent/01KZXZVXYVRV0CJEVT1ZDXQN1Q/shared-orchestration-context-the-parent-epic-sever
Open

feat(auth): build sign-in form and validation states#36
ayushtr-aws wants to merge 1 commit into
bgagent/01KZXZN46CAW1WYDYS07APWMT7/shared-orchestration-context-the-parent-epic-severfrom
bgagent/01KZXZVXYVRV0CJEVT1ZDXQN1Q/shared-orchestration-context-the-parent-epic-sever

Conversation

@ayushtr-aws

Copy link
Copy Markdown
Owner

Summary

Implements TG-17: Build sign-in form and validation states — an accessible sign-in form that consumes the shared authentication state model added in the parent epic.

What was added

  • src/components/SignInForm.tsx — a controlled, accessible sign-in form:
    • Email and password inputs with associated <label htmlFor> bindings, autoComplete, and appropriate type/inputMode.
    • Client-side validation reusing the shared isValidEmail/isValidPassword helpers from src/auth. Fields report required/format/length errors; invalid fields set aria-invalid and link their message via aria-describedby. Errors re-validate live after the first submit attempt so users get feedback as they correct input.
    • Loading feedback — while onSubmit is pending (or the external loading prop is set) the button shows "Signing in…", sets aria-busy, and inputs are disabled. Supports both internally-managed (promise-based) and externally-controlled loading.
    • Error feedback — form-level errors render in a role="alert" region, sourced from either a rejected onSubmit promise or an externally-provided error prop (e.g. an expired auth state).
    • Keyboard accessibility — native form semantics; Tab order flows email → password → submit, and Enter submits.
  • src/components/SignInForm.css — styling consistent with the app's existing dark theme, including visible focus rings and invalid-field states.
  • src/components/SignInForm.test.tsx — 11 component tests covering rendering, empty/format/length validation, aria wiring, successful submit, live error clearing, internal + external loading states, rejection and external error display, and keyboard operation.

Test infrastructure

The repo had Vitest configured but no DOM environment or React testing utilities. Added:

  • Dev deps: @testing-library/react, @testing-library/user-event, @testing-library/jest-dom, jsdom.
  • src/test/setup.ts — registers jest-dom matchers and cleans up between tests.
  • vitest.config.ts — a separate config (jsdom environment + setup file). It is kept apart from vite.config.ts because the repo uses Vite 8 (rolldown) at the root while Vitest bundles Vite 7; combining the two plugin types in one config trips tsc -b. The test npm script points at this config.

Build & test results

  • mise run build (tsc -b && vite build): PASS — built in ~150ms, no type errors.
  • mise run lint (oxlint): PASS — no warnings.
  • npm test (vitest run): PASS — 33/33 tests (11 new component tests + 22 existing auth tests).

Decisions made

  • Reused the shared model's isValidEmail/isValidPassword rather than re-implementing validation, keeping this UI aligned with sibling issues.
  • Exposed both a promise-driven flow and optional error/loading props so the form works standalone or wired to externally-managed auth state.
  • The form only collects and validates credentials and invokes onSubmit; it deliberately does not implement the authentication request or global state wiring, which belong to sibling issues in the epic.

Agent notes

  • What went well: The shared src/auth module was clean and pure, so validation reuse was straightforward. Native form semantics gave keyboard accessibility for free.
  • What was difficult: Getting Vitest to type-check and build cleanly. A Vite 7 (bundled with Vitest) vs Vite 8 (rolldown, project root) plugin-type mismatch made adding test to vite.config.ts fail tsc -b; isolating it in vitest.config.ts resolved it without touching the production build config.
  • Conventions discovered: Conventional-commit messages with a module scope; TypeScript is strict (noUnusedLocals/noUnusedParameters, verbatimModuleSyntax requiring import type); oxlint with react/typescript plugins; components live in src/components and are function components with named exports.
  • Suggestions for future tasks: Consider aligning the root and Vitest Vite versions to allow a single config. A shared AuthProvider/context would let this form wire directly into global auth state.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.

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

Task-Id: 01KZXZVXYVRV0CJEVT1ZDXQN1Q
Prompt-Version: 1c9c10e027a2
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