@gusto/embedded-react-sdk 0.49.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/components/Base/createCompoundContext.d.ts +1 -1
  3. package/dist/components/Base/createCompoundContext.js.map +1 -1
  4. package/dist/components/Common/UI/Breadcrumbs/Breadcrumbs.js +1 -1
  5. package/dist/components/Common/UI/CalendarPreview/CalendarLegend.d.ts +1 -1
  6. package/dist/components/Common/UI/CalendarPreview/CalendarLegend.js.map +1 -1
  7. package/dist/components/Common/UI/FileInput/FileInput.js +1 -1
  8. package/dist/components/Common/UI/ProgressBar/ProgressBar.js +4 -4
  9. package/dist/components/Company/AssignSignatory/CreateSignatory/useCreateSignatory.js +5 -3
  10. package/dist/components/Company/AssignSignatory/CreateSignatory/useCreateSignatory.js.map +1 -1
  11. package/dist/components/Company/AssignSignatory/InviteSignatory/useInviteSignatory.js +5 -3
  12. package/dist/components/Company/AssignSignatory/InviteSignatory/useInviteSignatory.js.map +1 -1
  13. package/dist/components/Company/AssignSignatory/useAssignSignatory.js +7 -5
  14. package/dist/components/Company/AssignSignatory/useAssignSignatory.js.map +1 -1
  15. package/dist/components/Company/BankAccount/BankAccountForm/context.js +5 -3
  16. package/dist/components/Company/BankAccount/BankAccountForm/context.js.map +1 -1
  17. package/dist/components/Company/DocumentSigner/DocumentList/useDocumentList.js +5 -3
  18. package/dist/components/Company/DocumentSigner/DocumentList/useDocumentList.js.map +1 -1
  19. package/dist/components/Company/DocumentSigner/shared/useSignCompanyForm/signCompanyFormSchema.d.ts +1 -0
  20. package/dist/components/Company/DocumentSigner/shared/useSignCompanyForm/signCompanyFormSchema.js.map +1 -1
  21. package/dist/components/Company/FederalTaxes/useFederalTaxes.js +10 -8
  22. package/dist/components/Company/FederalTaxes/useFederalTaxes.js.map +1 -1
  23. package/dist/components/Company/Industry/Context.js +8 -6
  24. package/dist/components/Company/Industry/Context.js.map +1 -1
  25. package/dist/components/Company/Locations/LocationForm/useLocationForm.js +5 -3
  26. package/dist/components/Company/Locations/LocationForm/useLocationForm.js.map +1 -1
  27. package/dist/components/Company/Locations/LocationsList/useLocationsList.js +5 -3
  28. package/dist/components/Company/Locations/LocationsList/useLocationsList.js.map +1 -1
  29. package/dist/components/Company/OnboardingFlow/OnboardingFlow.d.ts +1 -1
  30. package/dist/components/Company/OnboardingFlow/OnboardingFlow.js.map +1 -1
  31. package/dist/components/Company/OnboardingOverview/context.js +5 -3
  32. package/dist/components/Company/OnboardingOverview/context.js.map +1 -1
  33. package/dist/components/Company/PaySchedule/shared/usePayScheduleForm/payScheduleSchema.d.ts +1 -0
  34. package/dist/components/Company/PaySchedule/shared/usePayScheduleForm/payScheduleSchema.js.map +1 -1
  35. package/dist/components/Company/StateTaxes/StateTaxesForm/context.js +5 -3
  36. package/dist/components/Company/StateTaxes/StateTaxesForm/context.js.map +1 -1
  37. package/dist/components/Company/StateTaxes/StateTaxesList/context.js +5 -3
  38. package/dist/components/Company/StateTaxes/StateTaxesList/context.js.map +1 -1
  39. package/dist/components/Contractor/Address/shared/useContractorAddressForm/contractorAddressSchema.d.ts +1 -0
  40. package/dist/components/Contractor/Address/shared/useContractorAddressForm/contractorAddressSchema.js.map +1 -1
  41. package/dist/components/Contractor/Address/shared/useContractorAddressForm/useContractorAddressForm.d.ts +38 -0
  42. package/dist/components/Contractor/Address/shared/useContractorAddressForm/useContractorAddressForm.js.map +1 -1
  43. package/dist/components/Contractor/Documents/DocumentsList/useContractorDocumentsList/useContractorDocumentsList.d.ts +1 -0
  44. package/dist/components/Contractor/Documents/DocumentsList/useContractorDocumentsList/useContractorDocumentsList.js.map +1 -1
  45. package/dist/components/Contractor/OnboardingFlow/OnboardingFlow.d.ts +3 -3
  46. package/dist/components/Contractor/OnboardingFlow/OnboardingFlow.js.map +1 -1
  47. package/dist/components/Contractor/PaymentMethod/PaymentMethod.d.ts +5 -5
  48. package/dist/components/Contractor/PaymentMethod/PaymentMethod.js +105 -108
  49. package/dist/components/Contractor/PaymentMethod/PaymentMethod.js.map +1 -1
  50. package/dist/components/Contractor/PaymentMethod/PaymentMethod.module.scss.js +8 -0
  51. package/dist/components/Contractor/PaymentMethod/PaymentMethod.module.scss.js.map +1 -0
  52. package/dist/components/Contractor/PaymentMethod/shared/index.d.ts +2 -0
  53. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/fields.d.ts +93 -0
  54. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/fields.js +22 -0
  55. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/fields.js.map +1 -0
  56. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/index.d.ts +5 -0
  57. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/useContractorBankAccountForm.d.ts +127 -0
  58. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/useContractorBankAccountForm.js +109 -0
  59. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/useContractorBankAccountForm.js.map +1 -0
  60. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/useContractorBankAccountFormSchema.d.ts +83 -0
  61. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/useContractorBankAccountFormSchema.js +42 -0
  62. package/dist/components/Contractor/PaymentMethod/shared/useContractorBankAccountForm/useContractorBankAccountFormSchema.js.map +1 -0
  63. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/contractorPaymentMethodSchema.d.ts +58 -0
  64. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/contractorPaymentMethodSchema.js +21 -0
  65. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/contractorPaymentMethodSchema.js.map +1 -0
  66. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/fields.d.ts +20 -0
  67. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/fields.js +9 -0
  68. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/fields.js.map +1 -0
  69. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/index.d.ts +5 -0
  70. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/useContractorPaymentMethodForm.d.ts +117 -0
  71. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/useContractorPaymentMethodForm.js +91 -0
  72. package/dist/components/Contractor/PaymentMethod/shared/useContractorPaymentMethodForm/useContractorPaymentMethodForm.js.map +1 -0
  73. package/dist/components/Contractor/PaymentMethod/types.d.ts +0 -5
  74. package/dist/components/Contractor/Payments/PaymentFlow/PaymentFlow.d.ts +2 -2
  75. package/dist/components/Contractor/Payments/PaymentFlow/PaymentFlow.js.map +1 -1
  76. package/dist/components/Contractor/Profile/shared/useContractorDetailsForm/contractorDetailsSchema.d.ts +1 -0
  77. package/dist/components/Contractor/Profile/shared/useContractorDetailsForm/contractorDetailsSchema.js.map +1 -1
  78. package/dist/components/Contractor/Profile/shared/useContractorDetailsForm/useContractorDetailsForm.d.ts +45 -0
  79. package/dist/components/Contractor/Profile/shared/useContractorDetailsForm/useContractorDetailsForm.js.map +1 -1
  80. package/dist/components/Employee/Compensation/shared/useCompensationForm/compensationSchema.d.ts +1 -0
  81. package/dist/components/Employee/Compensation/shared/useCompensationForm/compensationSchema.js.map +1 -1
  82. package/dist/components/Employee/Dashboard/DashboardFlow.d.ts +1 -1
  83. package/dist/components/Employee/Dashboard/DashboardFlow.js.map +1 -1
  84. package/dist/components/Employee/Deductions/shared/useChildSupportGarnishmentForm/childSupportGarnishmentFormSchema.d.ts +1 -0
  85. package/dist/components/Employee/Deductions/shared/useChildSupportGarnishmentForm/childSupportGarnishmentFormSchema.js.map +1 -1
  86. package/dist/components/Employee/Deductions/shared/useDeductionForm/deductionFormSchema.d.ts +1 -0
  87. package/dist/components/Employee/Deductions/shared/useDeductionForm/deductionFormSchema.js.map +1 -1
  88. package/dist/components/Employee/Documents/onboarding/DocumentSigner/DocumentList/useDocumentList.js +5 -3
  89. package/dist/components/Employee/Documents/onboarding/DocumentSigner/DocumentList/useDocumentList.js.map +1 -1
  90. package/dist/components/Employee/Documents/shared/useSignEmployeeForm/signEmployeeFormSchema.d.ts +1 -0
  91. package/dist/components/Employee/Documents/shared/useSignEmployeeForm/signEmployeeFormSchema.js.map +1 -1
  92. package/dist/components/Employee/EmployeeListFlow/EmployeeListFlow.d.ts +2 -2
  93. package/dist/components/Employee/EmployeeListFlow/EmployeeListFlow.js.map +1 -1
  94. package/dist/components/Employee/FederalTaxes/shared/FederalTaxesView.js +1 -1
  95. package/dist/components/Employee/FederalTaxes/shared/useFederalTaxesForm/federalTaxesSchema.d.ts +1 -0
  96. package/dist/components/Employee/FederalTaxes/shared/useFederalTaxesForm/federalTaxesSchema.js.map +1 -1
  97. package/dist/components/Employee/OnboardingExecutionFlow/OnboardingExecutionFlow.d.ts +2 -2
  98. package/dist/components/Employee/OnboardingExecutionFlow/OnboardingExecutionFlow.js.map +1 -1
  99. package/dist/components/Employee/OnboardingFlow/OnboardingFlow.d.ts +3 -3
  100. package/dist/components/Employee/OnboardingFlow/OnboardingFlow.js.map +1 -1
  101. package/dist/components/Employee/PaymentMethod/shared/useBankForm/useBankForm.d.ts +4 -4
  102. package/dist/components/Employee/PaymentMethod/shared/useBankForm/useBankForm.js.map +1 -1
  103. package/dist/components/Employee/PaymentMethod/shared/useBankForm/useBankFormSchema.d.ts +1 -0
  104. package/dist/components/Employee/PaymentMethod/shared/useBankForm/useBankFormSchema.js +7 -6
  105. package/dist/components/Employee/PaymentMethod/shared/useBankForm/useBankFormSchema.js.map +1 -1
  106. package/dist/components/Employee/PaymentMethod/shared/usePaymentMethodForm/usePaymentMethodForm.d.ts +1 -1
  107. package/dist/components/Employee/PaymentMethod/shared/usePaymentMethodForm/usePaymentMethodForm.js.map +1 -1
  108. package/dist/components/Employee/PaymentMethod/shared/usePaymentMethodForm/usePaymentMethodFormSchema.d.ts +1 -0
  109. package/dist/components/Employee/PaymentMethod/shared/usePaymentMethodForm/usePaymentMethodFormSchema.js.map +1 -1
  110. package/dist/components/Employee/PaymentMethod/shared/useSplitPaymentsForm/useSplitPaymentsForm.d.ts +2 -2
  111. package/dist/components/Employee/PaymentMethod/shared/useSplitPaymentsForm/useSplitPaymentsForm.js.map +1 -1
  112. package/dist/components/Employee/Profile/shared/useEmployeeDetailsForm/employeeDetailsSchema.d.ts +1 -0
  113. package/dist/components/Employee/Profile/shared/useEmployeeDetailsForm/employeeDetailsSchema.js.map +1 -1
  114. package/dist/components/Employee/Profile/shared/useEmployeeDetailsForm/useEmployeeDetailsForm.d.ts +11 -12
  115. package/dist/components/Employee/Profile/shared/useEmployeeDetailsForm/useEmployeeDetailsForm.js.map +1 -1
  116. package/dist/components/Employee/Profile/shared/useHomeAddressForm/homeAddressSchema.d.ts +1 -0
  117. package/dist/components/Employee/Profile/shared/useHomeAddressForm/homeAddressSchema.js.map +1 -1
  118. package/dist/components/Employee/Profile/shared/useHomeAddressForm/useHomeAddressForm.d.ts +36 -0
  119. package/dist/components/Employee/Profile/shared/useHomeAddressForm/useHomeAddressForm.js.map +1 -1
  120. package/dist/components/Employee/Profile/shared/useWorkAddressForm/useWorkAddressForm.d.ts +31 -0
  121. package/dist/components/Employee/Profile/shared/useWorkAddressForm/useWorkAddressForm.js.map +1 -1
  122. package/dist/components/Employee/Profile/shared/useWorkAddressForm/workAddressSchema.d.ts +1 -0
  123. package/dist/components/Employee/Profile/shared/useWorkAddressForm/workAddressSchema.js.map +1 -1
  124. package/dist/components/Employee/SelfOnboardingFlow/SelfOnboardingFlow.d.ts +2 -2
  125. package/dist/components/Employee/SelfOnboardingFlow/SelfOnboardingFlow.js.map +1 -1
  126. package/dist/components/Employee/StateTaxes/shared/useEmployeeStateTaxesForm/fieldProps.d.ts +36 -18
  127. package/dist/components/Employee/StateTaxes/shared/useEmployeeStateTaxesForm/fields.d.ts +113 -13
  128. package/dist/components/Employee/StateTaxes/shared/useEmployeeStateTaxesForm/fields.js.map +1 -1
  129. package/dist/components/Employee/StateTaxes/shared/useEmployeeStateTaxesForm/index.d.ts +1 -1
  130. package/dist/components/Employee/StateTaxes/shared/useEmployeeStateTaxesForm/useEmployeeStateTaxesForm.d.ts +2 -7
  131. package/dist/components/Employee/StateTaxes/shared/useEmployeeStateTaxesForm/useEmployeeStateTaxesForm.js.map +1 -1
  132. package/dist/components/Flow/Flow.js +1 -1
  133. package/dist/components/InformationRequests/InformationRequests.d.ts +3 -3
  134. package/dist/components/InformationRequests/InformationRequests.js.map +1 -1
  135. package/dist/components/Payroll/usePreparedPayrollData.js +10 -8
  136. package/dist/components/Payroll/usePreparedPayrollData.js.map +1 -1
  137. package/dist/helpers/validations.d.ts +12 -0
  138. package/dist/helpers/validations.js +6 -4
  139. package/dist/helpers/validations.js.map +1 -1
  140. package/dist/index.d.ts +6 -2
  141. package/dist/index.js +247 -237
  142. package/dist/index.js.map +1 -1
  143. package/dist/models/external.d.ts +6 -0
  144. package/dist/style.css +1 -1
  145. package/dist/types/sdkError.js +13 -6
  146. package/dist/types/sdkError.js.map +1 -1
  147. package/package.json +7 -7
  148. package/dist/components/Contractor/PaymentMethod/BankAccountForm.d.ts +0 -3
  149. package/dist/components/Contractor/PaymentMethod/BankAccountForm.js +0 -56
  150. package/dist/components/Contractor/PaymentMethod/BankAccountForm.js.map +0 -1
  151. package/dist/components/Contractor/PaymentMethod/PaymentTypeForm.d.ts +0 -2
  152. package/dist/components/Contractor/PaymentMethod/PaymentTypeForm.js +0 -33
  153. package/dist/components/Contractor/PaymentMethod/PaymentTypeForm.js.map +0 -1
  154. /package/docs/{appendix → guides}/endpoint-inventory.json +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"federalTaxesSchema.js","sources":["../../../../../../src/components/Employee/FederalTaxes/shared/useFederalTaxesForm/federalTaxesSchema.ts"],"sourcesContent":["import { z } from 'zod'\nimport { FilingStatus } from '@gusto/embedded-api-v-2025-11-15/models/operations/putv1employeesemployeeidfederaltaxes'\nimport {\n buildFormSchema,\n type RequiredFieldConfig,\n type OptionalFieldsToRequire,\n} from '@/partner-hook-utils/form/buildFormSchema'\nimport { coerceNaN, coerceStringBoolean } from '@/partner-hook-utils/form/preprocessors'\n\n// ── Error codes ────────────────────────────────────────────────────────\n\n/**\n * Validation error codes emitted by the federal taxes form schema. Map these\n * codes to localized copy in `validationMessages` when composing the hook.\n *\n * @public\n */\nexport const FederalTaxesErrorCodes = {\n REQUIRED: 'REQUIRED',\n} as const\n\n/**\n * Union of validation error code strings emitted by the federal taxes form\n * schema.\n *\n * @public\n */\nexport type FederalTaxesErrorCode =\n (typeof FederalTaxesErrorCodes)[keyof typeof FederalTaxesErrorCodes]\n\n// ── Filing status options ──────────────────────────────────────────────\n\n/**\n * Supported W-4 filing status values: single, married filing jointly, head of\n * household, and exempt from withholding.\n *\n * @public\n */\nexport const FILING_STATUS_VALUES = [\n FilingStatus.Single,\n FilingStatus.Married,\n FilingStatus.HeadOfHousehold,\n FilingStatus.ExemptFromWithholding,\n] as const\n\n/**\n * Union of filing status values that the form accepts.\n *\n * @public\n */\nexport type FilingStatusValue = (typeof FILING_STATUS_VALUES)[number]\n\n// ── Field validators ───────────────────────────────────────────────────\n\n// `filingStatus` is typed as `string` (not `z.enum`) so the initial empty form state is valid\n// for parsing while still failing the required check via `buildFormSchema`. The actual value is\n// constrained at the UI layer via the Select's options, and cast back to `FilingStatus` at\n// submission time.\nconst fieldValidators = {\n filingStatus: z.string(),\n twoJobs: z.preprocess(coerceStringBoolean, z.boolean()),\n dependentsAmount: z.preprocess(coerceNaN(0), z.number()),\n otherIncome: z.preprocess(coerceNaN(0), z.number()),\n deductions: z.preprocess(coerceNaN(0), z.number()),\n extraWithholding: z.preprocess(coerceNaN(0), z.number()),\n}\n\n/**\n * Field names accepted by the federal taxes form.\n *\n * @public\n */\nexport type FederalTaxesField = keyof typeof fieldValidators\n\n/**\n * Shape of the values managed by the federal taxes form.\n *\n * @public\n */\nexport type FederalTaxesFormData = {\n [K in keyof typeof fieldValidators]: z.infer<(typeof fieldValidators)[K]>\n}\n/**\n * Shape of the validated values produced by the federal taxes form on submit.\n *\n * @public\n */\nexport type FederalTaxesFormOutputs = FederalTaxesFormData\n\n// ── Required fields config ─────────────────────────────────────────────\n\n// Only `filingStatus` is required by the API on update. The remaining fields are\n// optional by default so partners can decide their own UX; the bundled\n// `<FederalTaxes>` component promotes them to required via `optionalFieldsToRequire`\n// to preserve the original (all-required) behavior.\nconst requiredFieldsConfig = {\n twoJobs: 'never',\n dependentsAmount: 'never',\n otherIncome: 'never',\n deductions: 'never',\n extraWithholding: 'never',\n} satisfies RequiredFieldConfig<typeof fieldValidators>\n\n// ── Schema factory ─────────────────────────────────────────────────────\n\n/**\n * Keys of optional federal taxes fields that can be promoted to required via\n * the hook's `optionalFieldsToRequire` option.\n *\n * @public\n */\nexport type FederalTaxesOptionalFieldsToRequire = OptionalFieldsToRequire<\n typeof requiredFieldsConfig\n>\n\n/** @internal */\ninterface FederalTaxesSchemaOptions {\n optionalFieldsToRequire?: FederalTaxesOptionalFieldsToRequire\n}\n\n/** @internal */\nexport function createFederalTaxesSchema(options: FederalTaxesSchemaOptions = {}) {\n const { optionalFieldsToRequire } = options\n\n return buildFormSchema(fieldValidators, {\n requiredFieldsConfig,\n requiredErrorCode: FederalTaxesErrorCodes.REQUIRED,\n mode: 'update',\n optionalFieldsToRequire,\n })\n}\n"],"names":["FederalTaxesErrorCodes","FILING_STATUS_VALUES","FilingStatus","fieldValidators","z","coerceStringBoolean","coerceNaN","requiredFieldsConfig","createFederalTaxesSchema","options","optionalFieldsToRequire","buildFormSchema"],"mappings":";;;;AAiBO,MAAMA,IAAyB;AAAA,EACpC,UAAU;AACZ,GAmBaC,IAAuB;AAAA,EAClCC,EAAa;AAAA,EACbA,EAAa;AAAA,EACbA,EAAa;AAAA,EACbA,EAAa;AACf,GAeMC,IAAkB;AAAA,EACtB,cAAcC,EAAE,OAAA;AAAA,EAChB,SAASA,EAAE,WAAWC,GAAqBD,EAAE,SAAS;AAAA,EACtD,kBAAkBA,EAAE,WAAWE,EAAU,CAAC,GAAGF,EAAE,QAAQ;AAAA,EACvD,aAAaA,EAAE,WAAWE,EAAU,CAAC,GAAGF,EAAE,QAAQ;AAAA,EAClD,YAAYA,EAAE,WAAWE,EAAU,CAAC,GAAGF,EAAE,QAAQ;AAAA,EACjD,kBAAkBA,EAAE,WAAWE,EAAU,CAAC,GAAGF,EAAE,QAAQ;AACzD,GA8BMG,IAAuB;AAAA,EAC3B,SAAS;AAAA,EACT,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,kBAAkB;AACpB;AAoBO,SAASC,EAAyBC,IAAqC,IAAI;AAChF,QAAM,EAAE,yBAAAC,MAA4BD;AAEpC,SAAOE,EAAgBR,GAAiB;AAAA,IACtC,sBAAAI;AAAA,IACA,mBAAmBP,EAAuB;AAAA,IAC1C,MAAM;AAAA,IACN,yBAAAU;AAAA,EAAA,CACD;AACH;"}
