Skip to content

feat(Contractor.SignatureForm): add contractor W-9 signature form#2299

Closed
serikjensen wants to merge 5 commits into
mainfrom
feat/contractor-signature-form
Closed

feat(Contractor.SignatureForm): add contractor W-9 signature form#2299
serikjensen wants to merge 5 commits into
mainfrom
feat/contractor-signature-form

Conversation

@serikjensen

@serikjensen serikjensen commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary

Second PR in the contractor-documents series, stacked on #2298 (Contractor.DocumentsList). Adds the SignatureForm component and the useContractorSignatureForm headless hook for signing a contractor document (W-9).

  • Dynamic, metadata-driven form. The hook builds a zod schema, default values, and field metadata from the document's fields[] payload (same pattern as useEmployeeStateTaxesForm). Field labels/descriptions come from SDK i18n, not the API.
  • W-9 tax classification. The seven API checkbox fields (individual_proprietor, c_corporation, …, limited_liability_company) are synthesized into a single radio group with conditional LLC / "other" sub-fields, then serialized back to the API's key/value shape (0/1) on submit.
  • Redacted SSN/EIN handling. Masked values returned by the API are treated as on-file: the input is seeded empty with the masked value as a placeholder, required validation is waived (label shows (optional)), and the field is omitted from the sign payload when untouched — so the mask is never written back.
  • Dedicated Contractor.SignatureForm i18n namespace, scoped CONTRACTOR_SIGN_DOCUMENT event, and a self-contained component reusing Common/DocumentViewer for the PDF preview.

The orchestrator (ContractorDocumentSigner state machine that composes the list + signature form) will follow in a third PR.

Notable changes outside the component

  • partner-hook-utils/types.ts: FieldMetadata gains an optional placeholder so hooks can surface a masked value.
  • src/index.ts / contractorOnboarding.ts: export the hook + component surface.
  • src/test/mocks/apis/contractor_documents.ts: W-9 fixture + get/pdf/sign handlers.

Test plan

  • npm run test -- --run src/components/Contractor — 140 passed
  • npx tsc --noEmit clean
  • eslint clean on touched files
  • Reviewer: exercise the W-9 form in the SDK dev app (ContractorOnboarding.SignatureForm with contractorId + documentUuid); verify redacted SSN shows as placeholder and isn't sent back.
Screen.Recording.2026-06-30.at.4.52.45.PM.mov

Made with Cursor

Base automatically changed from feat/contractor-document-list to main June 29, 2026 16:16
serikjensen and others added 3 commits June 29, 2026 10:19
Add the SignatureForm component and useContractorSignatureForm headless
hook for signing contractor documents (W-9). The hook builds a dynamic
zod schema and field metadata from the document's fields[] payload,
synthesizes the seven API tax-classification checkboxes into a single
radio group with conditional LLC/other sub-fields, and serializes back
to the API's key/value shape on submit.

Redacted SSN/EIN values returned by the API are treated as on-file: the
input is seeded empty with the masked value as a placeholder, required
validation is waived, and the field is omitted from the sign payload
when left untouched so the mask is never written back.

Co-authored-by: Cursor <cursoragent@cursor.com>
…yload

Fold in W-9 fidelity fixes:
- Derive each field's input variant from the API data_type so
  exemption_from_FATCA renders as its text reporting code (4b) rather
  than a checkbox; swap the mock/i18n to match.
- Omit the date field from the sign payload so the API auto-fills the
  signing date in its own locale-correct format; drop the now-unused
  SIGNED_DATE_FIELD export.
- Send signedByIpAddress in the sign request body, matching the
  employee/company sign flows (IP supplied by the partner proxy header).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@serikjensen serikjensen force-pushed the feat/contractor-signature-form branch from a0898b2 to 9507110 Compare June 29, 2026 16:24
serikjensen and others added 2 commits June 29, 2026 10:38
…r types

Only useContractorSignatureForm, its error codes, and the types a partner
needs to consume the result (props/result/ready, sections, bound-field
types, form data, W9Section) are exported from the package entry. The W-9
wire-format helpers (buildW9FieldDescriptors, buildW9Defaults,
serializeW9Fields, isW9Document, createContractorSignatureFormSchema,
buildContractorSignatureFields) and raw API-key constants are
implementation details — dropped from the entry and tagged @internal so
they no longer surface in the generated reference docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
…alidation

- Seed the LLC classification code default from the API tax_classification field
- Add SSN/EIN format validation and input formatting; accept the N/A sentinel
  in both fields and keep omitting an untouched redacted value on submit
- Consolidate duplicate EIN regexes into a shared helpers/validations EIN_REGEX
- Restore the document PDF URL on the hook and surface a download link plus an
  IRS Form W-9 instructions link (no inline preview)
- Regenerate API report and docs

Co-authored-by: Cursor <cursoragent@cursor.com>
@serikjensen

Copy link
Copy Markdown
Member Author

Superseded — decomposed into two stacked PRs for easier review:

Closing this in favor of those.

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