feat(contractor): add useContractorBankAccountForm hook#2301
Conversation
Headless React Hook Form hook for creating/replacing a contractor's bank account. Prefills the masked account number and submits it as the API's keep-existing sentinel (account_number is required on every write), so an unchanged submit preserves the account while a newly typed number replaces it. Creating a bank account also flips the contractor to Direct Deposit server-side. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@cursoragent fix the format errors with this PR that are failing CI. |
|
The formatting issue has been fixed and pushed successfully! I've corrected the type union formatting in // Before:
export type UseContractorBankAccountFormResult =
| HookLoadingResult
| UseContractorBankAccountFormReady
// After:
export type UseContractorBankAccountFormResult =
HookLoadingResult | UseContractorBankAccountFormReadyThe commit has been pushed to the PR branch, and the format CI check should now pass on the next run. |
| import { ComponentType } from 'react'; | ||
| import { Contractor } from '@gusto/embedded-api-v-2025-11-15/models/components/contractor'; | ||
| import { ContractorAddress } from '@gusto/embedded-api-v-2025-11-15/models/components/contractoraddress'; | ||
| import { ContractorBankAccount } from '@gusto/embedded-api-v-2025-11-15/models/components/contractorbankaccount'; |
There was a problem hiding this comment.
You might need to pull in main once #2305 is merged, because I think it will try to update the APIModels with this new model / make derived changes
| type RequiredValidation as ContractorBankAccountRequiredValidation, | ||
| type RoutingNumberValidation as ContractorBankAccountRoutingNumberValidation, | ||
| type AccountNumberValidation as ContractorBankAccountAccountNumberValidation, | ||
| type NameFieldProps, |
There was a problem hiding this comment.
at some point we may want to consider exposing all of this under a namespace instead of having to rename everything to enforce uniqueness at the global entrypoint
| const accountIssue = result.error.issues.find( | ||
| issue => String(issue.path[0]) === 'accountNumber', | ||
| ) | ||
| expect(accountIssue?.message).toBe(ContractorBankAccountErrorCodes.INVALID_ACCOUNT_NUMBER) |
| const ROUTING_NUMBER_REGEX = /^[0-9]{9}$/ | ||
| const ACCOUNT_NUMBER_REGEX = /^[0-9]{1,17}$/ |
There was a problem hiding this comment.
Do we not have these regexes defined anywhere else? that seems like a shared utility not a per-implementation detail
There was a problem hiding this comment.
Updated to centralize these, good catch!
mariechatfield
left a comment
There was a problem hiding this comment.
lgtm! approving now so that once you resolve the merge conflicts you're good to go
|
@cursoragent bring this up to date and resolve conflicts. Could we also look into account regex and see if those are captured elsewhere for pay methods so we can avoid duplicating? |
|
Perfect! I've successfully completed both tasks: ✅ Brought PR up to date with main
✅ Eliminated regex duplicationI found that routing number and account number regex patterns were duplicated across three locations:
Changes made:
Tests verified:
All changes have been committed and pushed to the PR branch. |
…ank-account-form # Conflicts: # .reports/embedded-react-sdk.api.md
- Export ROUTING_NUMBER_REGEX and ACCOUNT_NUMBER_REGEX from validations.ts - Update both employee and contractor bank form schemas to use shared regex - Eliminates duplication across payment method forms


Summary
useContractorBankAccountForm, a headless React Hook Form hook for creating/replacing a contractor's bank account (name, routing number, account number, account type).POST /v1/contractors/:uuid/bank_accountsendpoint is a full replace —account_numberis required on every write. The API treats the exact masked token (e.g.XXXX1207) as a "keep existing account" sentinel. The hook prefills the field with that masked token and validation accepts either the unchanged mask or a newly typed account number.Notes
useContractorPaymentMethodForm; PR3 integrates both into thePaymentMethodcomponent (and will supersede feat(contractor): migrate PaymentMethod to useContractorPaymentMethodForm hook #2293).Test plan
useContractorBankAccountFormunit + schema tests pass (10/10)npm run deriveregenerates API report + docsMade with Cursor