1
+ {"version":3,"file":"federalTaxesSchema.js","sources":["../../../../../../src/components/Employee/FederalTaxes/shared/useFederalTaxesForm/federalTaxesSchema.ts"],"sourcesContent":["import { z } from 'zod'\nimport { FilingStatus } from '@gusto/embedded-api-v-2025-11-15/models/operations/putv1employeesemployeeidfederaltaxes'\nimport {\n buildFormSchema,\n type RequiredFieldConfig,\n type OptionalFieldsToRequire,\n} from '@/partner-hook-utils/form/buildFormSchema'\nimport { coerceNaN, coerceStringBoolean } from '@/partner-hook-utils/form/preprocessors'\n\n// ── Error codes ────────────────────────────────────────────────────────\n\n/**\n * Validation error codes emitted by the federal taxes form schema. Map these\n * codes to localized copy in `validationMessages` when composing the hook.\n *\n * @public\n */\nexport const FederalTaxesErrorCodes = {\n REQUIRED: 'REQUIRED',\n} as const\n\n/**\n * Union of validation error code strings emitted by the federal taxes form\n * schema.\n *\n * @public\n */\nexport type FederalTaxesErrorCode =\n (typeof FederalTaxesErrorCodes)[keyof typeof FederalTaxesErrorCodes]\n\n// ── Filing status options ──────────────────────────────────────────────\n\n/**\n * Supported W-4 filing status values: single, married filing jointly, head of\n * household, and exempt from withholding.\n *\n * @public\n */\nexport const FILING_STATUS_VALUES = [\n FilingStatus.Single,\n FilingStatus.Married,\n FilingStatus.HeadOfHousehold,\n FilingStatus.ExemptFromWithholding,\n] as const\n\n/**\n * Union of filing status values that the form accepts.\n *\n * @public\n */\nexport type FilingStatusValue = (typeof FILING_STATUS_VALUES)[number]\n\n// ── Field validators ───────────────────────────────────────────────────\n\n// `filingStatus` is typed as `string` (not `z.enum`) so the initial empty form state is valid\n// for parsing while still failing the required check via `buildFormSchema`. The actual value is\n// constrained at the UI layer via the Select's options, and cast back to `FilingStatus` at\n// submission time.\nconst fieldValidators = {\n filingStatus: z.string(),\n twoJobs: z.preprocess(coerceStringBoolean, z.boolean()),\n dependentsAmount: z.preprocess(coerceNaN(0), z.number()),\n otherIncome: z.preprocess(coerceNaN(0), z.number()),\n deductions: z.preprocess(coerceNaN(0), z.number()),\n extraWithholding: z.preprocess(coerceNaN(0), z.number()),\n}\n\n/**\n * Field names accepted by the federal taxes form.\n *\n * @public\n */\nexport type FederalTaxesField = keyof typeof fieldValidators\n\n/**\n * Shape of the values managed by the federal taxes form.\n *\n * @public\n * @interface\n */\nexport type FederalTaxesFormData = {\n [K in keyof typeof fieldValidators]: z.infer<(typeof fieldValidators)[K]>\n}\n/**\n * Shape of the validated values produced by the federal taxes form on submit.\n *\n * @public\n */\nexport type FederalTaxesFormOutputs = FederalTaxesFormData\n\n// ── Required fields config ─────────────────────────────────────────────\n\n// Only `filingStatus` is required by the API on update. The remaining fields are\n// optional by default so partners can decide their own UX; the bundled\n// `<FederalTaxes>` component promotes them to required via `optionalFieldsToRequire`\n// to preserve the original (all-required) behavior.\nconst requiredFieldsConfig = {\n twoJobs: 'never',\n dependentsAmount: 'never',\n otherIncome: 'never',\n deductions: 'never',\n extraWithholding: 'never',\n} satisfies RequiredFieldConfig<typeof fieldValidators>\n\n// ── Schema factory ─────────────────────────────────────────────────────\n\n/**\n * Keys of optional federal taxes fields that can be promoted to required via\n * the hook's `optionalFieldsToRequire` option.\n *\n * @public\n */\nexport type FederalTaxesOptionalFieldsToRequire = OptionalFieldsToRequire<\n typeof requiredFieldsConfig\n>\n\n/** @internal */\ninterface FederalTaxesSchemaOptions {\n optionalFieldsToRequire?: FederalTaxesOptionalFieldsToRequire\n}\n\n/** @internal */\nexport function createFederalTaxesSchema(options: FederalTaxesSchemaOptions = {}) {\n const { optionalFieldsToRequire } = options\n\n return buildFormSchema(fieldValidators, {\n requiredFieldsConfig,\n requiredErrorCode: FederalTaxesErrorCodes.REQUIRED,\n mode: 'update',\n optionalFieldsToRequire,\n })\n}\n"],"names":["FederalTaxesErrorCodes","FILING_STATUS_VALUES","FilingStatus","fieldValidators","z","coerceStringBoolean","coerceNaN","requiredFieldsConfig","createFederalTaxesSchema","options","optionalFieldsToRequire","buildFormSchema"],"mappings":";;;;AAiBO,MAAMA,IAAyB;AAAA,EACpC,UAAU;AACZ,GAmBaC,IAAuB;AAAA,EAClCC,EAAa;AAAA,EACbA,EAAa;AAAA,EACbA,EAAa;AAAA,EACbA,EAAa;AACf,GAeMC,IAAkB;AAAA,EACtB,cAAcC,EAAE,OAAA;AAAA,EAChB,SAASA,EAAE,WAAWC,GAAqBD,EAAE,SAAS;AAAA,EACtD,kBAAkBA,EAAE,WAAWE,EAAU,CAAC,GAAGF,EAAE,QAAQ;AAAA,EACvD,aAAaA,EAAE,WAAWE,EAAU,CAAC,GAAGF,EAAE,QAAQ;AAAA,EAClD,YAAYA,EAAE,WAAWE,EAAU,CAAC,GAAGF,EAAE,QAAQ;AAAA,EACjD,kBAAkBA,EAAE,WAAWE,EAAU,CAAC,GAAGF,EAAE,QAAQ;AACzD,GA+BMG,IAAuB;AAAA,EAC3B,SAAS;AAAA,EACT,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,kBAAkB;AACpB;AAoBO,SAASC,EAAyBC,IAAqC,IAAI;AAChF,QAAM,EAAE,yBAAAC,MAA4BD;AAEpC,SAAOE,EAAgBR,GAAiB;AAAA,IACtC,sBAAAI;AAAA,IACA,mBAAmBP,EAAuB;AAAA,IAC1C,MAAM;AAAA,IACN,yBAAAU;AAAA,EAAA,CACD;AACH;"}
@@ -31,11 +31,11 @@ export interface OnboardingExecutionFlowProps {
31
31
  * Guided flow to onboard an employee.
32
32
  *
33
33
  * @remarks
34
- * Drives the per-employee, admin-led onboarding steps used by {@link OnboardingFlow} and {@link EmployeeManagement.EmployeeListFlow}. ({@link SelfOnboardingFlow} is the separate employee-driven flow and runs its own state machine.) Each step is also exported as a standalone block (see the Sub-components table) for composing a custom workflow when this orchestration is the wrong fit.
34
+ * Drives the per-employee, admin-led onboarding steps used by {@link OnboardingFlow} and {@link EmployeeManagement.EmployeeListFlow}. ({@link SelfOnboardingFlow} is the separate employee-driven flow and runs its own state machine.) Each step is also exported as a standalone block (see the Blocks table) for composing a custom workflow when this orchestration is the wrong fit.
35
35
  *
36
36
  * Self-onboarding statuses cause the federal-taxes, state-taxes, and payment-method steps to be skipped (the employee fills those in themselves); the documents step is also skipped unless `withEmployeeI9` is true and the documents config has not yet been completed.
37
37
  *
38
- * The flow forwards every event emitted by its sub-components to `onEvent`; see the events table on each sub-component for the full set of events and payloads observable from this flow.
38
+ * The flow forwards every event emitted by its blocks to `onEvent`; see the events table on each block for the full set of events and payloads observable from this flow.
39
39
  *
40
40
  * @components
41
41
  * - {@link Profile}
@@ -1 +1 @@
1
- {"version":3,"file":"OnboardingExecutionFlow.js","sources":["../../../../src/components/Employee/OnboardingExecutionFlow/OnboardingExecutionFlow.tsx"],"sourcesContent":["import { createMachine } from 'robot3'\nimport { useMemo } from 'react'\nimport {\n onboardingExecutionMachine,\n INITIAL_COMPONENT_MAP,\n type OnboardingExecutionInitialState,\n} from './onboardingExecutionStateMachine'\nimport {\n type OnboardingContextInterface,\n type OnboardingDefaultValues,\n} from './OnboardingExecutionFlowComponents'\nimport { Flow } from '@/components/Flow/Flow'\nimport type { OnEventType } from '@/components/Base/useBase'\nimport type { EventType, EmployeeOnboardingStatus } from '@/shared/constants'\n\n/**\n * Props for {@link OnboardingExecutionFlow}.\n *\n * @public\n */\nexport interface OnboardingExecutionFlowProps {\n /** The associated company identifier. */\n companyId: string\n /** Callback invoked when the flow emits an event. */\n onEvent: OnEventType<EventType, unknown>\n /** The step the flow starts on. Defaults to `employeeProfile`. */\n initialState?: OnboardingExecutionInitialState\n /** The associated employee identifier to resume onboarding for. Omit to begin onboarding a new employee. */\n initialEmployeeId?: string\n /** The current onboarding status of the employee being onboarded. Drives skip behavior for self-onboarding and document steps. */\n initialOnboardingStatus?: (typeof EmployeeOnboardingStatus)[keyof typeof EmployeeOnboardingStatus]\n /** Default values for individual flow step components. */\n defaultValues?: OnboardingDefaultValues\n /** When true, the flow renders in the admin context. When false, it is configured for employee self-onboarding. Defaults to `true`. */\n isAdmin?: boolean\n /** When true, presents the self-onboarding toggle on the profile step. Defaults to `true`. */\n isSelfOnboardingEnabled?: boolean\n /** When true, enables the Employee Documents step in the flow, allowing the admin to configure I-9 document requirements. Defaults to `false`. */\n withEmployeeI9?: boolean\n}\n\n/**\n * Guided flow to onboard an employee.\n *\n * @remarks\n * Drives the per-employee, admin-led onboarding steps used by {@link OnboardingFlow} and {@link EmployeeManagement.EmployeeListFlow}. ({@link SelfOnboardingFlow} is the separate employee-driven flow and runs its own state machine.) Each step is also exported as a standalone block (see the Sub-components table) for composing a custom workflow when this orchestration is the wrong fit.\n *\n * Self-onboarding statuses cause the federal-taxes, state-taxes, and payment-method steps to be skipped (the employee fills those in themselves); the documents step is also skipped unless `withEmployeeI9` is true and the documents config has not yet been completed.\n *\n * The flow forwards every event emitted by its sub-components to `onEvent`; see the events table on each sub-component for the full set of events and payloads observable from this flow.\n *\n * @components\n * - {@link Profile}\n * - {@link Compensation}\n * - {@link FederalTaxes}\n * - {@link StateTaxes}\n * - {@link PaymentMethod}\n * - {@link Deductions}\n * - {@link EmployeeDocuments}\n * - {@link OnboardingSummary}\n *\n * @param props - See {@link OnboardingExecutionFlowProps}.\n * @returns The multi-step onboarding execution flow.\n * @public\n * @group Flow Components\n *\n * @example\n * ```tsx title=\"App.tsx\"\n * import { EmployeeOnboarding, type EventType } from '@gusto/embedded-react-sdk'\n *\n * function MyApp() {\n * return (\n * <EmployeeOnboarding.OnboardingExecutionFlow\n * companyId=\"a007e1ab-3595-43c2-ab4b-af7a5af2e365\"\n * onEvent={(eventType: EventType) => {\n * if (eventType === 'employee/onboarding/done') {\n * // Onboarding complete — navigate to your next screen\n * }\n * }}\n * />\n * )\n * }\n * ```\n */\nexport function OnboardingExecutionFlow({\n companyId,\n onEvent,\n initialState = 'employeeProfile',\n initialEmployeeId,\n initialOnboardingStatus,\n defaultValues,\n isAdmin = true,\n isSelfOnboardingEnabled = true,\n withEmployeeI9 = false,\n}: OnboardingExecutionFlowProps) {\n const machine = useMemo(\n () =>\n createMachine(\n initialState,\n onboardingExecutionMachine,\n (initialContext: OnboardingContextInterface) => ({\n ...initialContext,\n component: INITIAL_COMPONENT_MAP[initialState],\n companyId,\n employeeId: initialEmployeeId,\n onboardingStatus: initialOnboardingStatus,\n defaultValues,\n isAdmin,\n isSelfOnboardingEnabled,\n withEmployeeI9,\n }),\n ),\n [\n companyId,\n initialState,\n initialEmployeeId,\n initialOnboardingStatus,\n defaultValues,\n isAdmin,\n isSelfOnboardingEnabled,\n withEmployeeI9,\n ],\n )\n\n return <Flow machine={machine} onEvent={onEvent} />\n}\n"],"names":["OnboardingExecutionFlow","companyId","onEvent","initialState","initialEmployeeId","initialOnboardingStatus","defaultValues","isAdmin","isSelfOnboardingEnabled","withEmployeeI9","machine","useMemo","createMachine","onboardingExecutionMachine","initialContext","INITIAL_COMPONENT_MAP","jsx","Flow"],"mappings":";;;;;AAoFO,SAASA,EAAwB;AAAA,EACtC,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,cAAAC,IAAe;AAAA,EACf,mBAAAC;AAAA,EACA,yBAAAC;AAAA,EACA,eAAAC;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,yBAAAC,IAA0B;AAAA,EAC1B,gBAAAC,IAAiB;AACnB,GAAiC;AAC/B,QAAMC,IAAUC;AAAA,IACd,MACEC;AAAA,MACET;AAAA,MACAU;AAAA,MACA,CAACC,OAAgD;AAAA,QAC/C,GAAGA;AAAA,QACH,WAAWC,EAAsBZ,CAAY;AAAA,QAC7C,WAAAF;AAAA,QACA,YAAYG;AAAA,QACZ,kBAAkBC;AAAA,QAClB,eAAAC;AAAA,QACA,SAAAC;AAAA,QACA,yBAAAC;AAAA,QACA,gBAAAC;AAAA,MAAA;AAAA,IACF;AAAA,IAEJ;AAAA,MACER;AAAA,MACAE;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,IAAA;AAAA,EACF;AAGF,SAAO,gBAAAO,EAACC,GAAA,EAAK,SAAAP,GAAkB,SAAAR,EAAA,CAAkB;AACnD;"}
1
+ {"version":3,"file":"OnboardingExecutionFlow.js","sources":["../../../../src/components/Employee/OnboardingExecutionFlow/OnboardingExecutionFlow.tsx"],"sourcesContent":["import { createMachine } from 'robot3'\nimport { useMemo } from 'react'\nimport {\n onboardingExecutionMachine,\n INITIAL_COMPONENT_MAP,\n type OnboardingExecutionInitialState,\n} from './onboardingExecutionStateMachine'\nimport {\n type OnboardingContextInterface,\n type OnboardingDefaultValues,\n} from './OnboardingExecutionFlowComponents'\nimport { Flow } from '@/components/Flow/Flow'\nimport type { OnEventType } from '@/components/Base/useBase'\nimport type { EventType, EmployeeOnboardingStatus } from '@/shared/constants'\n\n/**\n * Props for {@link OnboardingExecutionFlow}.\n *\n * @public\n */\nexport interface OnboardingExecutionFlowProps {\n /** The associated company identifier. */\n companyId: string\n /** Callback invoked when the flow emits an event. */\n onEvent: OnEventType<EventType, unknown>\n /** The step the flow starts on. Defaults to `employeeProfile`. */\n initialState?: OnboardingExecutionInitialState\n /** The associated employee identifier to resume onboarding for. Omit to begin onboarding a new employee. */\n initialEmployeeId?: string\n /** The current onboarding status of the employee being onboarded. Drives skip behavior for self-onboarding and document steps. */\n initialOnboardingStatus?: (typeof EmployeeOnboardingStatus)[keyof typeof EmployeeOnboardingStatus]\n /** Default values for individual flow step components. */\n defaultValues?: OnboardingDefaultValues\n /** When true, the flow renders in the admin context. When false, it is configured for employee self-onboarding. Defaults to `true`. */\n isAdmin?: boolean\n /** When true, presents the self-onboarding toggle on the profile step. Defaults to `true`. */\n isSelfOnboardingEnabled?: boolean\n /** When true, enables the Employee Documents step in the flow, allowing the admin to configure I-9 document requirements. Defaults to `false`. */\n withEmployeeI9?: boolean\n}\n\n/**\n * Guided flow to onboard an employee.\n *\n * @remarks\n * Drives the per-employee, admin-led onboarding steps used by {@link OnboardingFlow} and {@link EmployeeManagement.EmployeeListFlow}. ({@link SelfOnboardingFlow} is the separate employee-driven flow and runs its own state machine.) Each step is also exported as a standalone block (see the Blocks table) for composing a custom workflow when this orchestration is the wrong fit.\n *\n * Self-onboarding statuses cause the federal-taxes, state-taxes, and payment-method steps to be skipped (the employee fills those in themselves); the documents step is also skipped unless `withEmployeeI9` is true and the documents config has not yet been completed.\n *\n * The flow forwards every event emitted by its blocks to `onEvent`; see the events table on each block for the full set of events and payloads observable from this flow.\n *\n * @components\n * - {@link Profile}\n * - {@link Compensation}\n * - {@link FederalTaxes}\n * - {@link StateTaxes}\n * - {@link PaymentMethod}\n * - {@link Deductions}\n * - {@link EmployeeDocuments}\n * - {@link OnboardingSummary}\n *\n * @param props - See {@link OnboardingExecutionFlowProps}.\n * @returns The multi-step onboarding execution flow.\n * @public\n * @group Flow Components\n *\n * @example\n * ```tsx title=\"App.tsx\"\n * import { EmployeeOnboarding, type EventType } from '@gusto/embedded-react-sdk'\n *\n * function MyApp() {\n * return (\n * <EmployeeOnboarding.OnboardingExecutionFlow\n * companyId=\"a007e1ab-3595-43c2-ab4b-af7a5af2e365\"\n * onEvent={(eventType: EventType) => {\n * if (eventType === 'employee/onboarding/done') {\n * // Onboarding complete — navigate to your next screen\n * }\n * }}\n * />\n * )\n * }\n * ```\n */\nexport function OnboardingExecutionFlow({\n companyId,\n onEvent,\n initialState = 'employeeProfile',\n initialEmployeeId,\n initialOnboardingStatus,\n defaultValues,\n isAdmin = true,\n isSelfOnboardingEnabled = true,\n withEmployeeI9 = false,\n}: OnboardingExecutionFlowProps) {\n const machine = useMemo(\n () =>\n createMachine(\n initialState,\n onboardingExecutionMachine,\n (initialContext: OnboardingContextInterface) => ({\n ...initialContext,\n component: INITIAL_COMPONENT_MAP[initialState],\n companyId,\n employeeId: initialEmployeeId,\n onboardingStatus: initialOnboardingStatus,\n defaultValues,\n isAdmin,\n isSelfOnboardingEnabled,\n withEmployeeI9,\n }),\n ),\n [\n companyId,\n initialState,\n initialEmployeeId,\n initialOnboardingStatus,\n defaultValues,\n isAdmin,\n isSelfOnboardingEnabled,\n withEmployeeI9,\n ],\n )\n\n return <Flow machine={machine} onEvent={onEvent} />\n}\n"],"names":["OnboardingExecutionFlow","companyId","onEvent","initialState","initialEmployeeId","initialOnboardingStatus","defaultValues","isAdmin","isSelfOnboardingEnabled","withEmployeeI9","machine","useMemo","createMachine","onboardingExecutionMachine","initialContext","INITIAL_COMPONENT_MAP","jsx","Flow"],"mappings":";;;;;AAoFO,SAASA,EAAwB;AAAA,EACtC,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,cAAAC,IAAe;AAAA,EACf,mBAAAC;AAAA,EACA,yBAAAC;AAAA,EACA,eAAAC;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,yBAAAC,IAA0B;AAAA,EAC1B,gBAAAC,IAAiB;AACnB,GAAiC;AAC/B,QAAMC,IAAUC;AAAA,IACd,MACEC;AAAA,MACET;AAAA,MACAU;AAAA,MACA,CAACC,OAAgD;AAAA,QAC/C,GAAGA;AAAA,QACH,WAAWC,EAAsBZ,CAAY;AAAA,QAC7C,WAAAF;AAAA,QACA,YAAYG;AAAA,QACZ,kBAAkBC;AAAA,QAClB,eAAAC;AAAA,QACA,SAAAC;AAAA,QACA,yBAAAC;AAAA,QACA,gBAAAC;AAAA,MAAA;AAAA,IACF;AAAA,IAEJ;AAAA,MACER;AAAA,MACAE;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,IAAA;AAAA,EACF;AAGF,SAAO,gBAAAO,EAACC,GAAA,EAAK,SAAAP,GAAkB,SAAAR,EAAA,CAAkB;AACnD;"}
@@ -51,11 +51,11 @@ export interface OnboardingFlowProps extends BaseComponentInterface<never> {
51
51
  * The per-employee steps live in {@link OnboardingExecutionFlow}, which is also
52
52
  * exported as a standalone block — along with each individual step — for
53
53
  * composing a custom workflow when this orchestration is the wrong fit. See the
54
- * {@link https://sdk.gusto.com/docs/integration-guide/composition | Composition guide}
54
+ * {@link https://sdk.gusto.com/docs/guides/integration-guide/composition | Composition guide}
55
55
  * for how to recompose these blocks into your own flow.
56
56
  *
57
- * The flow forwards every event emitted by its sub-components to `onEvent`;
58
- * see the events table on each sub-component for the full set of events and
57
+ * The flow forwards every event emitted by its blocks to `onEvent`;
58
+ * see the events table on each block for the full set of events and
59
59
  * payloads observable from this flow.
60
60
  *
61
61
  * @components
@@ -1 +1 @@
1
- {"version":3,"file":"OnboardingFlow.js","sources":["../../../../src/components/Employee/OnboardingFlow/OnboardingFlow.tsx"],"sourcesContent":["import { createMachine } from 'robot3'\nimport { useMemo } from 'react'\nimport { employeeOnboardingMachine } from './onboardingStateMachine'\nimport {\n type OnboardingDefaultValues,\n type OnboardingContextInterface,\n EmployeeListContextual,\n} from './OnboardingFlowComponents'\nimport { Flow } from '@/components/Flow/Flow'\nimport type { BaseComponentInterface } from '@/components/Base'\nimport type { RequireAtLeastOne } from '@/types/Helpers'\n\n/**\n * Props for {@link OnboardingFlow}.\n *\n * @public\n */\nexport interface OnboardingFlowProps extends BaseComponentInterface<never> {\n /** The associated company identifier. */\n companyId: string\n /** Default values for individual flow step components. */\n defaultValues?: RequireAtLeastOne<OnboardingDefaultValues>\n /**\n * When true, presents the self-onboarding toggle allowing the admin to opt\n * the employee into self-onboarding. When false, the option to self-onboard\n * is not available. Defaults to `true`.\n */\n isSelfOnboardingEnabled?: boolean\n /**\n * When true, enables the Employee Documents step in the onboarding flow,\n * allowing the admin to configure I-9 document requirements. Defaults to\n * `false`.\n */\n withEmployeeI9?: boolean\n /**\n * Controls visibility of the Continue button in the employee list.\n *\n * When `true`, shows a Continue button allowing navigation to the next step.\n * Use this when the employee onboarding flow is embedded as a step within\n * a larger flow (e.g., company onboarding).\n *\n * When `false` (default), hides the Continue button. Use this for standalone\n * employee onboarding where the list is the terminal screen.\n *\n * @defaultValue `false`\n */\n showContinueButton?: boolean\n}\n\n/**\n * Guided flow to onboard multiple employees, one at a time.\n *\n * @remarks\n * Renders a multi-step experience that collects every piece of information\n * required to add an employee to payroll. Begins on the employee list and\n * transitions into the onboarding execution flow when \"Add employee\" or a\n * row's \"Edit\"/\"Review\" action is invoked; returning from the execution flow\n * surfaces the list again. The flow is driven by an internal state machine\n * and wraps each step in error and suspense boundaries.\n *\n * The per-employee steps live in {@link OnboardingExecutionFlow}, which is also\n * exported as a standalone block — along with each individual step — for\n * composing a custom workflow when this orchestration is the wrong fit. See the\n * {@link https://sdk.gusto.com/docs/integration-guide/composition | Composition guide}\n * for how to recompose these blocks into your own flow.\n *\n * The flow forwards every event emitted by its sub-components to `onEvent`;\n * see the events table on each sub-component for the full set of events and\n * payloads observable from this flow.\n *\n * @components\n * - {@link EmployeeList}\n * - {@link OnboardingExecutionFlow}\n *\n * @param props - See {@link OnboardingFlowProps}.\n * @returns The multi-step onboarding flow with internal navigation between the employee list and the per-step screens.\n * @public\n * @group Flow Components\n *\n * @example\n * ```tsx title=\"App.tsx\"\n * import { EmployeeOnboarding, type EventType } from '@gusto/embedded-react-sdk'\n *\n * function MyApp() {\n * return (\n * <EmployeeOnboarding.OnboardingFlow\n * companyId=\"a007e1ab-3595-43c2-ab4b-af7a5af2e365\"\n * withEmployeeI9\n * onEvent={(eventType: EventType) => {\n * if (eventType === 'employee/onboarding/done') {\n * // Onboarding complete — navigate to your next screen\n * }\n * }}\n * />\n * )\n * }\n * ```\n */\nexport const OnboardingFlow = ({\n companyId,\n onEvent,\n defaultValues,\n isSelfOnboardingEnabled = true,\n withEmployeeI9 = false,\n showContinueButton = false,\n}: OnboardingFlowProps) => {\n const manageEmployees = useMemo(\n () =>\n createMachine(\n 'index',\n employeeOnboardingMachine,\n (initialContext: OnboardingContextInterface) => ({\n ...initialContext,\n component: EmployeeListContextual,\n companyId,\n isAdmin: true,\n defaultValues,\n isSelfOnboardingEnabled,\n withEmployeeI9,\n showContinueButton,\n }),\n ),\n [companyId, defaultValues, isSelfOnboardingEnabled, withEmployeeI9, showContinueButton],\n )\n return <Flow machine={manageEmployees} onEvent={onEvent} />\n}\n"],"names":["OnboardingFlow","companyId","onEvent","defaultValues","isSelfOnboardingEnabled","withEmployeeI9","showContinueButton","manageEmployees","useMemo","createMachine","employeeOnboardingMachine","initialContext","EmployeeListContextual","jsx","Flow"],"mappings":";;;;;;AAkGO,MAAMA,IAAiB,CAAC;AAAA,EAC7B,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,eAAAC;AAAA,EACA,yBAAAC,IAA0B;AAAA,EAC1B,gBAAAC,IAAiB;AAAA,EACjB,oBAAAC,IAAqB;AACvB,MAA2B;AACzB,QAAMC,IAAkBC;AAAA,IACtB,MACEC;AAAA,MACE;AAAA,MACAC;AAAA,MACA,CAACC,OAAgD;AAAA,QAC/C,GAAGA;AAAA,QACH,WAAWC;AAAA,QACX,WAAAX;AAAA,QACA,SAAS;AAAA,QACT,eAAAE;AAAA,QACA,yBAAAC;AAAA,QACA,gBAAAC;AAAA,QACA,oBAAAC;AAAA,MAAA;AAAA,IACF;AAAA,IAEJ,CAACL,GAAWE,GAAeC,GAAyBC,GAAgBC,CAAkB;AAAA,EAAA;AAExF,SAAO,gBAAAO,EAACC,GAAA,EAAK,SAASP,GAAiB,SAAAL,EAAA,CAAkB;AAC3D;"}
1
+ {"version":3,"file":"OnboardingFlow.js","sources":["../../../../src/components/Employee/OnboardingFlow/OnboardingFlow.tsx"],"sourcesContent":["import { createMachine } from 'robot3'\nimport { useMemo } from 'react'\nimport { employeeOnboardingMachine } from './onboardingStateMachine'\nimport {\n type OnboardingDefaultValues,\n type OnboardingContextInterface,\n EmployeeListContextual,\n} from './OnboardingFlowComponents'\nimport { Flow } from '@/components/Flow/Flow'\nimport type { BaseComponentInterface } from '@/components/Base'\nimport type { RequireAtLeastOne } from '@/types/Helpers'\n\n/**\n * Props for {@link OnboardingFlow}.\n *\n * @public\n */\nexport interface OnboardingFlowProps extends BaseComponentInterface<never> {\n /** The associated company identifier. */\n companyId: string\n /** Default values for individual flow step components. */\n defaultValues?: RequireAtLeastOne<OnboardingDefaultValues>\n /**\n * When true, presents the self-onboarding toggle allowing the admin to opt\n * the employee into self-onboarding. When false, the option to self-onboard\n * is not available. Defaults to `true`.\n */\n isSelfOnboardingEnabled?: boolean\n /**\n * When true, enables the Employee Documents step in the onboarding flow,\n * allowing the admin to configure I-9 document requirements. Defaults to\n * `false`.\n */\n withEmployeeI9?: boolean\n /**\n * Controls visibility of the Continue button in the employee list.\n *\n * When `true`, shows a Continue button allowing navigation to the next step.\n * Use this when the employee onboarding flow is embedded as a step within\n * a larger flow (e.g., company onboarding).\n *\n * When `false` (default), hides the Continue button. Use this for standalone\n * employee onboarding where the list is the terminal screen.\n *\n * @defaultValue `false`\n */\n showContinueButton?: boolean\n}\n\n/**\n * Guided flow to onboard multiple employees, one at a time.\n *\n * @remarks\n * Renders a multi-step experience that collects every piece of information\n * required to add an employee to payroll. Begins on the employee list and\n * transitions into the onboarding execution flow when \"Add employee\" or a\n * row's \"Edit\"/\"Review\" action is invoked; returning from the execution flow\n * surfaces the list again. The flow is driven by an internal state machine\n * and wraps each step in error and suspense boundaries.\n *\n * The per-employee steps live in {@link OnboardingExecutionFlow}, which is also\n * exported as a standalone block — along with each individual step — for\n * composing a custom workflow when this orchestration is the wrong fit. See the\n * {@link https://sdk.gusto.com/docs/guides/integration-guide/composition | Composition guide}\n * for how to recompose these blocks into your own flow.\n *\n * The flow forwards every event emitted by its blocks to `onEvent`;\n * see the events table on each block for the full set of events and\n * payloads observable from this flow.\n *\n * @components\n * - {@link EmployeeList}\n * - {@link OnboardingExecutionFlow}\n *\n * @param props - See {@link OnboardingFlowProps}.\n * @returns The multi-step onboarding flow with internal navigation between the employee list and the per-step screens.\n * @public\n * @group Flow Components\n *\n * @example\n * ```tsx title=\"App.tsx\"\n * import { EmployeeOnboarding, type EventType } from '@gusto/embedded-react-sdk'\n *\n * function MyApp() {\n * return (\n * <EmployeeOnboarding.OnboardingFlow\n * companyId=\"a007e1ab-3595-43c2-ab4b-af7a5af2e365\"\n * withEmployeeI9\n * onEvent={(eventType: EventType) => {\n * if (eventType === 'employee/onboarding/done') {\n * // Onboarding complete — navigate to your next screen\n * }\n * }}\n * />\n * )\n * }\n * ```\n */\nexport const OnboardingFlow = ({\n companyId,\n onEvent,\n defaultValues,\n isSelfOnboardingEnabled = true,\n withEmployeeI9 = false,\n showContinueButton = false,\n}: OnboardingFlowProps) => {\n const manageEmployees = useMemo(\n () =>\n createMachine(\n 'index',\n employeeOnboardingMachine,\n (initialContext: OnboardingContextInterface) => ({\n ...initialContext,\n component: EmployeeListContextual,\n companyId,\n isAdmin: true,\n defaultValues,\n isSelfOnboardingEnabled,\n withEmployeeI9,\n showContinueButton,\n }),\n ),\n [companyId, defaultValues, isSelfOnboardingEnabled, withEmployeeI9, showContinueButton],\n )\n return <Flow machine={manageEmployees} onEvent={onEvent} />\n}\n"],"names":["OnboardingFlow","companyId","onEvent","defaultValues","isSelfOnboardingEnabled","withEmployeeI9","showContinueButton","manageEmployees","useMemo","createMachine","employeeOnboardingMachine","initialContext","EmployeeListContextual","jsx","Flow"],"mappings":";;;;;;AAkGO,MAAMA,IAAiB,CAAC;AAAA,EAC7B,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,eAAAC;AAAA,EACA,yBAAAC,IAA0B;AAAA,EAC1B,gBAAAC,IAAiB;AAAA,EACjB,oBAAAC,IAAqB;AACvB,MAA2B;AACzB,QAAMC,IAAkBC;AAAA,IACtB,MACEC;AAAA,MACE;AAAA,MACAC;AAAA,MACA,CAACC,OAAgD;AAAA,QAC/C,GAAGA;AAAA,QACH,WAAWC;AAAA,QACX,WAAAX;AAAA,QACA,SAAS;AAAA,QACT,eAAAE;AAAA,QACA,yBAAAC;AAAA,QACA,gBAAAC;AAAA,QACA,oBAAAC;AAAA,MAAA;AAAA,IACF;AAAA,IAEJ,CAACL,GAAWE,GAAeC,GAAyBC,GAAgBC,CAAkB;AAAA,EAAA;AAExF,SAAO,gBAAAO,EAACC,GAAA,EAAK,SAASP,GAAiB,SAAAL,EAAA,CAAkB;AAC3D;"}
@@ -35,13 +35,13 @@ export interface UseBankFormProps {
35
35
  * @public
36
36
  */
37
37
  export interface BankFormFields {
38
- /** Bound to `name` — see {@link NameField}. */
38
+ /** Bound to `name`. */
39
39
  Name: typeof NameField;
40
- /** Bound to `routingNumber` — see {@link RoutingNumberField}. */
40
+ /** Bound to `routingNumber`. */
41
41
  RoutingNumber: typeof RoutingNumberField;
42
- /** Bound to `accountNumber` — see {@link AccountNumberField}. */
42
+ /** Bound to `accountNumber`. */
43
43
  AccountNumber: typeof AccountNumberField;
44
- /** Bound to `accountType` — see {@link AccountTypeField}. */
44
+ /** Bound to `accountType`. */
45
45
  AccountType: typeof AccountTypeField;
46
46
  }
47
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"useBankForm.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/useBankForm/useBankForm.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useForm } from 'react-hook-form'\nimport type { UseFormProps } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport type { EmployeeBankAccount } from '@gusto/embedded-api-v-2025-11-15/models/components/employeebankaccount'\nimport { useEmployeePaymentMethodCreateMutation } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodCreate'\nimport {\n ACCOUNT_TYPES,\n type AccountType,\n createBankFormSchema,\n type BankFormData,\n type BankFormOptionalFieldsToRequire,\n type BankFormOutputs,\n} from './useBankFormSchema'\nimport { AccountNumberField, AccountTypeField, NameField, RoutingNumberField } from './fields'\nimport { useDeriveFieldsMetadata } from '@/partner-hook-utils/form/useDeriveFieldsMetadata'\nimport { useHookFormInternals } from '@/partner-hook-utils/form/useHookFormInternals'\nimport { createGetFormSubmissionValues } from '@/partner-hook-utils/form/getFormSubmissionValues'\nimport { withOptions } from '@/partner-hook-utils/form/withOptions'\nimport { composeErrorHandler } from '@/partner-hook-utils/composeErrorHandler'\nimport type {\n BaseFormHookReady,\n FieldsMetadata,\n HookLoadingResult,\n HookSubmitResult,\n} from '@/partner-hook-utils/types'\nimport { useBaseSubmit } from '@/components/Base/useBaseSubmit'\nimport { SDKInternalError } from '@/types/sdkError'\n\n/**\n * Optional submit-time overrides for {@link useBankForm}'s `onSubmit`.\n *\n * @public\n */\nexport interface BankFormSubmitOptions {\n /** Override the `employeeId` configured at hook construction. Useful when the employee is created in the same submit chain. */\n employeeId?: string\n}\n\n/**\n * Props for {@link useBankForm}.\n *\n * @public\n */\nexport interface UseBankFormProps {\n /** Employee for whom to create the bank account. May be supplied later via `BankFormSubmitOptions.employeeId`. */\n employeeId?: string\n /** Override optional fields to be required. Reserved for future schema expansion — every field is required by default. */\n optionalFieldsToRequire?: BankFormOptionalFieldsToRequire\n /** Pre-fill form values. `accountType` defaults to `'Checking'` when not supplied. */\n defaultValues?: Partial<BankFormData>\n /** When validation runs. Passed through to react-hook-form. Defaults to `'onSubmit'`. */\n validationMode?: UseFormProps['mode']\n /** Auto-focus the first invalid field on submit. Set to `false` when using `composeSubmitHandler`. Defaults to `true`. */\n shouldFocusError?: boolean\n}\n\n/**\n * Field components exposed by {@link useBankForm} on `form.Fields`.\n *\n * @public\n */\nexport interface BankFormFields {\n /** Bound to `name` — see {@link NameField}. */\n Name: typeof NameField\n /** Bound to `routingNumber` — see {@link RoutingNumberField}. */\n RoutingNumber: typeof RoutingNumberField\n /** Bound to `accountNumber` — see {@link AccountNumberField}. */\n AccountNumber: typeof AccountNumberField\n /** Bound to `accountType` — see {@link AccountTypeField}. */\n AccountType: typeof AccountTypeField\n}\n\n/**\n * Ready-state return value of {@link useBankForm}.\n *\n * @public\n */\nexport interface UseBankFormReady extends BaseFormHookReady<\n FieldsMetadata,\n BankFormData,\n BankFormFields\n> {\n /** No server-fetched data — the create form derives everything from user input. */\n data: Record<string, never>\n /** `isPending` reflects the in-flight create mutation; `mode` is always `'create'`. */\n status: { isPending: boolean; mode: 'create' }\n /** Submit the form. Optional {@link BankFormSubmitOptions} can override the `employeeId` supplied to the hook. */\n actions: {\n onSubmit: (\n options?: BankFormSubmitOptions,\n ) => Promise<HookSubmitResult<EmployeeBankAccount> | undefined>\n }\n}\n\n/**\n * Headless React Hook Form hook for creating an employee bank account.\n *\n * @remarks\n * Captures the account nickname, routing number, account number, and account\n * type. Creating a bank account also updates the employee's payment method on\n * the Gusto API. Returns the standard `HookLoadingResult | UseBankFormReady`\n * discriminated union; in practice the hook transitions to the ready state\n * immediately because it does not fetch any server data.\n *\n * @param props - See {@link UseBankFormProps}.\n * @returns A loading-state result while the hook is initializing, or a {@link UseBankFormReady} ready to render.\n * @public\n *\n * @example\n * ```tsx\n * import { useBankForm, SDKFormProvider } from '@gusto/embedded-react-sdk'\n *\n * function AddBankAccount({ employeeId }: { employeeId: string }) {\n * const bankForm = useBankForm({ employeeId })\n *\n * if (bankForm.isLoading) return null\n * const { Fields } = bankForm.form\n *\n * return (\n * <SDKFormProvider formHookResult={bankForm}>\n * <form\n * onSubmit={e => {\n * e.preventDefault()\n * void bankForm.actions.onSubmit()\n * }}\n * >\n * <Fields.Name label=\"Account nickname\" />\n * <Fields.RoutingNumber label=\"Routing number\" />\n * <Fields.AccountNumber label=\"Account number\" />\n * <Fields.AccountType label=\"Account type\" />\n * <button type=\"submit\" disabled={bankForm.status.isPending}>Save</button>\n * </form>\n * </SDKFormProvider>\n * )\n * }\n * ```\n */\nexport function useBankForm({\n employeeId,\n optionalFieldsToRequire,\n defaultValues: partnerDefaults,\n validationMode = 'onSubmit',\n shouldFocusError = true,\n}: UseBankFormProps): HookLoadingResult | UseBankFormReady {\n const [schema, metadataConfig] = useMemo(\n () => createBankFormSchema({ optionalFieldsToRequire }),\n [optionalFieldsToRequire],\n )\n\n const resolvedDefaults: BankFormData = useMemo(\n () => ({\n name: partnerDefaults?.name ?? '',\n routingNumber: partnerDefaults?.routingNumber ?? '',\n accountNumber: partnerDefaults?.accountNumber ?? '',\n accountType: (partnerDefaults?.accountType ?? 'Checking') as AccountType,\n }),\n [partnerDefaults],\n )\n\n const formMethods = useForm<BankFormData, unknown, BankFormOutputs>({\n resolver: zodResolver(schema),\n mode: validationMode,\n shouldFocusError,\n defaultValues: resolvedDefaults,\n values: resolvedDefaults,\n resetOptions: { keepDirtyValues: true },\n })\n\n const createMutation = useEmployeePaymentMethodCreateMutation()\n const isPending = createMutation.isPending\n\n const {\n baseSubmitHandler,\n error: submitError,\n setError: setSubmitError,\n } = useBaseSubmit('BankForm')\n\n const errorHandling = composeErrorHandler([], { submitError, setSubmitError })\n\n const accountTypeOptions = ACCOUNT_TYPES.map(value => ({ value, label: value }))\n\n const baseMetadata = useDeriveFieldsMetadata(metadataConfig, formMethods.control)\n const fieldsMetadata = {\n name: baseMetadata.name,\n routingNumber: baseMetadata.routingNumber,\n accountNumber: baseMetadata.accountNumber,\n accountType: withOptions<AccountType>(baseMetadata.accountType, accountTypeOptions, [\n ...ACCOUNT_TYPES,\n ]),\n }\n\n const onSubmit = async (\n options?: BankFormSubmitOptions,\n ): Promise<HookSubmitResult<EmployeeBankAccount> | undefined> => {\n let submitResult: HookSubmitResult<EmployeeBankAccount> | undefined\n\n await new Promise<void>(resolve => {\n void formMethods.handleSubmit(\n async (data: BankFormOutputs) => {\n await baseSubmitHandler(data, async payload => {\n const resolvedEmployeeId = options?.employeeId ?? employeeId\n if (!resolvedEmployeeId) {\n throw new SDKInternalError(\n 'employeeId is required to submit a bank account. Pass it to useBankForm or via BankFormSubmitOptions.',\n )\n }\n\n const response = await createMutation.mutateAsync({\n request: {\n employeeId: resolvedEmployeeId,\n employeeBankAccountRequest: {\n name: payload.name,\n routingNumber: payload.routingNumber,\n accountNumber: payload.accountNumber,\n accountType: payload.accountType,\n },\n },\n })\n\n if (!response.employeeBankAccount) {\n throw new SDKInternalError('Bank account creation failed')\n }\n\n submitResult = { mode: 'create' as const, data: response.employeeBankAccount }\n })\n resolve()\n },\n () => {\n resolve()\n },\n )()\n })\n\n return submitResult\n }\n\n const hookFormInternals = useHookFormInternals(formMethods)\n\n return {\n isLoading: false as const,\n data: {} as Record<string, never>,\n status: { isPending, mode: 'create' as const },\n actions: { onSubmit },\n errorHandling,\n form: {\n Fields: {\n Name: NameField,\n RoutingNumber: RoutingNumberField,\n AccountNumber: AccountNumberField,\n AccountType: AccountTypeField,\n },\n fieldsMetadata,\n hookFormInternals,\n getFormSubmissionValues: createGetFormSubmissionValues(formMethods, schema),\n },\n }\n}\n\n/**\n * Return type of {@link useBankForm} — a discriminated union on `isLoading`.\n *\n * @public\n */\nexport type UseBankFormResult = HookLoadingResult | UseBankFormReady\n\n/**\n * Per-field metadata exposed on `form.fieldsMetadata` for {@link useBankForm}.\n *\n * @public\n */\nexport type BankFormFieldsMetadata = UseBankFormReady['form']['fieldsMetadata']\n"],"names":["useBankForm","employeeId","optionalFieldsToRequire","partnerDefaults","validationMode","shouldFocusError","schema","metadataConfig","useMemo","createBankFormSchema","resolvedDefaults","formMethods","useForm","zodResolver","createMutation","useEmployeePaymentMethodCreateMutation","isPending","baseSubmitHandler","submitError","setSubmitError","useBaseSubmit","errorHandling","composeErrorHandler","accountTypeOptions","ACCOUNT_TYPES","value","baseMetadata","useDeriveFieldsMetadata","fieldsMetadata","withOptions","onSubmit","options","submitResult","resolve","data","payload","resolvedEmployeeId","SDKInternalError","response","hookFormInternals","useHookFormInternals","NameField","RoutingNumberField","AccountNumberField","AccountTypeField","createGetFormSubmissionValues"],"mappings":"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"}
1
+ {"version":3,"file":"useBankForm.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/useBankForm/useBankForm.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useForm } from 'react-hook-form'\nimport type { UseFormProps } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport type { EmployeeBankAccount } from '@gusto/embedded-api-v-2025-11-15/models/components/employeebankaccount'\nimport { useEmployeePaymentMethodCreateMutation } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodCreate'\nimport {\n ACCOUNT_TYPES,\n type AccountType,\n createBankFormSchema,\n type BankFormData,\n type BankFormOptionalFieldsToRequire,\n type BankFormOutputs,\n} from './useBankFormSchema'\nimport { AccountNumberField, AccountTypeField, NameField, RoutingNumberField } from './fields'\nimport { useDeriveFieldsMetadata } from '@/partner-hook-utils/form/useDeriveFieldsMetadata'\nimport { useHookFormInternals } from '@/partner-hook-utils/form/useHookFormInternals'\nimport { createGetFormSubmissionValues } from '@/partner-hook-utils/form/getFormSubmissionValues'\nimport { withOptions } from '@/partner-hook-utils/form/withOptions'\nimport { composeErrorHandler } from '@/partner-hook-utils/composeErrorHandler'\nimport type {\n BaseFormHookReady,\n FieldsMetadata,\n HookLoadingResult,\n HookSubmitResult,\n} from '@/partner-hook-utils/types'\nimport { useBaseSubmit } from '@/components/Base/useBaseSubmit'\nimport { SDKInternalError } from '@/types/sdkError'\n\n/**\n * Optional submit-time overrides for {@link useBankForm}'s `onSubmit`.\n *\n * @public\n */\nexport interface BankFormSubmitOptions {\n /** Override the `employeeId` configured at hook construction. Useful when the employee is created in the same submit chain. */\n employeeId?: string\n}\n\n/**\n * Props for {@link useBankForm}.\n *\n * @public\n */\nexport interface UseBankFormProps {\n /** Employee for whom to create the bank account. May be supplied later via `BankFormSubmitOptions.employeeId`. */\n employeeId?: string\n /** Override optional fields to be required. Reserved for future schema expansion — every field is required by default. */\n optionalFieldsToRequire?: BankFormOptionalFieldsToRequire\n /** Pre-fill form values. `accountType` defaults to `'Checking'` when not supplied. */\n defaultValues?: Partial<BankFormData>\n /** When validation runs. Passed through to react-hook-form. Defaults to `'onSubmit'`. */\n validationMode?: UseFormProps['mode']\n /** Auto-focus the first invalid field on submit. Set to `false` when using `composeSubmitHandler`. Defaults to `true`. */\n shouldFocusError?: boolean\n}\n\n/**\n * Field components exposed by {@link useBankForm} on `form.Fields`.\n *\n * @public\n */\nexport interface BankFormFields {\n /** Bound to `name`. */\n Name: typeof NameField\n /** Bound to `routingNumber`. */\n RoutingNumber: typeof RoutingNumberField\n /** Bound to `accountNumber`. */\n AccountNumber: typeof AccountNumberField\n /** Bound to `accountType`. */\n AccountType: typeof AccountTypeField\n}\n\n/**\n * Ready-state return value of {@link useBankForm}.\n *\n * @public\n */\nexport interface UseBankFormReady extends BaseFormHookReady<\n FieldsMetadata,\n BankFormData,\n BankFormFields\n> {\n /** No server-fetched data — the create form derives everything from user input. */\n data: Record<string, never>\n /** `isPending` reflects the in-flight create mutation; `mode` is always `'create'`. */\n status: { isPending: boolean; mode: 'create' }\n /** Submit the form. Optional {@link BankFormSubmitOptions} can override the `employeeId` supplied to the hook. */\n actions: {\n onSubmit: (\n options?: BankFormSubmitOptions,\n ) => Promise<HookSubmitResult<EmployeeBankAccount> | undefined>\n }\n}\n\n/**\n * Headless React Hook Form hook for creating an employee bank account.\n *\n * @remarks\n * Captures the account nickname, routing number, account number, and account\n * type. Creating a bank account also updates the employee's payment method on\n * the Gusto API. Returns the standard `HookLoadingResult | UseBankFormReady`\n * discriminated union; in practice the hook transitions to the ready state\n * immediately because it does not fetch any server data.\n *\n * @param props - See {@link UseBankFormProps}.\n * @returns A loading-state result while the hook is initializing, or a {@link UseBankFormReady} ready to render.\n * @public\n *\n * @example\n * ```tsx\n * import { useBankForm, SDKFormProvider } from '@gusto/embedded-react-sdk'\n *\n * function AddBankAccount({ employeeId }: { employeeId: string }) {\n * const bankForm = useBankForm({ employeeId })\n *\n * if (bankForm.isLoading) return null\n * const { Fields } = bankForm.form\n *\n * return (\n * <SDKFormProvider formHookResult={bankForm}>\n * <form\n * onSubmit={e => {\n * e.preventDefault()\n * void bankForm.actions.onSubmit()\n * }}\n * >\n * <Fields.Name label=\"Account nickname\" />\n * <Fields.RoutingNumber label=\"Routing number\" />\n * <Fields.AccountNumber label=\"Account number\" />\n * <Fields.AccountType label=\"Account type\" />\n * <button type=\"submit\" disabled={bankForm.status.isPending}>Save</button>\n * </form>\n * </SDKFormProvider>\n * )\n * }\n * ```\n */\nexport function useBankForm({\n employeeId,\n optionalFieldsToRequire,\n defaultValues: partnerDefaults,\n validationMode = 'onSubmit',\n shouldFocusError = true,\n}: UseBankFormProps): HookLoadingResult | UseBankFormReady {\n const [schema, metadataConfig] = useMemo(\n () => createBankFormSchema({ optionalFieldsToRequire }),\n [optionalFieldsToRequire],\n )\n\n const resolvedDefaults: BankFormData = useMemo(\n () => ({\n name: partnerDefaults?.name ?? '',\n routingNumber: partnerDefaults?.routingNumber ?? '',\n accountNumber: partnerDefaults?.accountNumber ?? '',\n accountType: (partnerDefaults?.accountType ?? 'Checking') as AccountType,\n }),\n [partnerDefaults],\n )\n\n const formMethods = useForm<BankFormData, unknown, BankFormOutputs>({\n resolver: zodResolver(schema),\n mode: validationMode,\n shouldFocusError,\n defaultValues: resolvedDefaults,\n values: resolvedDefaults,\n resetOptions: { keepDirtyValues: true },\n })\n\n const createMutation = useEmployeePaymentMethodCreateMutation()\n const isPending = createMutation.isPending\n\n const {\n baseSubmitHandler,\n error: submitError,\n setError: setSubmitError,\n } = useBaseSubmit('BankForm')\n\n const errorHandling = composeErrorHandler([], { submitError, setSubmitError })\n\n const accountTypeOptions = ACCOUNT_TYPES.map(value => ({ value, label: value }))\n\n const baseMetadata = useDeriveFieldsMetadata(metadataConfig, formMethods.control)\n const fieldsMetadata = {\n name: baseMetadata.name,\n routingNumber: baseMetadata.routingNumber,\n accountNumber: baseMetadata.accountNumber,\n accountType: withOptions<AccountType>(baseMetadata.accountType, accountTypeOptions, [\n ...ACCOUNT_TYPES,\n ]),\n }\n\n const onSubmit = async (\n options?: BankFormSubmitOptions,\n ): Promise<HookSubmitResult<EmployeeBankAccount> | undefined> => {\n let submitResult: HookSubmitResult<EmployeeBankAccount> | undefined\n\n await new Promise<void>(resolve => {\n void formMethods.handleSubmit(\n async (data: BankFormOutputs) => {\n await baseSubmitHandler(data, async payload => {\n const resolvedEmployeeId = options?.employeeId ?? employeeId\n if (!resolvedEmployeeId) {\n throw new SDKInternalError(\n 'employeeId is required to submit a bank account. Pass it to useBankForm or via BankFormSubmitOptions.',\n )\n }\n\n const response = await createMutation.mutateAsync({\n request: {\n employeeId: resolvedEmployeeId,\n employeeBankAccountRequest: {\n name: payload.name,\n routingNumber: payload.routingNumber,\n accountNumber: payload.accountNumber,\n accountType: payload.accountType,\n },\n },\n })\n\n if (!response.employeeBankAccount) {\n throw new SDKInternalError('Bank account creation failed')\n }\n\n submitResult = { mode: 'create' as const, data: response.employeeBankAccount }\n })\n resolve()\n },\n () => {\n resolve()\n },\n )()\n })\n\n return submitResult\n }\n\n const hookFormInternals = useHookFormInternals(formMethods)\n\n return {\n isLoading: false as const,\n data: {} as Record<string, never>,\n status: { isPending, mode: 'create' as const },\n actions: { onSubmit },\n errorHandling,\n form: {\n Fields: {\n Name: NameField,\n RoutingNumber: RoutingNumberField,\n AccountNumber: AccountNumberField,\n AccountType: AccountTypeField,\n },\n fieldsMetadata,\n hookFormInternals,\n getFormSubmissionValues: createGetFormSubmissionValues(formMethods, schema),\n },\n }\n}\n\n/**\n * Return type of {@link useBankForm} — a discriminated union on `isLoading`.\n *\n * @public\n */\nexport type UseBankFormResult = HookLoadingResult | UseBankFormReady\n\n/**\n * Per-field metadata exposed on `form.fieldsMetadata` for {@link useBankForm}.\n *\n * @public\n */\nexport type BankFormFieldsMetadata = UseBankFormReady['form']['fieldsMetadata']\n"],"names":["useBankForm","employeeId","optionalFieldsToRequire","partnerDefaults","validationMode","shouldFocusError","schema","metadataConfig","useMemo","createBankFormSchema","resolvedDefaults","formMethods","useForm","zodResolver","createMutation","useEmployeePaymentMethodCreateMutation","isPending","baseSubmitHandler","submitError","setSubmitError","useBaseSubmit","errorHandling","composeErrorHandler","accountTypeOptions","ACCOUNT_TYPES","value","baseMetadata","useDeriveFieldsMetadata","fieldsMetadata","withOptions","onSubmit","options","submitResult","resolve","data","payload","resolvedEmployeeId","SDKInternalError","response","hookFormInternals","useHookFormInternals","NameField","RoutingNumberField","AccountNumberField","AccountTypeField","createGetFormSubmissionValues"],"mappings":"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"}
@@ -40,6 +40,7 @@ export type BankFormField = "name" | "routingNumber" | "accountNumber" | "accoun
40
40
  * Shape of the values managed by the bank account form.
41
41
  *
42
42
  * @public
43
+ * @interface
43
44
  */
44
45
  export type BankFormData = { name: string; routingNumber: string; accountNumber: string; accountType: "Checking" | "Savings"; };
45
46
  /**
@@ -1,17 +1,18 @@
1
1
  import { z as e } from "zod";
2
2
  import { buildFormSchema as N } from "../../../../../partner-hook-utils/form/buildFormSchema.js";
3
+ import { ACCOUNT_NUMBER_REGEX as i, ROUTING_NUMBER_REGEX as n } from "../../../../../helpers/validations.js";
3
4
  const r = {
4
5
  REQUIRED: "REQUIRED",
5
6
  INVALID_ROUTING_NUMBER: "INVALID_ROUTING_NUMBER",
6
7
  INVALID_ACCOUNT_NUMBER: "INVALID_ACCOUNT_NUMBER"
7
- }, n = /^[0-9]{9}$/, i = /^[0-9]{1,17}$/, t = ["Checking", "Savings"], R = {
8
+ }, R = ["Checking", "Savings"], t = {
8
9
  name: e.string(),
9
10
  routingNumber: e.string().regex(n, { message: r.INVALID_ROUTING_NUMBER }),
10
11
  accountNumber: e.string().regex(i, { message: r.INVALID_ACCOUNT_NUMBER }),
11
- accountType: e.enum(t)
12
+ accountType: e.enum(R)
12
13
  }, E = {};
13
- function I(o = {}) {
14
- return N(R, {
14
+ function s(o = {}) {
15
+ return N(t, {
15
16
  requiredFieldsConfig: E,
16
17
  requiredErrorCode: r.REQUIRED,
17
18
  mode: "create",
@@ -19,8 +20,8 @@ function I(o = {}) {
19
20
  });
20
21
  }
21
22
  export {
22
- t as ACCOUNT_TYPES,
23
+ R as ACCOUNT_TYPES,
23
24
  r as BankFormErrorCodes,
24
- I as createBankFormSchema
25
+ s as createBankFormSchema
25
26
  };
26
27
  //# sourceMappingURL=useBankFormSchema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useBankFormSchema.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/useBankForm/useBankFormSchema.ts"],"sourcesContent":["import { z } from 'zod'\nimport {\n buildFormSchema,\n type OptionalFieldsToRequire,\n type RequiredFieldConfig,\n} from '@/partner-hook-utils/form/buildFormSchema'\n\n/**\n * Validation error codes emitted by the bank account form schema. Map these\n * codes to localized copy in `validationMessages` when composing the hook.\n *\n * @public\n */\nexport const BankFormErrorCodes = {\n REQUIRED: 'REQUIRED',\n INVALID_ROUTING_NUMBER: 'INVALID_ROUTING_NUMBER',\n INVALID_ACCOUNT_NUMBER: 'INVALID_ACCOUNT_NUMBER',\n} as const\n\n/**\n * Union of validation error code strings emitted by the bank account form\n * schema.\n *\n * @public\n */\nexport type BankFormErrorCode = (typeof BankFormErrorCodes)[keyof typeof BankFormErrorCodes]\n\nconst ROUTING_NUMBER_REGEX = /^[0-9]{9}$/\nconst ACCOUNT_NUMBER_REGEX = /^[0-9]{1,17}$/\n\n/**\n * Supported bank account type values: checking and savings.\n *\n * @public\n */\nexport const ACCOUNT_TYPES = ['Checking', 'Savings'] as const\n/**\n * Union of bank account type values that the form accepts.\n *\n * @public\n */\nexport type AccountType = (typeof ACCOUNT_TYPES)[number]\n\nconst fieldValidators = {\n name: z.string(),\n routingNumber: z\n .string()\n .regex(ROUTING_NUMBER_REGEX, { message: BankFormErrorCodes.INVALID_ROUTING_NUMBER }),\n accountNumber: z\n .string()\n .regex(ACCOUNT_NUMBER_REGEX, { message: BankFormErrorCodes.INVALID_ACCOUNT_NUMBER }),\n accountType: z.enum(ACCOUNT_TYPES),\n}\n\n/**\n * Field names accepted by the bank account form.\n *\n * @public\n */\nexport type BankFormField = keyof typeof fieldValidators\n\n/**\n * Shape of the values managed by the bank account form.\n *\n * @public\n */\nexport type BankFormData = {\n [K in keyof typeof fieldValidators]: z.infer<(typeof fieldValidators)[K]>\n}\n/**\n * Shape of the validated values produced by the bank account form on submit.\n *\n * @public\n */\nexport type BankFormOutputs = BankFormData\n\nconst requiredFieldsConfig = {} satisfies RequiredFieldConfig<typeof fieldValidators>\n\n/**\n * Keys of optional bank account fields that can be promoted to required via\n * the hook's `optionalFieldsToRequire` option.\n *\n * @public\n */\nexport type BankFormOptionalFieldsToRequire = OptionalFieldsToRequire<typeof requiredFieldsConfig>\n\n/** @internal */\ninterface BankFormSchemaOptions {\n optionalFieldsToRequire?: BankFormOptionalFieldsToRequire\n}\n\n/** @internal */\nexport function createBankFormSchema(options: BankFormSchemaOptions = {}) {\n return buildFormSchema(fieldValidators, {\n requiredFieldsConfig,\n requiredErrorCode: BankFormErrorCodes.REQUIRED,\n mode: 'create',\n optionalFieldsToRequire: options.optionalFieldsToRequire,\n })\n}\n"],"names":["BankFormErrorCodes","ROUTING_NUMBER_REGEX","ACCOUNT_NUMBER_REGEX","ACCOUNT_TYPES","fieldValidators","z","requiredFieldsConfig","createBankFormSchema","options","buildFormSchema"],"mappings":";;AAaO,MAAMA,IAAqB;AAAA,EAChC,UAAU;AAAA,EACV,wBAAwB;AAAA,EACxB,wBAAwB;AAC1B,GAUMC,IAAuB,cACvBC,IAAuB,iBAOhBC,IAAgB,CAAC,YAAY,SAAS,GAQ7CC,IAAkB;AAAA,EACtB,MAAMC,EAAE,OAAA;AAAA,EACR,eAAeA,EACZ,OAAA,EACA,MAAMJ,GAAsB,EAAE,SAASD,EAAmB,wBAAwB;AAAA,EACrF,eAAeK,EACZ,OAAA,EACA,MAAMH,GAAsB,EAAE,SAASF,EAAmB,wBAAwB;AAAA,EACrF,aAAaK,EAAE,KAAKF,CAAa;AACnC,GAwBMG,IAAuB,CAAA;AAgBtB,SAASC,EAAqBC,IAAiC,IAAI;AACxE,SAAOC,EAAgBL,GAAiB;AAAA,IACtC,sBAAAE;AAAA,IACA,mBAAmBN,EAAmB;AAAA,IACtC,MAAM;AAAA,IACN,yBAAyBQ,EAAQ;AAAA,EAAA,CAClC;AACH;"}
1
+ {"version":3,"file":"useBankFormSchema.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/useBankForm/useBankFormSchema.ts"],"sourcesContent":["import { z } from 'zod'\nimport {\n buildFormSchema,\n type OptionalFieldsToRequire,\n type RequiredFieldConfig,\n} from '@/partner-hook-utils/form/buildFormSchema'\nimport { ACCOUNT_NUMBER_REGEX, ROUTING_NUMBER_REGEX } from '@/helpers/validations'\n\n/**\n * Validation error codes emitted by the bank account form schema. Map these\n * codes to localized copy in `validationMessages` when composing the hook.\n *\n * @public\n */\nexport const BankFormErrorCodes = {\n REQUIRED: 'REQUIRED',\n INVALID_ROUTING_NUMBER: 'INVALID_ROUTING_NUMBER',\n INVALID_ACCOUNT_NUMBER: 'INVALID_ACCOUNT_NUMBER',\n} as const\n\n/**\n * Union of validation error code strings emitted by the bank account form\n * schema.\n *\n * @public\n */\nexport type BankFormErrorCode = (typeof BankFormErrorCodes)[keyof typeof BankFormErrorCodes]\n\n/**\n * Supported bank account type values: checking and savings.\n *\n * @public\n */\nexport const ACCOUNT_TYPES = ['Checking', 'Savings'] as const\n/**\n * Union of bank account type values that the form accepts.\n *\n * @public\n */\nexport type AccountType = (typeof ACCOUNT_TYPES)[number]\n\nconst fieldValidators = {\n name: z.string(),\n routingNumber: z\n .string()\n .regex(ROUTING_NUMBER_REGEX, { message: BankFormErrorCodes.INVALID_ROUTING_NUMBER }),\n accountNumber: z\n .string()\n .regex(ACCOUNT_NUMBER_REGEX, { message: BankFormErrorCodes.INVALID_ACCOUNT_NUMBER }),\n accountType: z.enum(ACCOUNT_TYPES),\n}\n\n/**\n * Field names accepted by the bank account form.\n *\n * @public\n */\nexport type BankFormField = keyof typeof fieldValidators\n\n/**\n * Shape of the values managed by the bank account form.\n *\n * @public\n * @interface\n */\nexport type BankFormData = {\n [K in keyof typeof fieldValidators]: z.infer<(typeof fieldValidators)[K]>\n}\n/**\n * Shape of the validated values produced by the bank account form on submit.\n *\n * @public\n */\nexport type BankFormOutputs = BankFormData\n\nconst requiredFieldsConfig = {} satisfies RequiredFieldConfig<typeof fieldValidators>\n\n/**\n * Keys of optional bank account fields that can be promoted to required via\n * the hook's `optionalFieldsToRequire` option.\n *\n * @public\n */\nexport type BankFormOptionalFieldsToRequire = OptionalFieldsToRequire<typeof requiredFieldsConfig>\n\n/** @internal */\ninterface BankFormSchemaOptions {\n optionalFieldsToRequire?: BankFormOptionalFieldsToRequire\n}\n\n/** @internal */\nexport function createBankFormSchema(options: BankFormSchemaOptions = {}) {\n return buildFormSchema(fieldValidators, {\n requiredFieldsConfig,\n requiredErrorCode: BankFormErrorCodes.REQUIRED,\n mode: 'create',\n optionalFieldsToRequire: options.optionalFieldsToRequire,\n })\n}\n"],"names":["BankFormErrorCodes","ACCOUNT_TYPES","fieldValidators","z","ROUTING_NUMBER_REGEX","ACCOUNT_NUMBER_REGEX","requiredFieldsConfig","createBankFormSchema","options","buildFormSchema"],"mappings":";;;AAcO,MAAMA,IAAqB;AAAA,EAChC,UAAU;AAAA,EACV,wBAAwB;AAAA,EACxB,wBAAwB;AAC1B,GAeaC,IAAgB,CAAC,YAAY,SAAS,GAQ7CC,IAAkB;AAAA,EACtB,MAAMC,EAAE,OAAA;AAAA,EACR,eAAeA,EACZ,OAAA,EACA,MAAMC,GAAsB,EAAE,SAASJ,EAAmB,wBAAwB;AAAA,EACrF,eAAeG,EACZ,OAAA,EACA,MAAME,GAAsB,EAAE,SAASL,EAAmB,wBAAwB;AAAA,EACrF,aAAaG,EAAE,KAAKF,CAAa;AACnC,GAyBMK,IAAuB,CAAA;AAgBtB,SAASC,EAAqBC,IAAiC,IAAI;AACxE,SAAOC,EAAgBP,GAAiB;AAAA,IACtC,sBAAAI;AAAA,IACA,mBAAmBN,EAAmB;AAAA,IACtC,MAAM;AAAA,IACN,yBAAyBQ,EAAQ;AAAA,EAAA,CAClC;AACH;"}
@@ -26,7 +26,7 @@ export interface UsePaymentMethodFormProps {
26
26
  * @public
27
27
  */
28
28
  export interface PaymentMethodFormFields {
29
- /** Bound to `type` — see {@link TypeField}. */
29
+ /** Bound to `type`. */
30
30
  Type: typeof TypeField;
31
31
  }
32
32
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"usePaymentMethodForm.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/usePaymentMethodForm/usePaymentMethodForm.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useForm } from 'react-hook-form'\nimport type { UseFormProps } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport type { EmployeePaymentMethod } from '@gusto/embedded-api-v-2025-11-15/models/components/employeepaymentmethod'\nimport { useEmployeePaymentMethodGet } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodGet'\nimport { useEmployeePaymentMethodUpdateMutation } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodUpdate'\nimport {\n PAYMENT_METHOD_TYPES,\n type PaymentMethodFormData,\n type PaymentMethodFormOptionalFieldsToRequire,\n type PaymentMethodFormOutputs,\n type PaymentMethodType,\n createPaymentMethodFormSchema,\n} from './usePaymentMethodFormSchema'\nimport { TypeField } from './fields'\nimport { useDeriveFieldsMetadata } from '@/partner-hook-utils/form/useDeriveFieldsMetadata'\nimport { useHookFormInternals } from '@/partner-hook-utils/form/useHookFormInternals'\nimport { createGetFormSubmissionValues } from '@/partner-hook-utils/form/getFormSubmissionValues'\nimport { withOptions } from '@/partner-hook-utils/form/withOptions'\nimport { composeErrorHandler } from '@/partner-hook-utils/composeErrorHandler'\nimport type {\n BaseFormHookReady,\n FieldsMetadata,\n HookLoadingResult,\n HookSubmitResult,\n} from '@/partner-hook-utils/types'\nimport { useBaseSubmit } from '@/components/Base/useBaseSubmit'\nimport { SDKInternalError } from '@/types/sdkError'\nimport { PAYMENT_METHODS, SPLIT_BY } from '@/shared/constants'\n\n/**\n * Props for {@link usePaymentMethodForm}.\n *\n * @public\n */\nexport interface UsePaymentMethodFormProps {\n /** Employee whose payment method is being edited. */\n employeeId: string\n /** Override optional fields to be required. Reserved for future schema expansion — `type` is always required and always has a default. */\n optionalFieldsToRequire?: PaymentMethodFormOptionalFieldsToRequire\n /** Pre-fill form values. Server data (the current payment method) is used when no override is supplied. */\n defaultValues?: Partial<PaymentMethodFormData>\n /** When validation runs. Passed through to react-hook-form. Defaults to `'onSubmit'`. */\n validationMode?: UseFormProps['mode']\n /** Auto-focus the first invalid field on submit. Set to `false` when using `composeSubmitHandler`. Defaults to `true`. */\n shouldFocusError?: boolean\n}\n\n/**\n * Field components exposed by {@link usePaymentMethodForm} on `form.Fields`.\n *\n * @public\n */\nexport interface PaymentMethodFormFields {\n /** Bound to `type` — see {@link TypeField}. */\n Type: typeof TypeField\n}\n\n/**\n * Ready-state return value of {@link usePaymentMethodForm}.\n *\n * @public\n */\nexport interface UsePaymentMethodFormReady extends BaseFormHookReady<\n FieldsMetadata,\n PaymentMethodFormData,\n PaymentMethodFormFields\n> {\n /** The employee's current payment method, loaded from the API. */\n data: {\n paymentMethod: EmployeePaymentMethod\n }\n /** `isPending` reflects the in-flight update mutation; `mode` is always `'update'`. */\n status: { isPending: boolean; mode: 'update' }\n /** Submit the form. Returns the updated payment method on success or `undefined` on validation/mutation failure. */\n actions: {\n onSubmit: () => Promise<HookSubmitResult<EmployeePaymentMethod> | undefined>\n }\n}\n\n/**\n * Headless React Hook Form hook for updating an employee's payment method.\n *\n * @remarks\n * Switches between Direct Deposit and Check. Always operates in update mode —\n * every employee has a payment method, defaulting to Check. Switching to Check\n * sends a minimal request body; switching to or staying on Direct Deposit\n * preserves the existing splits and version so split allocations are not lost\n * when only the type changes.\n *\n * @param props - See {@link UsePaymentMethodFormProps}.\n * @returns A loading-state result while the current payment method is loading, or a {@link UsePaymentMethodFormReady} once ready.\n * @public\n *\n * @example\n * ```tsx\n * import {\n * usePaymentMethodForm,\n * SDKFormProvider,\n * PAYMENT_METHODS,\n * type PaymentMethodType,\n * } from '@gusto/embedded-react-sdk'\n *\n * function PaymentMethodScreen({ employeeId }: { employeeId: string }) {\n * const paymentMethodForm = usePaymentMethodForm({ employeeId })\n *\n * if (paymentMethodForm.isLoading) return null\n * const { Fields } = paymentMethodForm.form\n *\n * return (\n * <SDKFormProvider formHookResult={paymentMethodForm}>\n * <form\n * onSubmit={e => {\n * e.preventDefault()\n * void paymentMethodForm.actions.onSubmit()\n * }}\n * >\n * <Fields.Type\n * label=\"Select payment method\"\n * getOptionLabel={(value: PaymentMethodType) =>\n * value === PAYMENT_METHODS.directDeposit ? 'Direct Deposit' : 'Check'\n * }\n * />\n * <button type=\"submit\" disabled={paymentMethodForm.status.isPending}>Save</button>\n * </form>\n * </SDKFormProvider>\n * )\n * }\n * ```\n */\nexport function usePaymentMethodForm({\n employeeId,\n optionalFieldsToRequire,\n defaultValues: partnerDefaults,\n validationMode = 'onSubmit',\n shouldFocusError = true,\n}: UsePaymentMethodFormProps): HookLoadingResult | UsePaymentMethodFormReady {\n const paymentMethodQuery = useEmployeePaymentMethodGet({ employeeId })\n const paymentMethod = paymentMethodQuery.data?.employeePaymentMethod\n\n const [schema, metadataConfig] = useMemo(\n () => createPaymentMethodFormSchema({ optionalFieldsToRequire }),\n [optionalFieldsToRequire],\n )\n\n const resolvedDefaults: PaymentMethodFormData = useMemo(\n () => ({\n type: (partnerDefaults?.type ??\n paymentMethod?.type ??\n PAYMENT_METHODS.directDeposit) as PaymentMethodType,\n }),\n [partnerDefaults, paymentMethod],\n )\n\n const formMethods = useForm<PaymentMethodFormData, unknown, PaymentMethodFormOutputs>({\n resolver: zodResolver(schema),\n mode: validationMode,\n shouldFocusError,\n defaultValues: resolvedDefaults,\n values: resolvedDefaults,\n resetOptions: { keepDirtyValues: true },\n })\n\n const updateMutation = useEmployeePaymentMethodUpdateMutation()\n const isPending = updateMutation.isPending\n\n const {\n baseSubmitHandler,\n error: submitError,\n setError: setSubmitError,\n } = useBaseSubmit('PaymentMethodForm')\n\n const errorHandling = composeErrorHandler([paymentMethodQuery], {\n submitError,\n setSubmitError,\n })\n\n const typeOptions = PAYMENT_METHOD_TYPES.map(value => ({ value, label: value }))\n\n const baseMetadata = useDeriveFieldsMetadata(metadataConfig, formMethods.control)\n const fieldsMetadata = {\n type: withOptions<PaymentMethodType>(baseMetadata.type, typeOptions, [...PAYMENT_METHOD_TYPES]),\n }\n\n const onSubmit = async (): Promise<HookSubmitResult<EmployeePaymentMethod> | undefined> => {\n if (!paymentMethod) {\n throw new SDKInternalError('Cannot submit payment method form before data is loaded')\n }\n const currentPaymentMethod = paymentMethod\n let submitResult: HookSubmitResult<EmployeePaymentMethod> | undefined\n\n await new Promise<void>(resolve => {\n void formMethods.handleSubmit(\n async (data: PaymentMethodFormOutputs) => {\n await baseSubmitHandler(data, async payload => {\n const version = currentPaymentMethod.version as string\n const body =\n payload.type === PAYMENT_METHODS.check\n ? { version }\n : {\n ...currentPaymentMethod,\n version,\n splitBy: currentPaymentMethod.splitBy ?? SPLIT_BY.percentage,\n splits: currentPaymentMethod.splits ?? [],\n }\n\n const response = await updateMutation.mutateAsync({\n request: { employeeId, requestBody: { ...body, type: payload.type } },\n })\n\n if (!response.employeePaymentMethod) {\n throw new SDKInternalError('Payment method update failed')\n }\n\n submitResult = { mode: 'update' as const, data: response.employeePaymentMethod }\n })\n resolve()\n },\n () => {\n resolve()\n },\n )()\n })\n\n return submitResult\n }\n\n const hookFormInternals = useHookFormInternals(formMethods)\n\n if (paymentMethodQuery.isLoading || !paymentMethod) {\n return { isLoading: true as const, errorHandling }\n }\n\n return {\n isLoading: false as const,\n data: { paymentMethod },\n status: { isPending, mode: 'update' as const },\n actions: { onSubmit },\n errorHandling,\n form: {\n Fields: {\n Type: TypeField,\n },\n fieldsMetadata,\n hookFormInternals,\n getFormSubmissionValues: createGetFormSubmissionValues(formMethods, schema),\n },\n }\n}\n\n/**\n * Return type of {@link usePaymentMethodForm} — a discriminated union on `isLoading`.\n *\n * @public\n */\nexport type UsePaymentMethodFormResult = HookLoadingResult | UsePaymentMethodFormReady\n\n/**\n * Per-field metadata exposed on `form.fieldsMetadata` for {@link usePaymentMethodForm}.\n *\n * @public\n */\nexport type PaymentMethodFormFieldsMetadata = UsePaymentMethodFormReady['form']['fieldsMetadata']\n"],"names":["usePaymentMethodForm","employeeId","optionalFieldsToRequire","partnerDefaults","validationMode","shouldFocusError","paymentMethodQuery","useEmployeePaymentMethodGet","paymentMethod","schema","metadataConfig","useMemo","createPaymentMethodFormSchema","resolvedDefaults","PAYMENT_METHODS","formMethods","useForm","zodResolver","updateMutation","useEmployeePaymentMethodUpdateMutation","isPending","baseSubmitHandler","submitError","setSubmitError","useBaseSubmit","errorHandling","composeErrorHandler","typeOptions","PAYMENT_METHOD_TYPES","value","baseMetadata","useDeriveFieldsMetadata","fieldsMetadata","withOptions","onSubmit","SDKInternalError","currentPaymentMethod","submitResult","resolve","data","payload","version","body","SPLIT_BY","response","hookFormInternals","useHookFormInternals","TypeField","createGetFormSubmissionValues"],"mappings":"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"}
1
+ {"version":3,"file":"usePaymentMethodForm.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/usePaymentMethodForm/usePaymentMethodForm.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useForm } from 'react-hook-form'\nimport type { UseFormProps } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport type { EmployeePaymentMethod } from '@gusto/embedded-api-v-2025-11-15/models/components/employeepaymentmethod'\nimport { useEmployeePaymentMethodGet } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodGet'\nimport { useEmployeePaymentMethodUpdateMutation } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodUpdate'\nimport {\n PAYMENT_METHOD_TYPES,\n type PaymentMethodFormData,\n type PaymentMethodFormOptionalFieldsToRequire,\n type PaymentMethodFormOutputs,\n type PaymentMethodType,\n createPaymentMethodFormSchema,\n} from './usePaymentMethodFormSchema'\nimport { TypeField } from './fields'\nimport { useDeriveFieldsMetadata } from '@/partner-hook-utils/form/useDeriveFieldsMetadata'\nimport { useHookFormInternals } from '@/partner-hook-utils/form/useHookFormInternals'\nimport { createGetFormSubmissionValues } from '@/partner-hook-utils/form/getFormSubmissionValues'\nimport { withOptions } from '@/partner-hook-utils/form/withOptions'\nimport { composeErrorHandler } from '@/partner-hook-utils/composeErrorHandler'\nimport type {\n BaseFormHookReady,\n FieldsMetadata,\n HookLoadingResult,\n HookSubmitResult,\n} from '@/partner-hook-utils/types'\nimport { useBaseSubmit } from '@/components/Base/useBaseSubmit'\nimport { SDKInternalError } from '@/types/sdkError'\nimport { PAYMENT_METHODS, SPLIT_BY } from '@/shared/constants'\n\n/**\n * Props for {@link usePaymentMethodForm}.\n *\n * @public\n */\nexport interface UsePaymentMethodFormProps {\n /** Employee whose payment method is being edited. */\n employeeId: string\n /** Override optional fields to be required. Reserved for future schema expansion — `type` is always required and always has a default. */\n optionalFieldsToRequire?: PaymentMethodFormOptionalFieldsToRequire\n /** Pre-fill form values. Server data (the current payment method) is used when no override is supplied. */\n defaultValues?: Partial<PaymentMethodFormData>\n /** When validation runs. Passed through to react-hook-form. Defaults to `'onSubmit'`. */\n validationMode?: UseFormProps['mode']\n /** Auto-focus the first invalid field on submit. Set to `false` when using `composeSubmitHandler`. Defaults to `true`. */\n shouldFocusError?: boolean\n}\n\n/**\n * Field components exposed by {@link usePaymentMethodForm} on `form.Fields`.\n *\n * @public\n */\nexport interface PaymentMethodFormFields {\n /** Bound to `type`. */\n Type: typeof TypeField\n}\n\n/**\n * Ready-state return value of {@link usePaymentMethodForm}.\n *\n * @public\n */\nexport interface UsePaymentMethodFormReady extends BaseFormHookReady<\n FieldsMetadata,\n PaymentMethodFormData,\n PaymentMethodFormFields\n> {\n /** The employee's current payment method, loaded from the API. */\n data: {\n paymentMethod: EmployeePaymentMethod\n }\n /** `isPending` reflects the in-flight update mutation; `mode` is always `'update'`. */\n status: { isPending: boolean; mode: 'update' }\n /** Submit the form. Returns the updated payment method on success or `undefined` on validation/mutation failure. */\n actions: {\n onSubmit: () => Promise<HookSubmitResult<EmployeePaymentMethod> | undefined>\n }\n}\n\n/**\n * Headless React Hook Form hook for updating an employee's payment method.\n *\n * @remarks\n * Switches between Direct Deposit and Check. Always operates in update mode —\n * every employee has a payment method, defaulting to Check. Switching to Check\n * sends a minimal request body; switching to or staying on Direct Deposit\n * preserves the existing splits and version so split allocations are not lost\n * when only the type changes.\n *\n * @param props - See {@link UsePaymentMethodFormProps}.\n * @returns A loading-state result while the current payment method is loading, or a {@link UsePaymentMethodFormReady} once ready.\n * @public\n *\n * @example\n * ```tsx\n * import {\n * usePaymentMethodForm,\n * SDKFormProvider,\n * PAYMENT_METHODS,\n * type PaymentMethodType,\n * } from '@gusto/embedded-react-sdk'\n *\n * function PaymentMethodScreen({ employeeId }: { employeeId: string }) {\n * const paymentMethodForm = usePaymentMethodForm({ employeeId })\n *\n * if (paymentMethodForm.isLoading) return null\n * const { Fields } = paymentMethodForm.form\n *\n * return (\n * <SDKFormProvider formHookResult={paymentMethodForm}>\n * <form\n * onSubmit={e => {\n * e.preventDefault()\n * void paymentMethodForm.actions.onSubmit()\n * }}\n * >\n * <Fields.Type\n * label=\"Select payment method\"\n * getOptionLabel={(value: PaymentMethodType) =>\n * value === PAYMENT_METHODS.directDeposit ? 'Direct Deposit' : 'Check'\n * }\n * />\n * <button type=\"submit\" disabled={paymentMethodForm.status.isPending}>Save</button>\n * </form>\n * </SDKFormProvider>\n * )\n * }\n * ```\n */\nexport function usePaymentMethodForm({\n employeeId,\n optionalFieldsToRequire,\n defaultValues: partnerDefaults,\n validationMode = 'onSubmit',\n shouldFocusError = true,\n}: UsePaymentMethodFormProps): HookLoadingResult | UsePaymentMethodFormReady {\n const paymentMethodQuery = useEmployeePaymentMethodGet({ employeeId })\n const paymentMethod = paymentMethodQuery.data?.employeePaymentMethod\n\n const [schema, metadataConfig] = useMemo(\n () => createPaymentMethodFormSchema({ optionalFieldsToRequire }),\n [optionalFieldsToRequire],\n )\n\n const resolvedDefaults: PaymentMethodFormData = useMemo(\n () => ({\n type: (partnerDefaults?.type ??\n paymentMethod?.type ??\n PAYMENT_METHODS.directDeposit) as PaymentMethodType,\n }),\n [partnerDefaults, paymentMethod],\n )\n\n const formMethods = useForm<PaymentMethodFormData, unknown, PaymentMethodFormOutputs>({\n resolver: zodResolver(schema),\n mode: validationMode,\n shouldFocusError,\n defaultValues: resolvedDefaults,\n values: resolvedDefaults,\n resetOptions: { keepDirtyValues: true },\n })\n\n const updateMutation = useEmployeePaymentMethodUpdateMutation()\n const isPending = updateMutation.isPending\n\n const {\n baseSubmitHandler,\n error: submitError,\n setError: setSubmitError,\n } = useBaseSubmit('PaymentMethodForm')\n\n const errorHandling = composeErrorHandler([paymentMethodQuery], {\n submitError,\n setSubmitError,\n })\n\n const typeOptions = PAYMENT_METHOD_TYPES.map(value => ({ value, label: value }))\n\n const baseMetadata = useDeriveFieldsMetadata(metadataConfig, formMethods.control)\n const fieldsMetadata = {\n type: withOptions<PaymentMethodType>(baseMetadata.type, typeOptions, [...PAYMENT_METHOD_TYPES]),\n }\n\n const onSubmit = async (): Promise<HookSubmitResult<EmployeePaymentMethod> | undefined> => {\n if (!paymentMethod) {\n throw new SDKInternalError('Cannot submit payment method form before data is loaded')\n }\n const currentPaymentMethod = paymentMethod\n let submitResult: HookSubmitResult<EmployeePaymentMethod> | undefined\n\n await new Promise<void>(resolve => {\n void formMethods.handleSubmit(\n async (data: PaymentMethodFormOutputs) => {\n await baseSubmitHandler(data, async payload => {\n const version = currentPaymentMethod.version as string\n const body =\n payload.type === PAYMENT_METHODS.check\n ? { version }\n : {\n ...currentPaymentMethod,\n version,\n splitBy: currentPaymentMethod.splitBy ?? SPLIT_BY.percentage,\n splits: currentPaymentMethod.splits ?? [],\n }\n\n const response = await updateMutation.mutateAsync({\n request: { employeeId, requestBody: { ...body, type: payload.type } },\n })\n\n if (!response.employeePaymentMethod) {\n throw new SDKInternalError('Payment method update failed')\n }\n\n submitResult = { mode: 'update' as const, data: response.employeePaymentMethod }\n })\n resolve()\n },\n () => {\n resolve()\n },\n )()\n })\n\n return submitResult\n }\n\n const hookFormInternals = useHookFormInternals(formMethods)\n\n if (paymentMethodQuery.isLoading || !paymentMethod) {\n return { isLoading: true as const, errorHandling }\n }\n\n return {\n isLoading: false as const,\n data: { paymentMethod },\n status: { isPending, mode: 'update' as const },\n actions: { onSubmit },\n errorHandling,\n form: {\n Fields: {\n Type: TypeField,\n },\n fieldsMetadata,\n hookFormInternals,\n getFormSubmissionValues: createGetFormSubmissionValues(formMethods, schema),\n },\n }\n}\n\n/**\n * Return type of {@link usePaymentMethodForm} — a discriminated union on `isLoading`.\n *\n * @public\n */\nexport type UsePaymentMethodFormResult = HookLoadingResult | UsePaymentMethodFormReady\n\n/**\n * Per-field metadata exposed on `form.fieldsMetadata` for {@link usePaymentMethodForm}.\n *\n * @public\n */\nexport type PaymentMethodFormFieldsMetadata = UsePaymentMethodFormReady['form']['fieldsMetadata']\n"],"names":["usePaymentMethodForm","employeeId","optionalFieldsToRequire","partnerDefaults","validationMode","shouldFocusError","paymentMethodQuery","useEmployeePaymentMethodGet","paymentMethod","schema","metadataConfig","useMemo","createPaymentMethodFormSchema","resolvedDefaults","PAYMENT_METHODS","formMethods","useForm","zodResolver","updateMutation","useEmployeePaymentMethodUpdateMutation","isPending","baseSubmitHandler","submitError","setSubmitError","useBaseSubmit","errorHandling","composeErrorHandler","typeOptions","PAYMENT_METHOD_TYPES","value","baseMetadata","useDeriveFieldsMetadata","fieldsMetadata","withOptions","onSubmit","SDKInternalError","currentPaymentMethod","submitResult","resolve","data","payload","version","body","SPLIT_BY","response","hookFormInternals","useHookFormInternals","TypeField","createGetFormSubmissionValues"],"mappings":"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"}
@@ -38,6 +38,7 @@ export type PaymentMethodFormField = "type";
38
38
  * Shape of the values managed by the payment method form.
