Skip to content

feat: add useEmployeeDetailsForm hook with configurable required fields#1365

Merged
serikjensen merged 4 commits intomainfrom
SDK-513-employee-details-form
Mar 25, 2026
Merged

feat: add useEmployeeDetailsForm hook with configurable required fields#1365
serikjensen merged 4 commits intomainfrom
SDK-513-employee-details-form

Conversation

@serikjensen
Copy link
Copy Markdown
Member

@serikjensen serikjensen commented Mar 25, 2026

Summary

Adds the useEmployeeDetailsForm hook and EmployeeDetailsForm component with a schema-driven approach to configurable required fields. Partners can specify which fields are required per mode via requiredFields: { create: ['email'], update: ['ssn'] }, with the schema as the single source of truth for both validation and UI metadata (isRequired indicators).

Key changes

  • requiredIf utility (src/helpers/requiredIf.ts) — conditionally makes a Zod validator optional using z.preprocess, compatible with z.toJSONSchema()
  • composeFormSchema utility — reusable schema builder that takes fieldValidators, applies mode-specific API defaults (requiredOnCreate), and partner requiredFields overrides via requiredIf
  • deriveFieldsMetadata — updated to use z.toJSONSchema() for accurate isRequired detection, making the schema the single source of truth for UI metadata
  • useEmployeeDetailsForm hook — full create/update lifecycle with self-onboarding toggle, SSN redaction (hasRedactedValue metadata), and hasSsn schema option to skip SSN requirement when already on file
  • EmployeeDetailsForm component — reference implementation consuming the hook
  • Compensation schema refactor — migrated stateWcCovered, rate, and startDate from z.transform/z.date()/z.nan() to z.preprocess/z.iso.date() for toJSONSchema compatibility, with types derived from a single fieldValidators object (same pattern as employee details)
  • DatePickerField string mode — accepts and returns ISO date strings (YYYY-MM-DD) in addition to Date objects
  • SwitchHookField — new hook-connected field component for boolean toggles

Schema pattern established

All form schemas follow a consistent pattern:

  1. Define field validators once in a fieldValidators object
  2. Derive FormData type from fieldValidators via mapped type
  3. Build the runtime schema via composeFormSchema (for configurable fields) or spread + preprocess overrides (for type coercion)
  4. Use superRefine only for cross-field validations that depend on runtime form values
  5. Use schema options (like hasSsn) for static prop-based exceptions resolved at construction time

Test plan

  • Unit tests for deriveFieldsMetadata with requiredIf scenarios (6 new test cases)
  • Unit tests for useEmployeeDetailsForm hook (create, update, validation, self-onboarding, SSN handling — 12 test cases)
  • Compensation form tests still passing (4 tests)
  • TypeScript compilation clean
  • Manual testing: create mode validation, self-onboarding + email cross-validation, successful create, update mode with required SSN, successful update, SSN not required when hasSsn is true
Screen.Recording.2026-03-24.at.11.52.08.PM.mov

Made with Cursor

Implement useEmployeeDetailsForm hook and EmployeeDetailsForm component
with schema-driven field metadata and configurable required fields per
create/update mode.

- Add requiredIf utility and composeFormSchema for conditional field
  requirements derived from a single fieldValidators source of truth
- Update deriveFieldsMetadata to use z.toJSONSchema() for accurate
  isRequired detection, including requiredIf fields
- Add hasSsn schema option to skip SSN requirement when already on file
- Refactor compensationSchema to use z.preprocess for toJSONSchema
  compatibility (stateWcCovered, rate, startDate) and derive types
  from fieldValidators
- Add SwitchHookField, DatePickerField string mode, hasRedactedValue
  metadata, and employee mock API handlers

Made-with: Cursor
- Revert react-dom peerDependency back to "^18.0.0 || ^19.0.0" to
  support partners on React 18
- Make composeFormSchema generic over fieldValidators type so
  zodResolver infers the correct form data type without per-hook casts
- Remove manual Resolver cast from useEmployeeDetailsForm

Made-with: Cursor
@serikjensen serikjensen enabled auto-merge (squash) March 25, 2026 17:12
@serikjensen serikjensen merged commit c80feb3 into main Mar 25, 2026
17 checks passed
@serikjensen serikjensen deleted the SDK-513-employee-details-form branch March 25, 2026 17:13
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