39
39
  *
40
40
  * @public
41
+ * @interface
41
42
  */
42
43
  export type PaymentMethodFormData = { type: "Check" | "Direct Deposit"; };
43
44
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"usePaymentMethodFormSchema.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/usePaymentMethodForm/usePaymentMethodFormSchema.ts"],"sourcesContent":["import { z } from 'zod'\nimport {\n buildFormSchema,\n type OptionalFieldsToRequire,\n type RequiredFieldConfig,\n} from '@/partner-hook-utils/form/buildFormSchema'\nimport { PAYMENT_METHODS } from '@/shared/constants'\n\n/**\n * Validation error codes emitted by the payment method form schema. Map these\n * codes to localized copy in `validationMessages` when composing the hook.\n *\n * @public\n */\nexport const PaymentMethodFormErrorCodes = {\n REQUIRED: 'REQUIRED',\n} as const\n\n/**\n * Union of validation error code strings emitted by the payment method form\n * schema.\n *\n * @public\n */\nexport type PaymentMethodFormErrorCode =\n (typeof PaymentMethodFormErrorCodes)[keyof typeof PaymentMethodFormErrorCodes]\n\n/**\n * Supported payment method type values: direct deposit and check.\n *\n * @public\n */\nexport const PAYMENT_METHOD_TYPES = [PAYMENT_METHODS.directDeposit, PAYMENT_METHODS.check] as const\n\n/**\n * Union of payment method type values that the form accepts.\n *\n * @public\n */\nexport type PaymentMethodType = (typeof PAYMENT_METHOD_TYPES)[number]\n\nconst fieldValidators = {\n type: z.enum(PAYMENT_METHOD_TYPES),\n}\n\n/**\n * Field names accepted by the payment method form.\n *\n * @public\n */\nexport type PaymentMethodFormField = keyof typeof fieldValidators\n\n/**\n * Shape of the values managed by the payment method form.\n *\n * @public\n */\nexport type PaymentMethodFormData = {\n [K in keyof typeof fieldValidators]: z.infer<(typeof fieldValidators)[K]>\n}\n/**\n * Shape of the validated values produced by the payment method form on submit.\n *\n * @public\n */\nexport type PaymentMethodFormOutputs = PaymentMethodFormData\n\nconst requiredFieldsConfig = {} satisfies RequiredFieldConfig<typeof fieldValidators>\n\n/**\n * Keys of optional payment method fields that can be promoted to required via\n * the hook's `optionalFieldsToRequire` option.\n *\n * @public\n */\nexport type PaymentMethodFormOptionalFieldsToRequire = OptionalFieldsToRequire<\n typeof requiredFieldsConfig\n>\n\n/** @internal */\ninterface PaymentMethodFormSchemaOptions {\n optionalFieldsToRequire?: PaymentMethodFormOptionalFieldsToRequire\n}\n\n/** @internal */\nexport function createPaymentMethodFormSchema(options: PaymentMethodFormSchemaOptions = {}) {\n return buildFormSchema(fieldValidators, {\n requiredFieldsConfig,\n requiredErrorCode: PaymentMethodFormErrorCodes.REQUIRED,\n mode: 'update',\n optionalFieldsToRequire: options.optionalFieldsToRequire,\n })\n}\n"],"names":["PaymentMethodFormErrorCodes","PAYMENT_METHOD_TYPES","PAYMENT_METHODS","fieldValidators","z","requiredFieldsConfig","createPaymentMethodFormSchema","options","buildFormSchema"],"mappings":";;;AAcO,MAAMA,IAA8B;AAAA,EACzC,UAAU;AACZ,GAgBaC,IAAuB,CAACC,EAAgB,eAAeA,EAAgB,KAAK,GASnFC,IAAkB;AAAA,EACtB,MAAMC,EAAE,KAAKH,CAAoB;AACnC,GAwBMI,IAAuB,CAAA;AAkBtB,SAASC,EAA8BC,IAA0C,IAAI;AAC1F,SAAOC,EAAgBL,GAAiB;AAAA,IACtC,sBAAAE;AAAA,IACA,mBAAmBL,EAA4B;AAAA,IAC/C,MAAM;AAAA,IACN,yBAAyBO,EAAQ;AAAA,EAAA,CAClC;AACH;"}
1
+ {"version":3,"file":"usePaymentMethodFormSchema.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/usePaymentMethodForm/usePaymentMethodFormSchema.ts"],"sourcesContent":["import { z } from 'zod'\nimport {\n buildFormSchema,\n type OptionalFieldsToRequire,\n type RequiredFieldConfig,\n} from '@/partner-hook-utils/form/buildFormSchema'\nimport { PAYMENT_METHODS } from '@/shared/constants'\n\n/**\n * Validation error codes emitted by the payment method form schema. Map these\n * codes to localized copy in `validationMessages` when composing the hook.\n *\n * @public\n */\nexport const PaymentMethodFormErrorCodes = {\n REQUIRED: 'REQUIRED',\n} as const\n\n/**\n * Union of validation error code strings emitted by the payment method form\n * schema.\n *\n * @public\n */\nexport type PaymentMethodFormErrorCode =\n (typeof PaymentMethodFormErrorCodes)[keyof typeof PaymentMethodFormErrorCodes]\n\n/**\n * Supported payment method type values: direct deposit and check.\n *\n * @public\n */\nexport const PAYMENT_METHOD_TYPES = [PAYMENT_METHODS.directDeposit, PAYMENT_METHODS.check] as const\n\n/**\n * Union of payment method type values that the form accepts.\n *\n * @public\n */\nexport type PaymentMethodType = (typeof PAYMENT_METHOD_TYPES)[number]\n\nconst fieldValidators = {\n type: z.enum(PAYMENT_METHOD_TYPES),\n}\n\n/**\n * Field names accepted by the payment method form.\n *\n * @public\n */\nexport type PaymentMethodFormField = keyof typeof fieldValidators\n\n/**\n * Shape of the values managed by the payment method form.\n *\n * @public\n * @interface\n */\nexport type PaymentMethodFormData = {\n [K in keyof typeof fieldValidators]: z.infer<(typeof fieldValidators)[K]>\n}\n/**\n * Shape of the validated values produced by the payment method form on submit.\n *\n * @public\n */\nexport type PaymentMethodFormOutputs = PaymentMethodFormData\n\nconst requiredFieldsConfig = {} satisfies RequiredFieldConfig<typeof fieldValidators>\n\n/**\n * Keys of optional payment method fields that can be promoted to required via\n * the hook's `optionalFieldsToRequire` option.\n *\n * @public\n */\nexport type PaymentMethodFormOptionalFieldsToRequire = OptionalFieldsToRequire<\n typeof requiredFieldsConfig\n>\n\n/** @internal */\ninterface PaymentMethodFormSchemaOptions {\n optionalFieldsToRequire?: PaymentMethodFormOptionalFieldsToRequire\n}\n\n/** @internal */\nexport function createPaymentMethodFormSchema(options: PaymentMethodFormSchemaOptions = {}) {\n return buildFormSchema(fieldValidators, {\n requiredFieldsConfig,\n requiredErrorCode: PaymentMethodFormErrorCodes.REQUIRED,\n mode: 'update',\n optionalFieldsToRequire: options.optionalFieldsToRequire,\n })\n}\n"],"names":["PaymentMethodFormErrorCodes","PAYMENT_METHOD_TYPES","PAYMENT_METHODS","fieldValidators","z","requiredFieldsConfig","createPaymentMethodFormSchema","options","buildFormSchema"],"mappings":";;;AAcO,MAAMA,IAA8B;AAAA,EACzC,UAAU;AACZ,GAgBaC,IAAuB,CAACC,EAAgB,eAAeA,EAAgB,KAAK,GASnFC,IAAkB;AAAA,EACtB,MAAMC,EAAE,KAAKH,CAAoB;AACnC,GAyBMI,IAAuB,CAAA;AAkBtB,SAASC,EAA8BC,IAA0C,IAAI;AAC1F,SAAOC,EAAgBL,GAAiB;AAAA,IACtC,sBAAAE;AAAA,IACA,mBAAmBL,EAA4B;AAAA,IAC/C,MAAM;AAAA,IACN,yBAAyBO,EAAQ;AAAA,EAAA,CAClC;AACH;"}
@@ -50,7 +50,7 @@ export interface UseSplitPaymentsFormProps {
50
50
  * @public
51
51
  */
52
52
  export interface SplitPaymentsFormFields {
53
- /** Bound to `splitBy` see {@link SplitByField}. */
53
+ /** Radio group bound to `splitBy`; selects Percentage or Amount split mode. */
54
54
  SplitBy: ComponentType<SplitByFieldProps>;
55
55
  /** One entry per bank account, each carrying a pre-bound `Field` component for the per-split amount. */
56
56
  splits: SplitFieldEntry[];
@@ -167,7 +167,7 @@ export interface UseSplitPaymentsFormReady extends BaseFormHookReady<FieldsMetad
167
167
  * }
168
168
  * ```
169
169
  */
170
- export declare function useSplitPaymentsForm({ employeeId, optionalFieldsToRequire, validationMode, shouldFocusError, }: UseSplitPaymentsFormProps): HookLoadingResult | UseSplitPaymentsFormReady;
170
+ export declare function useSplitPaymentsForm({ employeeId, optionalFieldsToRequire, validationMode, shouldFocusError, }: UseSplitPaymentsFormProps): UseSplitPaymentsFormResult;
171
171
  /**
172
172
  * Return type of {@link useSplitPaymentsForm} — a discriminated union on `isLoading`.
173
173
  *
@@ -1 +1 @@
1
- {"version":3,"file":"useSplitPaymentsForm.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/useSplitPaymentsForm/useSplitPaymentsForm.tsx"],"sourcesContent":["import type { ComponentType } from 'react'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport { useForm, useFormState, useWatch } from 'react-hook-form'\nimport type { UseFormProps } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport type { EmployeeBankAccount } from '@gusto/embedded-api-v-2025-11-15/models/components/employeebankaccount'\nimport type { EmployeePaymentMethod } from '@gusto/embedded-api-v-2025-11-15/models/components/employeepaymentmethod'\nimport { useEmployeePaymentMethodGet } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodGet'\nimport { useEmployeePaymentMethodsGetBankAccounts } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodsGetBankAccounts'\nimport { useEmployeePaymentMethodUpdateMutation } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodUpdate'\nimport {\n PERCENTAGE_TOTAL_PATH,\n SPLIT_BY_VALUES,\n SplitPaymentsFormErrorCodes,\n type SplitByValue,\n type SplitPaymentsFormData,\n type SplitPaymentsFormOptionalFieldsToRequire,\n type SplitPaymentsFormOutputs,\n createSplitPaymentsFormSchema,\n} from './useSplitPaymentsFormSchema'\nimport { SplitByField, type SplitByFieldProps } from './fields'\nimport { buildSplitFieldEntries, type SplitFieldEntry } from './splitFieldFactory'\nimport { useDeriveFieldsMetadata } from '@/partner-hook-utils/form/useDeriveFieldsMetadata'\nimport { useHookFormInternals } from '@/partner-hook-utils/form/useHookFormInternals'\nimport { createGetFormSubmissionValues } from '@/partner-hook-utils/form/getFormSubmissionValues'\nimport { withOptions } from '@/partner-hook-utils/form/withOptions'\nimport { composeErrorHandler } from '@/partner-hook-utils/composeErrorHandler'\nimport type {\n BaseFormHookReady,\n FieldsMetadata,\n HookLoadingResult,\n HookSubmitResult,\n} from '@/partner-hook-utils/types'\nimport { useBaseSubmit } from '@/components/Base/useBaseSubmit'\nimport { SDKInternalError } from '@/types/sdkError'\nimport { centsToDollars, dollarsToCents } from '@/helpers/currencyHelpers'\nimport { PAYMENT_METHODS, SPLIT_BY } from '@/shared/constants'\n\n/**\n * A single split entry — pairs a bank account identifier with its current split allocation.\n *\n * @remarks\n * Surfaced on `data.splits` from {@link useSplitPaymentsForm}. Derived from\n * `paymentMethod.splits` when present, otherwise from the employee's bank\n * accounts (one entry per account, no allocated amount). Carries the raw\n * domain data — use it for label construction or lookups by uuid.\n *\n * @public\n */\nexport interface WorkingSplit {\n /** UUID of the underlying bank account. */\n uuid: string\n /** Account nickname, when available. */\n name: string | null\n /** Masked account number suffix, when available. */\n hiddenAccountNumber: string | null\n /** Allocation amount — `null` for the remainder split in Amount mode and for splits that haven't been allocated yet. */\n splitAmount: number | null\n /** Ordering value — splits are processed in ascending priority; the highest priority is the remainder. */\n priority: number\n}\n\n/**\n * Props for {@link useSplitPaymentsForm}.\n *\n * @public\n */\nexport interface UseSplitPaymentsFormProps {\n /** Employee whose payment splits are being edited. */\n employeeId: string\n /** Override optional fields to be required. Currently a no-op — `splitBy` and `priority` are always required, and per-split `splitAmount` required-ness is automatic. */\n optionalFieldsToRequire?: SplitPaymentsFormOptionalFieldsToRequire\n /** When validation runs. Passed through to react-hook-form. Defaults to `'onSubmit'`. */\n validationMode?: UseFormProps['mode']\n /** Auto-focus the first invalid field on submit. Set to `false` when using `composeSubmitHandler`. Defaults to `true`. */\n shouldFocusError?: boolean\n}\n\n/**\n * Field components exposed by {@link useSplitPaymentsForm} on `form.Fields`.\n *\n * @public\n */\nexport interface SplitPaymentsFormFields {\n /** Bound to `splitBy` — see {@link SplitByField}. */\n SplitBy: ComponentType<SplitByFieldProps>\n /** One entry per bank account, each carrying a pre-bound `Field` component for the per-split amount. */\n splits: SplitFieldEntry[]\n}\n\n/**\n * Ready-state return value of {@link useSplitPaymentsForm}.\n *\n * @public\n */\nexport interface UseSplitPaymentsFormReady extends BaseFormHookReady<\n FieldsMetadata,\n SplitPaymentsFormData,\n SplitPaymentsFormFields\n> {\n /** Server-fetched data and derived working values. */\n data: {\n /** The employee's current payment method. */\n paymentMethod: EmployeePaymentMethod\n /** All bank accounts available to allocate splits across. */\n bankAccounts: EmployeeBankAccount[]\n /** The current working split entries, one per bank account. */\n splits: WorkingSplit[]\n /** UUID of the split that absorbs the remainder in Amount mode (always the last by priority). */\n remainderId: string\n }\n /** Submission state and reactive form-level flags. */\n status: {\n /** `true` while the update mutation is in flight. */\n isPending: boolean\n /** Always `'update'` — the hook always edits an existing payment method. */\n mode: 'update'\n /** Current `splitBy` value, reactively tracked. */\n splitBy: SplitByValue\n /** Live sum of `splitAmount` values; useful for displaying the current total in Percentage mode. */\n percentageTotal: number\n /**\n * `true` after a failed Percentage-mode Save when the splits don't sum to\n * 100; clears live as the user corrects the total. Follows the standard\n * react-hook-form validation lifecycle (controlled by `validationMode`).\n * Only surfaces in Percentage mode.\n */\n hasPercentageImbalance: boolean\n }\n /** Actions that mutate the form or submit it. */\n actions: {\n /** Submit the form. Returns the updated payment method on success or `undefined` on validation/mutation failure. */\n onSubmit: () => Promise<HookSubmitResult<EmployeePaymentMethod> | undefined>\n /**\n * Reorder splits by uuid (Amount mode). Pass the ordered list of split\n * uuids; the last uuid becomes the remainder. The hook writes the new\n * priority map and re-anchors the remainder's `splitAmount` to `null`\n * (clearing the previous remainder to `0`).\n */\n reorderSplits: (orderedUuids: string[]) => void\n }\n}\n\nconst buildWorkingSplits = (\n paymentMethod: EmployeePaymentMethod,\n bankAccounts: EmployeeBankAccount[],\n): WorkingSplit[] => {\n if (paymentMethod.splits && paymentMethod.splits.length > 0) {\n return paymentMethod.splits.map(split => ({\n uuid: split.uuid,\n name: split.name ?? null,\n hiddenAccountNumber: split.hiddenAccountNumber ?? null,\n splitAmount: split.splitAmount ?? null,\n priority: split.priority ?? 0,\n }))\n }\n return bankAccounts.map((account, index) => ({\n uuid: account.uuid,\n name: account.name ?? null,\n hiddenAccountNumber: account.hiddenAccountNumber ?? null,\n splitAmount: null,\n priority: index + 1,\n }))\n}\n\n/**\n * Headless React Hook Form hook for splitting an employee's Direct Deposit across multiple bank accounts.\n *\n * @remarks\n * Supports two split modes: Percentage (whole-number shares that sum to 100)\n * and Amount (dollar amounts, with the last-priority split absorbing the\n * remainder). Always operates in update mode against the employee's existing\n * payment method.\n *\n * The Percentage sum-to-100 invariant is surfaced via\n * `status.hasPercentageImbalance` (not as a per-field error). With the default\n * `validationMode: 'onSubmit'`, the imbalance flag appears after the first\n * failed Save and clears live as the user corrects the total.\n *\n * @param props - See {@link UseSplitPaymentsFormProps}.\n * @returns A loading-state result while the payment method and bank accounts are loading, or a {@link UseSplitPaymentsFormReady} once ready.\n * @public\n *\n * @example\n * ```tsx\n * import {\n * useSplitPaymentsForm,\n * SDKFormProvider,\n * type SplitByValue,\n * type UseSplitPaymentsFormReady,\n * } from '@gusto/embedded-react-sdk'\n *\n * function SplitPaycheckScreen({ employeeId }: { employeeId: string }) {\n * const splitForm = useSplitPaymentsForm({ employeeId })\n *\n * if (splitForm.isLoading) return null\n * return <SplitPaycheckReady splitForm={splitForm} />\n * }\n *\n * function SplitPaycheckReady({ splitForm }: { splitForm: UseSplitPaymentsFormReady }) {\n * const { Fields } = splitForm.form\n * const { hasPercentageImbalance, percentageTotal } = splitForm.status\n *\n * return (\n * <SDKFormProvider formHookResult={splitForm}>\n * <form\n * onSubmit={e => {\n * e.preventDefault()\n * void splitForm.actions.onSubmit()\n * }}\n * >\n * {hasPercentageImbalance && (\n * <div role=\"alert\">Splits must total 100%. Currently {percentageTotal}%.</div>\n * )}\n * <Fields.SplitBy label=\"Split by\" getOptionLabel={(value: SplitByValue) => value} />\n * {Fields.splits.map(split => (\n * <split.Field\n * key={split.uuid}\n * label={split.name ?? 'Account'}\n * min={0}\n * />\n * ))}\n * <button type=\"submit\" disabled={splitForm.status.isPending}>Save</button>\n * </form>\n * </SDKFormProvider>\n * )\n * }\n * ```\n */\nexport function useSplitPaymentsForm({\n employeeId,\n optionalFieldsToRequire,\n validationMode = 'onSubmit',\n shouldFocusError = true,\n}: UseSplitPaymentsFormProps): HookLoadingResult | UseSplitPaymentsFormReady {\n const paymentMethodQuery = useEmployeePaymentMethodGet({ employeeId })\n const bankAccountsQuery = useEmployeePaymentMethodsGetBankAccounts({ employeeId })\n\n const paymentMethod = paymentMethodQuery.data?.employeePaymentMethod\n const bankAccounts = bankAccountsQuery.data?.employeeBankAccounts\n\n const splits = useMemo<WorkingSplit[]>(\n () => (paymentMethod && bankAccounts ? buildWorkingSplits(paymentMethod, bankAccounts) : []),\n [paymentMethod, bankAccounts],\n )\n\n const [schema, metadataConfig] = useMemo(\n () => createSplitPaymentsFormSchema({ optionalFieldsToRequire }),\n [optionalFieldsToRequire],\n )\n\n const resolvedDefaults: SplitPaymentsFormData = useMemo(() => {\n const isAmountSplit = paymentMethod?.splitBy === SPLIT_BY.amount\n const splitAmount: Record<string, number | null> = {}\n const priority: Record<string, number> = {}\n splits.forEach(split => {\n splitAmount[split.uuid] = isAmountSplit\n ? centsToDollars(split.splitAmount)\n : split.splitAmount\n priority[split.uuid] = split.priority\n })\n return {\n splitBy: (paymentMethod?.splitBy ?? SPLIT_BY.percentage) as SplitByValue,\n splitAmount,\n priority,\n }\n }, [paymentMethod, splits])\n\n const formMethods = useForm<SplitPaymentsFormData, unknown, SplitPaymentsFormOutputs>({\n resolver: zodResolver(schema),\n mode: validationMode,\n shouldFocusError,\n defaultValues: resolvedDefaults,\n values: resolvedDefaults,\n resetOptions: { keepDirtyValues: true },\n })\n\n const updateMutation = useEmployeePaymentMethodUpdateMutation()\n const isPending = updateMutation.isPending\n\n const {\n baseSubmitHandler,\n error: submitError,\n setError: setSubmitError,\n } = useBaseSubmit('SplitPaymentsForm')\n\n const errorHandling = composeErrorHandler([paymentMethodQuery, bankAccountsQuery], {\n submitError,\n setSubmitError,\n })\n\n const watchedSplitBy = useWatch({ control: formMethods.control, name: 'splitBy' })\n const watchedPriority = useWatch({ control: formMethods.control, name: 'priority' })\n const watchedSplitAmount = useWatch({ control: formMethods.control, name: 'splitAmount' })\n\n const percentageTotal = useMemo(() => {\n if (watchedSplitBy !== SPLIT_BY.percentage) return 0\n return Object.values(watchedSplitAmount).reduce<number>(\n (acc, v) => acc + (typeof v === 'number' && Number.isFinite(v) ? v : 0),\n 0,\n )\n }, [watchedSplitBy, watchedSplitAmount])\n\n // Subscribe to the schema-emitted imbalance error. The schema places it at\n // a synthetic path (`PERCENTAGE_TOTAL_PATH`) so it does not collide with\n // per-uuid `splitAmount.<uuid>` errors. Following the standard validation\n // lifecycle means `validationMode` (onSubmit / onChange / onBlur / ...)\n // controls when the alert can appear. We subscribe to the full errors map\n // because `name` only tracks registered field paths and our synthetic key\n // is not a registered field. The derivation is also gated on Percentage\n // mode so a stale error from a prior Percentage submit can't leak into\n // Amount mode after a toggle.\n const { errors: validationErrors, isSubmitted } = useFormState({\n control: formMethods.control,\n })\n const hasPercentageImbalance =\n watchedSplitBy === SPLIT_BY.percentage &&\n (validationErrors as Record<string, { message?: string } | undefined>)[PERCENTAGE_TOTAL_PATH]\n ?.message === SplitPaymentsFormErrorCodes.PERCENTAGE_TOTAL_MISMATCH\n\n // Re-sync the synthetic PERCENTAGE_TOTAL_PATH error whenever any\n // `splitAmount` value changes (in Percentage mode, after the first\n // submit attempt). RHF's per-field reValidate after a failed submit\n // scopes the resolver merge to the changed field's name, so an error\n // at our form-level synthetic path is otherwise left stuck once the\n // user has typed the total back to 100. Targeting the synthetic name\n // re-runs the resolver and lets RHF set/unset that single path through\n // its normal merge — preserving per-field error lifecycles unchanged.\n const { trigger } = formMethods\n useEffect(() => {\n if (!isSubmitted) return\n if (watchedSplitBy !== SPLIT_BY.percentage) return\n // `trigger`'s type is keyed to registered field paths, but the\n // synthetic `percentageTotal` resolves through RHF's get/set/unset\n // helpers at runtime — cast at the boundary to keep the contract\n // honest above.\n void trigger(PERCENTAGE_TOTAL_PATH as Parameters<typeof trigger>[0])\n }, [isSubmitted, watchedSplitBy, watchedSplitAmount, trigger])\n\n const remainderId = useMemo(() => {\n if (!Object.keys(watchedPriority).length) return ''\n return Object.entries(watchedPriority).reduce((maxId, [uuid, priority]) => {\n if (!maxId) return uuid\n const currentMax = watchedPriority[maxId] ?? 0\n return priority > currentMax ? uuid : maxId\n }, '')\n }, [watchedPriority])\n\n // Reset splitAmount values when the user toggles splitBy. Skip the first\n // post-load run so values loaded from `paymentMethod.splits` are preserved\n // on mount — only the user's explicit toggle should clear them.\n const splitsRef = useRef(splits)\n splitsRef.current = splits\n const remainderIdRef = useRef(remainderId)\n remainderIdRef.current = remainderId\n const previousSplitByRef = useRef<SplitByValue | null>(null)\n const { setValue, resetField } = formMethods\n\n useEffect(() => {\n if (!splitsRef.current.length) return\n if (previousSplitByRef.current === null) {\n previousSplitByRef.current = watchedSplitBy as SplitByValue\n return\n }\n if (previousSplitByRef.current === watchedSplitBy) return\n previousSplitByRef.current = watchedSplitBy as SplitByValue\n\n if (watchedSplitBy === SPLIT_BY.amount) {\n const newValues = splitsRef.current.reduce<Record<string, number | null>>((acc, curr) => {\n acc[curr.uuid] = curr.uuid === remainderIdRef.current ? null : 0\n return acc\n }, {})\n setValue('splitAmount', newValues)\n } else {\n const newValues = splitsRef.current.reduce<Record<string, number | null>>(\n (acc, curr, index) => {\n acc[curr.uuid] = index === 0 ? 100 : 0\n return acc\n },\n {},\n )\n setValue('splitAmount', newValues)\n }\n }, [watchedSplitBy, setValue])\n\n const reorderSplits = useCallback(\n (orderedUuids: string[]) => {\n const currentSplits = splitsRef.current\n const knownUuids = new Set(currentSplits.map(s => s.uuid))\n if (\n orderedUuids.length !== knownUuids.size ||\n !orderedUuids.every(uuid => knownUuids.has(uuid))\n ) {\n return\n }\n\n const newPriorities = orderedUuids.reduce<Record<string, number>>((acc, uuid, index) => {\n acc[uuid] = index + 1\n return acc\n }, {})\n const newRemainderId = orderedUuids[orderedUuids.length - 1]\n if (!newRemainderId) return\n\n setValue('priority', newPriorities)\n const previousRemainder = remainderIdRef.current\n if (previousRemainder && previousRemainder !== newRemainderId) {\n resetField(`splitAmount.${previousRemainder}`)\n setValue(`splitAmount.${previousRemainder}`, 0)\n }\n setValue(`splitAmount.${newRemainderId}`, null)\n },\n [setValue, resetField],\n )\n\n const splitByOptions = SPLIT_BY_VALUES.map(value => ({ value, label: value }))\n const baseMetadata = useDeriveFieldsMetadata(metadataConfig, formMethods.control)\n const dynamicSplitMetadata = useMemo<FieldsMetadata>(() => {\n const entries: FieldsMetadata = {}\n const isAmountSplit = watchedSplitBy === SPLIT_BY.amount\n for (const split of splits) {\n const path = `splitAmount.${split.uuid}`\n const isRemainder = isAmountSplit && split.uuid === remainderId\n // Every split — including the remainder — is \"required\" from the\n // user's perspective: the remainder always carries a value at submit\n // (the API absorbs leftover). The form-state `null` is a modeling\n // detail, not a UX choice, so we don't surface it as \"(optional)\" on\n // the label. `isDisabled` already conveys the non-interactivity.\n entries[path] = {\n name: path,\n isRequired: true,\n isDisabled: isRemainder,\n }\n }\n return entries\n }, [splits, watchedSplitBy, remainderId])\n const fieldsMetadata: FieldsMetadata = {\n splitBy: withOptions<SplitByValue>(baseMetadata.splitBy, splitByOptions, [...SPLIT_BY_VALUES]),\n splitAmount: baseMetadata.splitAmount,\n priority: baseMetadata.priority,\n ...dynamicSplitMetadata,\n }\n\n const splitFieldEntries = useMemo(\n () =>\n buildSplitFieldEntries(\n splits.map(s => ({\n uuid: s.uuid,\n name: s.name,\n hiddenAccountNumber: s.hiddenAccountNumber,\n })),\n ),\n [splits],\n )\n\n const onSubmit = async (): Promise<HookSubmitResult<EmployeePaymentMethod> | undefined> => {\n if (!paymentMethod) {\n throw new SDKInternalError('Cannot submit split payments form before data is loaded')\n }\n const currentPaymentMethod = paymentMethod\n const currentSplits = splits\n let submitResult: HookSubmitResult<EmployeePaymentMethod> | undefined\n\n await new Promise<void>(resolve => {\n void formMethods.handleSubmit(\n async (data: SplitPaymentsFormOutputs) => {\n await baseSubmitHandler(data, async payload => {\n const isAmountSplit = payload.splitBy === SPLIT_BY.amount\n const body = {\n ...currentPaymentMethod,\n version: currentPaymentMethod.version as string,\n splitBy: payload.splitBy,\n splits: currentSplits.map(split => {\n const splitAmountValue = payload.splitAmount[split.uuid] ?? null\n return {\n uuid: split.uuid,\n name: split.name ?? undefined,\n hiddenAccountNumber: split.hiddenAccountNumber ?? undefined,\n splitAmount: isAmountSplit ? dollarsToCents(splitAmountValue) : splitAmountValue,\n priority: payload.priority[split.uuid],\n }\n }),\n }\n\n const response = await updateMutation.mutateAsync({\n request: {\n employeeId,\n requestBody: { ...body, type: PAYMENT_METHODS.directDeposit },\n },\n })\n\n if (!response.employeePaymentMethod) {\n throw new SDKInternalError('Payment method update failed')\n }\n\n submitResult = { mode: 'update' as const, data: response.employeePaymentMethod }\n })\n resolve()\n },\n () => {\n resolve()\n },\n )()\n })\n\n return submitResult\n }\n\n const hookFormInternals = useHookFormInternals(formMethods)\n\n if (\n paymentMethodQuery.isLoading ||\n bankAccountsQuery.isLoading ||\n !paymentMethod ||\n !bankAccounts\n ) {\n return { isLoading: true as const, errorHandling }\n }\n\n return {\n isLoading: false as const,\n data: {\n paymentMethod,\n bankAccounts,\n splits,\n remainderId,\n },\n status: {\n isPending,\n mode: 'update' as const,\n splitBy: watchedSplitBy as SplitByValue,\n percentageTotal,\n hasPercentageImbalance,\n },\n actions: { onSubmit, reorderSplits },\n errorHandling,\n form: {\n Fields: { SplitBy: SplitByField, splits: splitFieldEntries },\n fieldsMetadata,\n hookFormInternals,\n getFormSubmissionValues: createGetFormSubmissionValues(formMethods, schema),\n },\n }\n}\n\n/**\n * Return type of {@link useSplitPaymentsForm} — a discriminated union on `isLoading`.\n *\n * @public\n */\nexport type UseSplitPaymentsFormResult = HookLoadingResult | UseSplitPaymentsFormReady\n\n/**\n * Per-field metadata exposed on `form.fieldsMetadata` for {@link useSplitPaymentsForm}.\n *\n * @public\n */\nexport type SplitPaymentsFormFieldsMetadata = UseSplitPaymentsFormReady['form']['fieldsMetadata']\n"],"names":["buildWorkingSplits","paymentMethod","bankAccounts","split","account","index","useSplitPaymentsForm","employeeId","optionalFieldsToRequire","validationMode","shouldFocusError","paymentMethodQuery","useEmployeePaymentMethodGet","bankAccountsQuery","useEmployeePaymentMethodsGetBankAccounts","splits","useMemo","schema","metadataConfig","createSplitPaymentsFormSchema","resolvedDefaults","isAmountSplit","SPLIT_BY","splitAmount","priority","centsToDollars","formMethods","useForm","zodResolver","updateMutation","useEmployeePaymentMethodUpdateMutation","isPending","baseSubmitHandler","submitError","setSubmitError","useBaseSubmit","errorHandling","composeErrorHandler","watchedSplitBy","useWatch","watchedPriority","watchedSplitAmount","percentageTotal","acc","v","validationErrors","isSubmitted","useFormState","hasPercentageImbalance","PERCENTAGE_TOTAL_PATH","SplitPaymentsFormErrorCodes","trigger","useEffect","remainderId","maxId","uuid","currentMax","splitsRef","useRef","remainderIdRef","previousSplitByRef","setValue","resetField","newValues","curr","reorderSplits","useCallback","orderedUuids","currentSplits","knownUuids","s","newPriorities","newRemainderId","previousRemainder","splitByOptions","SPLIT_BY_VALUES","value","baseMetadata","useDeriveFieldsMetadata","dynamicSplitMetadata","entries","path","isRemainder","fieldsMetadata","withOptions","splitFieldEntries","buildSplitFieldEntries","onSubmit","SDKInternalError","currentPaymentMethod","submitResult","resolve","data","payload","body","splitAmountValue","dollarsToCents","response","PAYMENT_METHODS","hookFormInternals","useHookFormInternals","SplitByField","createGetFormSubmissionValues"],"mappings":"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"}
1
+ {"version":3,"file":"useSplitPaymentsForm.js","sources":["../../../../../../src/components/Employee/PaymentMethod/shared/useSplitPaymentsForm/useSplitPaymentsForm.tsx"],"sourcesContent":["import type { ComponentType } from 'react'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport { useForm, useFormState, useWatch } from 'react-hook-form'\nimport type { UseFormProps } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport type { EmployeeBankAccount } from '@gusto/embedded-api-v-2025-11-15/models/components/employeebankaccount'\nimport type { EmployeePaymentMethod } from '@gusto/embedded-api-v-2025-11-15/models/components/employeepaymentmethod'\nimport { useEmployeePaymentMethodGet } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodGet'\nimport { useEmployeePaymentMethodsGetBankAccounts } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodsGetBankAccounts'\nimport { useEmployeePaymentMethodUpdateMutation } from '@gusto/embedded-api-v-2025-11-15/react-query/employeePaymentMethodUpdate'\nimport {\n PERCENTAGE_TOTAL_PATH,\n SPLIT_BY_VALUES,\n SplitPaymentsFormErrorCodes,\n type SplitByValue,\n type SplitPaymentsFormData,\n type SplitPaymentsFormOptionalFieldsToRequire,\n type SplitPaymentsFormOutputs,\n createSplitPaymentsFormSchema,\n} from './useSplitPaymentsFormSchema'\nimport { SplitByField, type SplitByFieldProps } from './fields'\nimport { buildSplitFieldEntries, type SplitFieldEntry } from './splitFieldFactory'\nimport { useDeriveFieldsMetadata } from '@/partner-hook-utils/form/useDeriveFieldsMetadata'\nimport { useHookFormInternals } from '@/partner-hook-utils/form/useHookFormInternals'\nimport { createGetFormSubmissionValues } from '@/partner-hook-utils/form/getFormSubmissionValues'\nimport { withOptions } from '@/partner-hook-utils/form/withOptions'\nimport { composeErrorHandler } from '@/partner-hook-utils/composeErrorHandler'\nimport type {\n BaseFormHookReady,\n FieldsMetadata,\n HookLoadingResult,\n HookSubmitResult,\n} from '@/partner-hook-utils/types'\nimport { useBaseSubmit } from '@/components/Base/useBaseSubmit'\nimport { SDKInternalError } from '@/types/sdkError'\nimport { centsToDollars, dollarsToCents } from '@/helpers/currencyHelpers'\nimport { PAYMENT_METHODS, SPLIT_BY } from '@/shared/constants'\n\n/**\n * A single split entry — pairs a bank account identifier with its current split allocation.\n *\n * @remarks\n * Surfaced on `data.splits` from {@link useSplitPaymentsForm}. Derived from\n * `paymentMethod.splits` when present, otherwise from the employee's bank\n * accounts (one entry per account, no allocated amount). Carries the raw\n * domain data — use it for label construction or lookups by uuid.\n *\n * @public\n */\nexport interface WorkingSplit {\n /** UUID of the underlying bank account. */\n uuid: string\n /** Account nickname, when available. */\n name: string | null\n /** Masked account number suffix, when available. */\n hiddenAccountNumber: string | null\n /** Allocation amount — `null` for the remainder split in Amount mode and for splits that haven't been allocated yet. */\n splitAmount: number | null\n /** Ordering value — splits are processed in ascending priority; the highest priority is the remainder. */\n priority: number\n}\n\n/**\n * Props for {@link useSplitPaymentsForm}.\n *\n * @public\n */\nexport interface UseSplitPaymentsFormProps {\n /** Employee whose payment splits are being edited. */\n employeeId: string\n /** Override optional fields to be required. Currently a no-op — `splitBy` and `priority` are always required, and per-split `splitAmount` required-ness is automatic. */\n optionalFieldsToRequire?: SplitPaymentsFormOptionalFieldsToRequire\n /** When validation runs. Passed through to react-hook-form. Defaults to `'onSubmit'`. */\n validationMode?: UseFormProps['mode']\n /** Auto-focus the first invalid field on submit. Set to `false` when using `composeSubmitHandler`. Defaults to `true`. */\n shouldFocusError?: boolean\n}\n\n/**\n * Field components exposed by {@link useSplitPaymentsForm} on `form.Fields`.\n *\n * @public\n */\nexport interface SplitPaymentsFormFields {\n /** Radio group bound to `splitBy`; selects Percentage or Amount split mode. */\n SplitBy: ComponentType<SplitByFieldProps>\n /** One entry per bank account, each carrying a pre-bound `Field` component for the per-split amount. */\n splits: SplitFieldEntry[]\n}\n\n/**\n * Ready-state return value of {@link useSplitPaymentsForm}.\n *\n * @public\n */\nexport interface UseSplitPaymentsFormReady extends BaseFormHookReady<\n FieldsMetadata,\n SplitPaymentsFormData,\n SplitPaymentsFormFields\n> {\n /** Server-fetched data and derived working values. */\n data: {\n /** The employee's current payment method. */\n paymentMethod: EmployeePaymentMethod\n /** All bank accounts available to allocate splits across. */\n bankAccounts: EmployeeBankAccount[]\n /** The current working split entries, one per bank account. */\n splits: WorkingSplit[]\n /** UUID of the split that absorbs the remainder in Amount mode (always the last by priority). */\n remainderId: string\n }\n /** Submission state and reactive form-level flags. */\n status: {\n /** `true` while the update mutation is in flight. */\n isPending: boolean\n /** Always `'update'` — the hook always edits an existing payment method. */\n mode: 'update'\n /** Current `splitBy` value, reactively tracked. */\n splitBy: SplitByValue\n /** Live sum of `splitAmount` values; useful for displaying the current total in Percentage mode. */\n percentageTotal: number\n /**\n * `true` after a failed Percentage-mode Save when the splits don't sum to\n * 100; clears live as the user corrects the total. Follows the standard\n * react-hook-form validation lifecycle (controlled by `validationMode`).\n * Only surfaces in Percentage mode.\n */\n hasPercentageImbalance: boolean\n }\n /** Actions that mutate the form or submit it. */\n actions: {\n /** Submit the form. Returns the updated payment method on success or `undefined` on validation/mutation failure. */\n onSubmit: () => Promise<HookSubmitResult<EmployeePaymentMethod> | undefined>\n /**\n * Reorder splits by uuid (Amount mode). Pass the ordered list of split\n * uuids; the last uuid becomes the remainder. The hook writes the new\n * priority map and re-anchors the remainder's `splitAmount` to `null`\n * (clearing the previous remainder to `0`).\n */\n reorderSplits: (orderedUuids: string[]) => void\n }\n}\n\nconst buildWorkingSplits = (\n paymentMethod: EmployeePaymentMethod,\n bankAccounts: EmployeeBankAccount[],\n): WorkingSplit[] => {\n if (paymentMethod.splits && paymentMethod.splits.length > 0) {\n return paymentMethod.splits.map(split => ({\n uuid: split.uuid,\n name: split.name ?? null,\n hiddenAccountNumber: split.hiddenAccountNumber ?? null,\n splitAmount: split.splitAmount ?? null,\n priority: split.priority ?? 0,\n }))\n }\n return bankAccounts.map((account, index) => ({\n uuid: account.uuid,\n name: account.name ?? null,\n hiddenAccountNumber: account.hiddenAccountNumber ?? null,\n splitAmount: null,\n priority: index + 1,\n }))\n}\n\n/**\n * Headless React Hook Form hook for splitting an employee's Direct Deposit across multiple bank accounts.\n *\n * @remarks\n * Supports two split modes: Percentage (whole-number shares that sum to 100)\n * and Amount (dollar amounts, with the last-priority split absorbing the\n * remainder). Always operates in update mode against the employee's existing\n * payment method.\n *\n * The Percentage sum-to-100 invariant is surfaced via\n * `status.hasPercentageImbalance` (not as a per-field error). With the default\n * `validationMode: 'onSubmit'`, the imbalance flag appears after the first\n * failed Save and clears live as the user corrects the total.\n *\n * @param props - See {@link UseSplitPaymentsFormProps}.\n * @returns A loading-state result while the payment method and bank accounts are loading, or a {@link UseSplitPaymentsFormReady} once ready.\n * @public\n *\n * @example\n * ```tsx\n * import {\n * useSplitPaymentsForm,\n * SDKFormProvider,\n * type SplitByValue,\n * type UseSplitPaymentsFormReady,\n * } from '@gusto/embedded-react-sdk'\n *\n * function SplitPaycheckScreen({ employeeId }: { employeeId: string }) {\n * const splitForm = useSplitPaymentsForm({ employeeId })\n *\n * if (splitForm.isLoading) return null\n * return <SplitPaycheckReady splitForm={splitForm} />\n * }\n *\n * function SplitPaycheckReady({ splitForm }: { splitForm: UseSplitPaymentsFormReady }) {\n * const { Fields } = splitForm.form\n * const { hasPercentageImbalance, percentageTotal } = splitForm.status\n *\n * return (\n * <SDKFormProvider formHookResult={splitForm}>\n * <form\n * onSubmit={e => {\n * e.preventDefault()\n * void splitForm.actions.onSubmit()\n * }}\n * >\n * {hasPercentageImbalance && (\n * <div role=\"alert\">Splits must total 100%. Currently {percentageTotal}%.</div>\n * )}\n * <Fields.SplitBy label=\"Split by\" getOptionLabel={(value: SplitByValue) => value} />\n * {Fields.splits.map(split => (\n * <split.Field\n * key={split.uuid}\n * label={split.name ?? 'Account'}\n * min={0}\n * />\n * ))}\n * <button type=\"submit\" disabled={splitForm.status.isPending}>Save</button>\n * </form>\n * </SDKFormProvider>\n * )\n * }\n * ```\n */\nexport function useSplitPaymentsForm({\n employeeId,\n optionalFieldsToRequire,\n validationMode = 'onSubmit',\n shouldFocusError = true,\n}: UseSplitPaymentsFormProps): UseSplitPaymentsFormResult {\n const paymentMethodQuery = useEmployeePaymentMethodGet({ employeeId })\n const bankAccountsQuery = useEmployeePaymentMethodsGetBankAccounts({ employeeId })\n\n const paymentMethod = paymentMethodQuery.data?.employeePaymentMethod\n const bankAccounts = bankAccountsQuery.data?.employeeBankAccounts\n\n const splits = useMemo<WorkingSplit[]>(\n () => (paymentMethod && bankAccounts ? buildWorkingSplits(paymentMethod, bankAccounts) : []),\n [paymentMethod, bankAccounts],\n )\n\n const [schema, metadataConfig] = useMemo(\n () => createSplitPaymentsFormSchema({ optionalFieldsToRequire }),\n [optionalFieldsToRequire],\n )\n\n const resolvedDefaults: SplitPaymentsFormData = useMemo(() => {\n const isAmountSplit = paymentMethod?.splitBy === SPLIT_BY.amount\n const splitAmount: Record<string, number | null> = {}\n const priority: Record<string, number> = {}\n splits.forEach(split => {\n splitAmount[split.uuid] = isAmountSplit\n ? centsToDollars(split.splitAmount)\n : split.splitAmount\n priority[split.uuid] = split.priority\n })\n return {\n splitBy: (paymentMethod?.splitBy ?? SPLIT_BY.percentage) as SplitByValue,\n splitAmount,\n priority,\n }\n }, [paymentMethod, splits])\n\n const formMethods = useForm<SplitPaymentsFormData, unknown, SplitPaymentsFormOutputs>({\n resolver: zodResolver(schema),\n mode: validationMode,\n shouldFocusError,\n defaultValues: resolvedDefaults,\n values: resolvedDefaults,\n resetOptions: { keepDirtyValues: true },\n })\n\n const updateMutation = useEmployeePaymentMethodUpdateMutation()\n const isPending = updateMutation.isPending\n\n const {\n baseSubmitHandler,\n error: submitError,\n setError: setSubmitError,\n } = useBaseSubmit('SplitPaymentsForm')\n\n const errorHandling = composeErrorHandler([paymentMethodQuery, bankAccountsQuery], {\n submitError,\n setSubmitError,\n })\n\n const watchedSplitBy = useWatch({ control: formMethods.control, name: 'splitBy' })\n const watchedPriority = useWatch({ control: formMethods.control, name: 'priority' })\n const watchedSplitAmount = useWatch({ control: formMethods.control, name: 'splitAmount' })\n\n const percentageTotal = useMemo(() => {\n if (watchedSplitBy !== SPLIT_BY.percentage) return 0\n return Object.values(watchedSplitAmount).reduce<number>(\n (acc, v) => acc + (typeof v === 'number' && Number.isFinite(v) ? v : 0),\n 0,\n )\n }, [watchedSplitBy, watchedSplitAmount])\n\n // Subscribe to the schema-emitted imbalance error. The schema places it at\n // a synthetic path (`PERCENTAGE_TOTAL_PATH`) so it does not collide with\n // per-uuid `splitAmount.<uuid>` errors. Following the standard validation\n // lifecycle means `validationMode` (onSubmit / onChange / onBlur / ...)\n // controls when the alert can appear. We subscribe to the full errors map\n // because `name` only tracks registered field paths and our synthetic key\n // is not a registered field. The derivation is also gated on Percentage\n // mode so a stale error from a prior Percentage submit can't leak into\n // Amount mode after a toggle.\n const { errors: validationErrors, isSubmitted } = useFormState({\n control: formMethods.control,\n })\n const hasPercentageImbalance =\n watchedSplitBy === SPLIT_BY.percentage &&\n (validationErrors as Record<string, { message?: string } | undefined>)[PERCENTAGE_TOTAL_PATH]\n ?.message === SplitPaymentsFormErrorCodes.PERCENTAGE_TOTAL_MISMATCH\n\n // Re-sync the synthetic PERCENTAGE_TOTAL_PATH error whenever any\n // `splitAmount` value changes (in Percentage mode, after the first\n // submit attempt). RHF's per-field reValidate after a failed submit\n // scopes the resolver merge to the changed field's name, so an error\n // at our form-level synthetic path is otherwise left stuck once the\n // user has typed the total back to 100. Targeting the synthetic name\n // re-runs the resolver and lets RHF set/unset that single path through\n // its normal merge — preserving per-field error lifecycles unchanged.\n const { trigger } = formMethods\n useEffect(() => {\n if (!isSubmitted) return\n if (watchedSplitBy !== SPLIT_BY.percentage) return\n // `trigger`'s type is keyed to registered field paths, but the\n // synthetic `percentageTotal` resolves through RHF's get/set/unset\n // helpers at runtime — cast at the boundary to keep the contract\n // honest above.\n void trigger(PERCENTAGE_TOTAL_PATH as Parameters<typeof trigger>[0])\n }, [isSubmitted, watchedSplitBy, watchedSplitAmount, trigger])\n\n const remainderId = useMemo(() => {\n if (!Object.keys(watchedPriority).length) return ''\n return Object.entries(watchedPriority).reduce((maxId, [uuid, priority]) => {\n if (!maxId) return uuid\n const currentMax = watchedPriority[maxId] ?? 0\n return priority > currentMax ? uuid : maxId\n }, '')\n }, [watchedPriority])\n\n // Reset splitAmount values when the user toggles splitBy. Skip the first\n // post-load run so values loaded from `paymentMethod.splits` are preserved\n // on mount — only the user's explicit toggle should clear them.\n const splitsRef = useRef(splits)\n splitsRef.current = splits\n const remainderIdRef = useRef(remainderId)\n remainderIdRef.current = remainderId\n const previousSplitByRef = useRef<SplitByValue | null>(null)\n const { setValue, resetField } = formMethods\n\n useEffect(() => {\n if (!splitsRef.current.length) return\n if (previousSplitByRef.current === null) {\n previousSplitByRef.current = watchedSplitBy as SplitByValue\n return\n }\n if (previousSplitByRef.current === watchedSplitBy) return\n previousSplitByRef.current = watchedSplitBy as SplitByValue\n\n if (watchedSplitBy === SPLIT_BY.amount) {\n const newValues = splitsRef.current.reduce<Record<string, number | null>>((acc, curr) => {\n acc[curr.uuid] = curr.uuid === remainderIdRef.current ? null : 0\n return acc\n }, {})\n setValue('splitAmount', newValues)\n } else {\n const newValues = splitsRef.current.reduce<Record<string, number | null>>(\n (acc, curr, index) => {\n acc[curr.uuid] = index === 0 ? 100 : 0\n return acc\n },\n {},\n )\n setValue('splitAmount', newValues)\n }\n }, [watchedSplitBy, setValue])\n\n const reorderSplits = useCallback(\n (orderedUuids: string[]) => {\n const currentSplits = splitsRef.current\n const knownUuids = new Set(currentSplits.map(s => s.uuid))\n if (\n orderedUuids.length !== knownUuids.size ||\n !orderedUuids.every(uuid => knownUuids.has(uuid))\n ) {\n return\n }\n\n const newPriorities = orderedUuids.reduce<Record<string, number>>((acc, uuid, index) => {\n acc[uuid] = index + 1\n return acc\n }, {})\n const newRemainderId = orderedUuids[orderedUuids.length - 1]\n if (!newRemainderId) return\n\n setValue('priority', newPriorities)\n const previousRemainder = remainderIdRef.current\n if (previousRemainder && previousRemainder !== newRemainderId) {\n resetField(`splitAmount.${previousRemainder}`)\n setValue(`splitAmount.${previousRemainder}`, 0)\n }\n setValue(`splitAmount.${newRemainderId}`, null)\n },\n [setValue, resetField],\n )\n\n const splitByOptions = SPLIT_BY_VALUES.map(value => ({ value, label: value }))\n const baseMetadata = useDeriveFieldsMetadata(metadataConfig, formMethods.control)\n const dynamicSplitMetadata = useMemo<FieldsMetadata>(() => {\n const entries: FieldsMetadata = {}\n const isAmountSplit = watchedSplitBy === SPLIT_BY.amount\n for (const split of splits) {\n const path = `splitAmount.${split.uuid}`\n const isRemainder = isAmountSplit && split.uuid === remainderId\n // Every split — including the remainder — is \"required\" from the\n // user's perspective: the remainder always carries a value at submit\n // (the API absorbs leftover). The form-state `null` is a modeling\n // detail, not a UX choice, so we don't surface it as \"(optional)\" on\n // the label. `isDisabled` already conveys the non-interactivity.\n entries[path] = {\n name: path,\n isRequired: true,\n isDisabled: isRemainder,\n }\n }\n return entries\n }, [splits, watchedSplitBy, remainderId])\n const fieldsMetadata: FieldsMetadata = {\n splitBy: withOptions<SplitByValue>(baseMetadata.splitBy, splitByOptions, [...SPLIT_BY_VALUES]),\n splitAmount: baseMetadata.splitAmount,\n priority: baseMetadata.priority,\n ...dynamicSplitMetadata,\n }\n\n const splitFieldEntries = useMemo(\n () =>\n buildSplitFieldEntries(\n splits.map(s => ({\n uuid: s.uuid,\n name: s.name,\n hiddenAccountNumber: s.hiddenAccountNumber,\n })),\n ),\n [splits],\n )\n\n const onSubmit = async (): Promise<HookSubmitResult<EmployeePaymentMethod> | undefined> => {\n if (!paymentMethod) {\n throw new SDKInternalError('Cannot submit split payments form before data is loaded')\n }\n const currentPaymentMethod = paymentMethod\n const currentSplits = splits\n let submitResult: HookSubmitResult<EmployeePaymentMethod> | undefined\n\n await new Promise<void>(resolve => {\n void formMethods.handleSubmit(\n async (data: SplitPaymentsFormOutputs) => {\n await baseSubmitHandler(data, async payload => {\n const isAmountSplit = payload.splitBy === SPLIT_BY.amount\n const body = {\n ...currentPaymentMethod,\n version: currentPaymentMethod.version as string,\n splitBy: payload.splitBy,\n splits: currentSplits.map(split => {\n const splitAmountValue = payload.splitAmount[split.uuid] ?? null\n return {\n uuid: split.uuid,\n name: split.name ?? undefined,\n hiddenAccountNumber: split.hiddenAccountNumber ?? undefined,\n splitAmount: isAmountSplit ? dollarsToCents(splitAmountValue) : splitAmountValue,\n priority: payload.priority[split.uuid],\n }\n }),\n }\n\n const response = await updateMutation.mutateAsync({\n request: {\n employeeId,\n requestBody: { ...body, type: PAYMENT_METHODS.directDeposit },\n },\n })\n\n if (!response.employeePaymentMethod) {\n throw new SDKInternalError('Payment method update failed')\n }\n\n submitResult = { mode: 'update' as const, data: response.employeePaymentMethod }\n })\n resolve()\n },\n () => {\n resolve()\n },\n )()\n })\n\n return submitResult\n }\n\n const hookFormInternals = useHookFormInternals(formMethods)\n\n if (\n paymentMethodQuery.isLoading ||\n bankAccountsQuery.isLoading ||\n !paymentMethod ||\n !bankAccounts\n ) {\n return { isLoading: true as const, errorHandling }\n }\n\n return {\n isLoading: false as const,\n data: {\n paymentMethod,\n bankAccounts,\n splits,\n remainderId,\n },\n status: {\n isPending,\n mode: 'update' as const,\n splitBy: watchedSplitBy as SplitByValue,\n percentageTotal,\n hasPercentageImbalance,\n },\n actions: { onSubmit, reorderSplits },\n errorHandling,\n form: {\n Fields: { SplitBy: SplitByField, splits: splitFieldEntries },\n fieldsMetadata,\n hookFormInternals,\n getFormSubmissionValues: createGetFormSubmissionValues(formMethods, schema),\n },\n }\n}\n\n/**\n * Return type of {@link useSplitPaymentsForm} — a discriminated union on `isLoading`.\n *\n * @public\n */\nexport type UseSplitPaymentsFormResult = HookLoadingResult | UseSplitPaymentsFormReady\n\n/**\n * Per-field metadata exposed on `form.fieldsMetadata` for {@link useSplitPaymentsForm}.\n *\n * @public\n */\nexport type SplitPaymentsFormFieldsMetadata = UseSplitPaymentsFormReady['form']['fieldsMetadata']\n"],"names":["buildWorkingSplits","paymentMethod","bankAccounts","split","account","index","useSplitPaymentsForm","employeeId","optionalFieldsToRequire","validationMode","shouldFocusError","paymentMethodQuery","useEmployeePaymentMethodGet","bankAccountsQuery","useEmployeePaymentMethodsGetBankAccounts","splits","useMemo","schema","metadataConfig","createSplitPaymentsFormSchema","resolvedDefaults","isAmountSplit","SPLIT_BY","splitAmount","priority","centsToDollars","formMethods","useForm","zodResolver","updateMutation","useEmployeePaymentMethodUpdateMutation","isPending","baseSubmitHandler","submitError","setSubmitError","useBaseSubmit","errorHandling","composeErrorHandler","watchedSplitBy","useWatch","watchedPriority","watchedSplitAmount","percentageTotal","acc","v","validationErrors","isSubmitted","useFormState","hasPercentageImbalance","PERCENTAGE_TOTAL_PATH","SplitPaymentsFormErrorCodes","trigger","useEffect","remainderId","maxId","uuid","currentMax","splitsRef","useRef","remainderIdRef","previousSplitByRef","setValue","resetField","newValues","curr","reorderSplits","useCallback","orderedUuids","currentSplits","knownUuids","s","newPriorities","newRemainderId","previousRemainder","splitByOptions","SPLIT_BY_VALUES","value","baseMetadata","useDeriveFieldsMetadata","dynamicSplitMetadata","entries","path","isRemainder","fieldsMetadata","withOptions","splitFieldEntries","buildSplitFieldEntries","onSubmit","SDKInternalError","currentPaymentMethod","submitResult","resolve","data","payload","body","splitAmountValue","dollarsToCents","response","PAYMENT_METHODS","hookFormInternals","useHookFormInternals","SplitByField","createGetFormSubmissionValues"],"mappings":"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"}
@@ -31,6 +31,7 @@ export type EmployeeDetailsField = "email" | "firstName" | "lastName" | "middleI
31
31
  * Shape of the values managed by the employee details form.
32
32
  *
33
33
  * @public
34
+ * @interface
34
35
  */
35
36
  export type EmployeeDetailsFormData = { firstName: string; middleInitial: string; lastName: string; email: string; dateOfBirth: string; ssn: string; selfOnboarding: boolean; };
36
37
  /**