@gusto/embedded-react-sdk 0.56.6 → 0.56.7

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.56.7](https://github.com/Gusto/embedded-react-sdk/compare/v0.56.6...v0.56.7) (2026-10-13)
4
+
5
+ ### Fixes
6
+
7
+ - Fix employees going missing from the payroll configuration screen when the API returns a deduction amount as a decimal string rather than a number. Prepare-payroll failures now surface as errors instead of silently rendering an incomplete employee list ([#2890](https://github.com/Gusto/embedded-react-sdk/issues/2890))
8
+
9
+ ### Chores & Maintenance
10
+
11
+ - Bump `dompurify` to 3.4.16 ([#2888](https://github.com/Gusto/embedded-react-sdk/issues/2888))
12
+ - Bump dev dependencies (`prettier`, `typescript-eslint`, `sass-embedded`, `dotenv`) ([#2852](https://github.com/Gusto/embedded-react-sdk/issues/2852), [#2853](https://github.com/Gusto/embedded-react-sdk/issues/2853), [#2854](https://github.com/Gusto/embedded-react-sdk/issues/2854), [#2855](https://github.com/Gusto/embedded-react-sdk/issues/2855))
13
+ - Bump transitive dependencies for security advisories (`axios`, `brace-expansion`, `markdown-it`, `shell-quote`, `undici`, `qs`, `ip-address`, and others) ([#2857](https://github.com/Gusto/embedded-react-sdk/issues/2857), [#2858](https://github.com/Gusto/embedded-react-sdk/issues/2858), [#2888](https://github.com/Gusto/embedded-react-sdk/issues/2888), [#2889](https://github.com/Gusto/embedded-react-sdk/issues/2889))
14
+
3
15
  ## [0.56.6](https://github.com/Gusto/embedded-react-sdk/compare/v0.56.5...v0.56.6) (2026-10-12)
4
16
 
5
17
  ### Features & Enhancements
@@ -1,50 +1,50 @@
1
- import { useState as R, useRef as q, useMemo as y, useEffect as P, useCallback as L } from "react";
1
+ import { useState as q, useRef as L, useMemo as y, useEffect as P, useCallback as F } from "react";
2
2
  import { useEmployeesList as te } from "@gusto/embedded-api/react-query/employeesList";
3
- import { useQueryClient as se, keepPreviousData as F, useQuery as K } from "@tanstack/react-query";
4
- import { usePaySchedulesGet as oe } from "@gusto/embedded-api/react-query/paySchedulesGet";
3
+ import { useQueryClient as oe, keepPreviousData as K, useQuery as _ } from "@tanstack/react-query";
4
+ import { usePaySchedulesGet as se } from "@gusto/embedded-api/react-query/paySchedulesGet";
5
5
  import { useGustoEmbeddedContext as re } from "@gusto/embedded-api/react-query/_context";
6
6
  import { payrollsPrepare as ae } from "@gusto/embedded-api/funcs/payrollsPrepare";
7
7
  import { employeesGet as ne } from "@gusto/embedded-api/funcs/employeesGet";
8
8
  import { UnprocessableEntityError as ie } from "@gusto/embedded-api/models/errors/unprocessableentityerror";
9
9
  import { derivePayrollCategory as le } from "../payrollTypes.js";
10
10
  import { usePagination as ue } from "../../../hooks/usePagination/usePagination.js";
11
- const f = "payroll-prepare", _ = 300 * 1e3, ce = 3, A = (n) => n instanceof ie ? n.errors.some((s) => s.category === "invalid_operation") : !1;
12
- function we({
11
+ const f = "payroll-prepare", A = 300 * 1e3, ce = 3, S = (n) => n instanceof ie ? n.errors.some((o) => o.category === "invalid_operation") : !1;
12
+ function De({
13
13
  companyId: n,
14
- payrollId: s,
14
+ payrollId: o,
15
15
  disablePrepare: d = !1,
16
- excludedEmployeeUuids: S = [],
16
+ excludedEmployeeUuids: w = [],
17
17
  isTransitionPayroll: Q = !1
18
18
  }) {
19
- const D = re(), i = se(), { currentPage: c, itemsPerPage: T, getPaginationProps: k } = ue({
19
+ const D = re(), i = oe(), { currentPage: c, itemsPerPage: T, getPaginationProps: k } = ue({
20
20
  defaultItemsPerPage: 25
21
- }), [x, M] = R([]), [b, h] = R(!1), g = q(!1), { data: l, isFetching: w } = te(
21
+ }), [x, M] = q([]), [b, h] = q(!1), g = L(!1), { data: l, isFetching: U } = te(
22
22
  {
23
23
  companyId: n,
24
- payrollUuid: s,
24
+ payrollUuid: o,
25
25
  per: T,
26
26
  page: c,
27
27
  sortBy: "name"
28
28
  },
29
- { placeholderData: F }
30
- ), U = q(l);
31
- U.current = l;
29
+ { placeholderData: K, throwOnError: !0 }
30
+ ), C = L(l);
31
+ C.current = l;
32
32
  const p = y(() => l?.showEmployees?.map((e) => e.uuid) || [], [l?.showEmployees]), u = y(() => {
33
33
  const e = new Set(p);
34
- return S.filter((t) => !e.has(t));
35
- }, [S, p]), m = y(() => c === 1 ? [...p, ...u] : p, [p, u, c]), B = y(() => m.join(","), [m]), {
34
+ return w.filter((t) => !e.has(t));
35
+ }, [w, p]), m = y(() => c === 1 ? [...p, ...u] : p, [p, u, c]), B = y(() => m.join(","), [m]), {
36
36
  data: r,
37
37
  error: G,
38
38
  isLoading: j,
39
39
  isFetching: I
40
- } = K({
41
- queryKey: [f, s, B],
40
+ } = _({
41
+ queryKey: [f, o, B],
42
42
  queryFn: async ({ signal: e }) => {
43
43
  const t = await ae(
44
44
  D,
45
45
  {
46
46
  companyId: n,
47
- payrollId: s,
47
+ payrollId: o,
48
48
  sortBy: "last_name",
49
49
  requestBody: {
50
50
  employeeUuids: Q ? void 0 : m
@@ -57,55 +57,56 @@ function we({
57
57
  return t.value.payrollPrepared;
58
58
  },
59
59
  enabled: m.length > 0 && !d,
60
- staleTime: _,
61
- placeholderData: F,
60
+ staleTime: A,
61
+ placeholderData: K,
62
+ throwOnError: (e) => !S(e),
62
63
  // An "already processed" prepare failure is terminal — retrying it wastes time. Other
63
64
  // errors (network blips, etc.) still get the standard retry treatment.
64
- retry: (e, t) => !A(t) && e < ce
65
- }), Y = A(G);
65
+ retry: (e, t) => !S(t) && e < ce
66
+ }), O = S(G);
66
67
  P(() => () => {
67
68
  i.cancelQueries({
68
- queryKey: [f, s]
69
+ queryKey: [f, o]
69
70
  });
70
- }, [i, s]), P(() => {
71
+ }, [i, o]), P(() => {
71
72
  d && i.cancelQueries({
72
- queryKey: [f, s]
73
+ queryKey: [f, o]
73
74
  });
74
- }, [d, i, s]);
75
- const H = y(() => u.join(","), [u]), { data: E } = K({
76
- queryKey: ["excluded-employee-details", H],
75
+ }, [d, i, o]);
76
+ const Y = y(() => u.join(","), [u]), { data: E } = _({
77
+ queryKey: ["excluded-employee-details", Y],
77
78
  queryFn: async () => {
78
79
  const e = await Promise.all(
79
- u.map((o) => ne(D, { employeeId: o }))
80
- ), t = e.find((o) => !o.ok);
80
+ u.map((s) => ne(D, { employeeId: s }))
81
+ ), t = e.find((s) => !s.ok);
81
82
  if (t)
82
83
  throw t.error;
83
- return e.filter((o) => o.ok).map((o) => o.value.employee).filter((o) => o != null);
84
+ return e.filter((s) => s.ok).map((s) => s.value.employee).filter((s) => s != null);
84
85
  },
85
86
  enabled: u.length > 0 && !d,
86
- staleTime: _
87
- }), C = L(() => {
88
- const e = U.current;
87
+ staleTime: A
88
+ }), v = F(() => {
89
+ const e = C.current;
89
90
  if (!e?.showEmployees || !r?.employeeCompensations) {
90
91
  h(!1);
91
92
  return;
92
93
  }
93
- const t = e.showEmployees.map((a) => a.uuid), o = new Set(r.employeeCompensations.map((a) => a.employeeUuid));
94
- if (t.length > 0 && t.every((a) => o.has(a))) {
94
+ const t = e.showEmployees.map((a) => a.uuid), s = new Set(r.employeeCompensations.map((a) => a.employeeUuid));
95
+ if (t.length > 0 && t.every((a) => s.has(a))) {
95
96
  const a = [...e.showEmployees];
96
97
  if (c === 1 && E?.length) {
97
98
  const ee = new Set(t);
98
- for (const v of E)
99
- ee.has(v.uuid) || a.push(v);
99
+ for (const R of E)
100
+ ee.has(R.uuid) || a.push(R);
100
101
  }
101
102
  M(a), h(!0), g.current = !0;
102
103
  } else
103
104
  h(!1);
104
105
  }, [r?.employeeCompensations, E, c]);
105
106
  P(() => {
106
- C();
107
- }, [C]);
108
- const { data: N, isLoading: V } = oe(
107
+ v();
108
+ }, [v]);
109
+ const { data: H, isLoading: N } = se(
109
110
  {
110
111
  companyId: n,
111
112
  payScheduleId: r?.payPeriod?.payScheduleUuid || ""
@@ -113,25 +114,25 @@ function we({
113
114
  {
114
115
  enabled: !!r?.payPeriod?.payScheduleUuid
115
116
  }
116
- ), X = L(async () => {
117
+ ), V = F(async () => {
117
118
  await i.invalidateQueries({
118
- queryKey: [f, s]
119
+ queryKey: [f, o]
119
120
  });
120
- }, [i, s]), z = j && !g.current, J = I && g.current, O = w || J || !b, W = z || V || !l && w, Z = l?.httpMeta.response.headers ?? new Headers(), $ = k(Z, O);
121
+ }, [i, o]), X = j && !g.current, z = I && g.current, J = U || z || !b, W = X || N || !l && U, Z = l?.httpMeta.response.headers ?? new Headers(), $ = k(Z, J);
121
122
  return {
122
123
  employeeCompensations: r?.employeeCompensations ?? [],
123
124
  employeeDetails: x,
124
125
  payPeriod: r?.payPeriod,
125
- paySchedule: N?.payScheduleShow,
126
+ paySchedule: H?.payScheduleShow,
126
127
  payrollCategory: le(r ?? {}),
127
128
  pagination: $,
128
129
  isLoading: W,
129
- isAlreadyProcessed: Y,
130
- refetch: X
130
+ isAlreadyProcessed: O,
131
+ refetch: V
131
132
  };
132
133
  }
133
134
  export {
134
135
  f as PREPARE_QUERY_KEY,
135
- we as usePayrollConfigurationData
136
+ De as usePayrollConfigurationData
136
137
  };
137
138
  //# sourceMappingURL=usePayrollConfigurationData.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"usePayrollConfigurationData.js","sources":["../../../../src/components/Payroll/PayrollConfiguration/usePayrollConfigurationData.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useEmployeesList } from '@gusto/embedded-api/react-query/employeesList'\nimport { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query'\nimport { usePaySchedulesGet } from '@gusto/embedded-api/react-query/paySchedulesGet'\nimport { useGustoEmbeddedContext } from '@gusto/embedded-api/react-query/_context'\nimport { payrollsPrepare } from '@gusto/embedded-api/funcs/payrollsPrepare'\nimport { employeesGet } from '@gusto/embedded-api/funcs/employeesGet'\nimport { UnprocessableEntityError } from '@gusto/embedded-api/models/errors/unprocessableentityerror'\nimport type { PayrollEmployeeCompensationsType } from '@gusto/embedded-api/models/components/payrollemployeecompensationstype'\nimport type { Employee } from '@gusto/embedded-api/models/components/employee'\nimport type { PayrollPayPeriodType } from '@gusto/embedded-api/models/components/payrollpayperiodtype'\nimport type { PayScheduleShow } from '@gusto/embedded-api/models/components/payscheduleshow'\nimport type { PayrollCategory } from '../payrollTypes'\nimport { derivePayrollCategory } from '../payrollTypes'\nimport type { PaginationControlProps } from '@/components/Common/PaginationControl/PaginationControlTypes'\nimport { usePagination } from '@/hooks/usePagination/usePagination'\n\ninterface UsePayrollConfigurationDataParams {\n companyId: string\n payrollId: string\n /** When true, don't call prepare and cancel any prepare already running. */\n disablePrepare?: boolean\n excludedEmployeeUuids?: string[]\n /**\n * When true, prepare is called without a roster. A transition payroll's roster is fixed by the\n * pay-schedule transition, so the API rejects any `employeeUuids` sent to prepare.\n */\n isTransitionPayroll?: boolean\n}\n\ninterface UsePayrollConfigurationDataReturn {\n employeeCompensations: PayrollEmployeeCompensationsType[]\n employeeDetails: Employee[]\n payPeriod: PayrollPayPeriodType | undefined\n paySchedule: PayScheduleShow | undefined\n payrollCategory: PayrollCategory\n pagination: PaginationControlProps\n isLoading: boolean\n isAlreadyProcessed: boolean\n refetch: () => Promise<void>\n}\n\n/** @internal */\nexport const PREPARE_QUERY_KEY = 'payroll-prepare'\nconst FIVE_MINUTES = 5 * 60 * 1000\nconst PREPARE_MAX_ATTEMPTS = 3\n\nconst isAlreadyProcessedError = (error: unknown): boolean => {\n if (!(error instanceof UnprocessableEntityError)) return false\n return error.errors.some(e => e.category === 'invalid_operation')\n}\n\n/** @internal */\nexport function usePayrollConfigurationData({\n companyId,\n payrollId,\n disablePrepare = false,\n excludedEmployeeUuids = [],\n isTransitionPayroll = false,\n}: UsePayrollConfigurationDataParams): UsePayrollConfigurationDataReturn {\n const gustoClient = useGustoEmbeddedContext()\n const queryClient = useQueryClient()\n\n const { currentPage, itemsPerPage, getPaginationProps } = usePagination({\n defaultItemsPerPage: 25,\n })\n const [displayedEmployees, setDisplayedEmployees] = useState<Employee[]>([])\n const [isDataInSync, setIsDataInSync] = useState(false)\n const hasInitialDataRef = useRef(false)\n\n const { data: employeeData, isFetching: isFetchingEmployeeData } = useEmployeesList(\n {\n companyId,\n payrollUuid: payrollId,\n per: itemsPerPage,\n page: currentPage,\n sortBy: 'name',\n },\n { placeholderData: keepPreviousData },\n )\n\n const employeeDataRef = useRef(employeeData)\n employeeDataRef.current = employeeData\n\n const listedEmployeeUuids = useMemo(() => {\n return employeeData?.showEmployees?.map(e => e.uuid) || []\n }, [employeeData?.showEmployees])\n\n const missingExcludedUuids = useMemo(() => {\n const listedSet = new Set(listedEmployeeUuids)\n return excludedEmployeeUuids.filter(uuid => !listedSet.has(uuid))\n }, [excludedEmployeeUuids, listedEmployeeUuids])\n\n const employeeUuids = useMemo(() => {\n if (currentPage === 1) {\n return [...listedEmployeeUuids, ...missingExcludedUuids]\n }\n return listedEmployeeUuids\n }, [listedEmployeeUuids, missingExcludedUuids, currentPage])\n\n const employeeUuidsKey = useMemo(() => employeeUuids.join(','), [employeeUuids])\n\n const {\n data: prepareData,\n error: prepareError,\n isLoading: isPrepareLoading,\n isFetching: isPrepareFetching,\n } = useQuery({\n queryKey: [PREPARE_QUERY_KEY, payrollId, employeeUuidsKey],\n queryFn: async ({ signal }) => {\n const result = await payrollsPrepare(\n gustoClient,\n {\n companyId,\n payrollId,\n sortBy: 'last_name',\n requestBody: {\n employeeUuids: isTransitionPayroll ? undefined : employeeUuids,\n },\n },\n { signal },\n )\n\n if (!result.ok) {\n throw result.error\n }\n\n return result.value.payrollPrepared\n },\n enabled: employeeUuids.length > 0 && !disablePrepare,\n staleTime: FIVE_MINUTES,\n placeholderData: keepPreviousData,\n // An \"already processed\" prepare failure is terminal — retrying it wastes time. Other\n // errors (network blips, etc.) still get the standard retry treatment.\n retry: (failureCount, error) =>\n !isAlreadyProcessedError(error) && failureCount < PREPARE_MAX_ATTEMPTS,\n })\n\n const isAlreadyProcessed = isAlreadyProcessedError(prepareError)\n\n useEffect(() => {\n return () => {\n void queryClient.cancelQueries({\n queryKey: [PREPARE_QUERY_KEY, payrollId],\n })\n }\n }, [queryClient, payrollId])\n\n useEffect(() => {\n if (disablePrepare) {\n void queryClient.cancelQueries({\n queryKey: [PREPARE_QUERY_KEY, payrollId],\n })\n }\n }, [disablePrepare, queryClient, payrollId])\n\n const excludedUuidsKey = useMemo(() => missingExcludedUuids.join(','), [missingExcludedUuids])\n\n const { data: excludedEmployeeDetails } = useQuery({\n queryKey: ['excluded-employee-details', excludedUuidsKey],\n queryFn: async () => {\n const results = await Promise.all(\n missingExcludedUuids.map(uuid => employeesGet(gustoClient, { employeeId: uuid })),\n )\n const failedResult = results.find(result => !result.ok)\n if (failedResult) {\n throw failedResult.error\n }\n\n return results\n .filter(result => result.ok)\n .map(result => result.value.employee)\n .filter((e): e is Employee => e != null)\n },\n enabled: missingExcludedUuids.length > 0 && !disablePrepare,\n staleTime: FIVE_MINUTES,\n })\n\n const syncData = useCallback(() => {\n const currentEmployeeData = employeeDataRef.current\n if (!currentEmployeeData?.showEmployees || !prepareData?.employeeCompensations) {\n setIsDataInSync(false)\n return\n }\n\n const currentUuids = currentEmployeeData.showEmployees.map(e => e.uuid)\n const preparedUuids = new Set(prepareData.employeeCompensations.map(c => c.employeeUuid))\n const allListedInSync =\n currentUuids.length > 0 && currentUuids.every(uuid => preparedUuids.has(uuid))\n\n if (allListedInSync) {\n const mergedEmployees = [...currentEmployeeData.showEmployees]\n if (currentPage === 1 && excludedEmployeeDetails?.length) {\n const listedSet = new Set(currentUuids)\n for (const employee of excludedEmployeeDetails) {\n if (!listedSet.has(employee.uuid)) {\n mergedEmployees.push(employee)\n }\n }\n }\n setDisplayedEmployees(mergedEmployees)\n setIsDataInSync(true)\n hasInitialDataRef.current = true\n } else {\n setIsDataInSync(false)\n }\n }, [prepareData?.employeeCompensations, excludedEmployeeDetails, currentPage])\n\n useEffect(() => {\n syncData()\n }, [syncData])\n\n const { data: payScheduleData, isLoading: isPayScheduleLoading } = usePaySchedulesGet(\n {\n companyId,\n payScheduleId: prepareData?.payPeriod?.payScheduleUuid || '',\n },\n {\n enabled: !!prepareData?.payPeriod?.payScheduleUuid,\n },\n )\n\n const handleRefetch = useCallback(async () => {\n await queryClient.invalidateQueries({\n queryKey: [PREPARE_QUERY_KEY, payrollId],\n })\n }, [queryClient, payrollId])\n\n const isInitialLoading = isPrepareLoading && !hasInitialDataRef.current\n const isPaginating = isPrepareFetching && hasInitialDataRef.current\n const isPaginationFetching = isFetchingEmployeeData || isPaginating || !isDataInSync\n const isLoading =\n isInitialLoading || isPayScheduleLoading || (!employeeData && isFetchingEmployeeData)\n\n const headers = employeeData?.httpMeta.response.headers ?? new Headers()\n const pagination: PaginationControlProps = getPaginationProps(headers, isPaginationFetching)\n\n return {\n employeeCompensations: prepareData?.employeeCompensations ?? [],\n employeeDetails: displayedEmployees,\n payPeriod: prepareData?.payPeriod,\n paySchedule: payScheduleData?.payScheduleShow,\n payrollCategory: derivePayrollCategory(prepareData ?? {}),\n pagination,\n isLoading,\n isAlreadyProcessed,\n refetch: handleRefetch,\n }\n}\n"],"names":["PREPARE_QUERY_KEY","FIVE_MINUTES","PREPARE_MAX_ATTEMPTS","isAlreadyProcessedError","error","UnprocessableEntityError","e","usePayrollConfigurationData","companyId","payrollId","disablePrepare","excludedEmployeeUuids","isTransitionPayroll","gustoClient","useGustoEmbeddedContext","queryClient","useQueryClient","currentPage","itemsPerPage","getPaginationProps","usePagination","displayedEmployees","setDisplayedEmployees","useState","isDataInSync","setIsDataInSync","hasInitialDataRef","useRef","employeeData","isFetchingEmployeeData","useEmployeesList","keepPreviousData","employeeDataRef","listedEmployeeUuids","useMemo","missingExcludedUuids","listedSet","uuid","employeeUuids","employeeUuidsKey","prepareData","prepareError","isPrepareLoading","isPrepareFetching","useQuery","signal","result","payrollsPrepare","failureCount","isAlreadyProcessed","useEffect","excludedUuidsKey","excludedEmployeeDetails","results","employeesGet","failedResult","syncData","useCallback","currentEmployeeData","currentUuids","preparedUuids","c","mergedEmployees","employee","payScheduleData","isPayScheduleLoading","usePaySchedulesGet","handleRefetch","isInitialLoading","isPaginating","isPaginationFetching","isLoading","headers","pagination","derivePayrollCategory"],"mappings":"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"}
1
+ {"version":3,"file":"usePayrollConfigurationData.js","sources":["../../../../src/components/Payroll/PayrollConfiguration/usePayrollConfigurationData.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useEmployeesList } from '@gusto/embedded-api/react-query/employeesList'\nimport { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query'\nimport { usePaySchedulesGet } from '@gusto/embedded-api/react-query/paySchedulesGet'\nimport { useGustoEmbeddedContext } from '@gusto/embedded-api/react-query/_context'\nimport { payrollsPrepare } from '@gusto/embedded-api/funcs/payrollsPrepare'\nimport { employeesGet } from '@gusto/embedded-api/funcs/employeesGet'\nimport { UnprocessableEntityError } from '@gusto/embedded-api/models/errors/unprocessableentityerror'\nimport type { PayrollEmployeeCompensationsType } from '@gusto/embedded-api/models/components/payrollemployeecompensationstype'\nimport type { Employee } from '@gusto/embedded-api/models/components/employee'\nimport type { PayrollPayPeriodType } from '@gusto/embedded-api/models/components/payrollpayperiodtype'\nimport type { PayScheduleShow } from '@gusto/embedded-api/models/components/payscheduleshow'\nimport type { PayrollCategory } from '../payrollTypes'\nimport { derivePayrollCategory } from '../payrollTypes'\nimport type { PaginationControlProps } from '@/components/Common/PaginationControl/PaginationControlTypes'\nimport { usePagination } from '@/hooks/usePagination/usePagination'\n\ninterface UsePayrollConfigurationDataParams {\n companyId: string\n payrollId: string\n /** When true, don't call prepare and cancel any prepare already running. */\n disablePrepare?: boolean\n excludedEmployeeUuids?: string[]\n /**\n * When true, prepare is called without a roster. A transition payroll's roster is fixed by the\n * pay-schedule transition, so the API rejects any `employeeUuids` sent to prepare.\n */\n isTransitionPayroll?: boolean\n}\n\ninterface UsePayrollConfigurationDataReturn {\n employeeCompensations: PayrollEmployeeCompensationsType[]\n employeeDetails: Employee[]\n payPeriod: PayrollPayPeriodType | undefined\n paySchedule: PayScheduleShow | undefined\n payrollCategory: PayrollCategory\n pagination: PaginationControlProps\n isLoading: boolean\n isAlreadyProcessed: boolean\n refetch: () => Promise<void>\n}\n\n/** @internal */\nexport const PREPARE_QUERY_KEY = 'payroll-prepare'\nconst FIVE_MINUTES = 5 * 60 * 1000\nconst PREPARE_MAX_ATTEMPTS = 3\n\nconst isAlreadyProcessedError = (error: unknown): boolean => {\n if (!(error instanceof UnprocessableEntityError)) return false\n return error.errors.some(e => e.category === 'invalid_operation')\n}\n\n/** @internal */\nexport function usePayrollConfigurationData({\n companyId,\n payrollId,\n disablePrepare = false,\n excludedEmployeeUuids = [],\n isTransitionPayroll = false,\n}: UsePayrollConfigurationDataParams): UsePayrollConfigurationDataReturn {\n const gustoClient = useGustoEmbeddedContext()\n const queryClient = useQueryClient()\n\n const { currentPage, itemsPerPage, getPaginationProps } = usePagination({\n defaultItemsPerPage: 25,\n })\n const [displayedEmployees, setDisplayedEmployees] = useState<Employee[]>([])\n const [isDataInSync, setIsDataInSync] = useState(false)\n const hasInitialDataRef = useRef(false)\n\n const { data: employeeData, isFetching: isFetchingEmployeeData } = useEmployeesList(\n {\n companyId,\n payrollUuid: payrollId,\n per: itemsPerPage,\n page: currentPage,\n sortBy: 'name',\n },\n { placeholderData: keepPreviousData, throwOnError: true },\n )\n\n const employeeDataRef = useRef(employeeData)\n employeeDataRef.current = employeeData\n\n const listedEmployeeUuids = useMemo(() => {\n return employeeData?.showEmployees?.map(e => e.uuid) || []\n }, [employeeData?.showEmployees])\n\n const missingExcludedUuids = useMemo(() => {\n const listedSet = new Set(listedEmployeeUuids)\n return excludedEmployeeUuids.filter(uuid => !listedSet.has(uuid))\n }, [excludedEmployeeUuids, listedEmployeeUuids])\n\n const employeeUuids = useMemo(() => {\n if (currentPage === 1) {\n return [...listedEmployeeUuids, ...missingExcludedUuids]\n }\n return listedEmployeeUuids\n }, [listedEmployeeUuids, missingExcludedUuids, currentPage])\n\n const employeeUuidsKey = useMemo(() => employeeUuids.join(','), [employeeUuids])\n\n const {\n data: prepareData,\n error: prepareError,\n isLoading: isPrepareLoading,\n isFetching: isPrepareFetching,\n } = useQuery({\n queryKey: [PREPARE_QUERY_KEY, payrollId, employeeUuidsKey],\n queryFn: async ({ signal }) => {\n const result = await payrollsPrepare(\n gustoClient,\n {\n companyId,\n payrollId,\n sortBy: 'last_name',\n requestBody: {\n employeeUuids: isTransitionPayroll ? undefined : employeeUuids,\n },\n },\n { signal },\n )\n\n if (!result.ok) {\n throw result.error\n }\n\n return result.value.payrollPrepared\n },\n enabled: employeeUuids.length > 0 && !disablePrepare,\n staleTime: FIVE_MINUTES,\n placeholderData: keepPreviousData,\n throwOnError: error => !isAlreadyProcessedError(error),\n // An \"already processed\" prepare failure is terminal — retrying it wastes time. Other\n // errors (network blips, etc.) still get the standard retry treatment.\n retry: (failureCount, error) =>\n !isAlreadyProcessedError(error) && failureCount < PREPARE_MAX_ATTEMPTS,\n })\n\n const isAlreadyProcessed = isAlreadyProcessedError(prepareError)\n\n useEffect(() => {\n return () => {\n void queryClient.cancelQueries({\n queryKey: [PREPARE_QUERY_KEY, payrollId],\n })\n }\n }, [queryClient, payrollId])\n\n useEffect(() => {\n if (disablePrepare) {\n void queryClient.cancelQueries({\n queryKey: [PREPARE_QUERY_KEY, payrollId],\n })\n }\n }, [disablePrepare, queryClient, payrollId])\n\n const excludedUuidsKey = useMemo(() => missingExcludedUuids.join(','), [missingExcludedUuids])\n\n const { data: excludedEmployeeDetails } = useQuery({\n queryKey: ['excluded-employee-details', excludedUuidsKey],\n queryFn: async () => {\n const results = await Promise.all(\n missingExcludedUuids.map(uuid => employeesGet(gustoClient, { employeeId: uuid })),\n )\n const failedResult = results.find(result => !result.ok)\n if (failedResult) {\n throw failedResult.error\n }\n\n return results\n .filter(result => result.ok)\n .map(result => result.value.employee)\n .filter((e): e is Employee => e != null)\n },\n enabled: missingExcludedUuids.length > 0 && !disablePrepare,\n staleTime: FIVE_MINUTES,\n })\n\n const syncData = useCallback(() => {\n const currentEmployeeData = employeeDataRef.current\n if (!currentEmployeeData?.showEmployees || !prepareData?.employeeCompensations) {\n setIsDataInSync(false)\n return\n }\n\n const currentUuids = currentEmployeeData.showEmployees.map(e => e.uuid)\n const preparedUuids = new Set(prepareData.employeeCompensations.map(c => c.employeeUuid))\n const allListedInSync =\n currentUuids.length > 0 && currentUuids.every(uuid => preparedUuids.has(uuid))\n\n if (allListedInSync) {\n const mergedEmployees = [...currentEmployeeData.showEmployees]\n if (currentPage === 1 && excludedEmployeeDetails?.length) {\n const listedSet = new Set(currentUuids)\n for (const employee of excludedEmployeeDetails) {\n if (!listedSet.has(employee.uuid)) {\n mergedEmployees.push(employee)\n }\n }\n }\n setDisplayedEmployees(mergedEmployees)\n setIsDataInSync(true)\n hasInitialDataRef.current = true\n } else {\n setIsDataInSync(false)\n }\n }, [prepareData?.employeeCompensations, excludedEmployeeDetails, currentPage])\n\n useEffect(() => {\n syncData()\n }, [syncData])\n\n const { data: payScheduleData, isLoading: isPayScheduleLoading } = usePaySchedulesGet(\n {\n companyId,\n payScheduleId: prepareData?.payPeriod?.payScheduleUuid || '',\n },\n {\n enabled: !!prepareData?.payPeriod?.payScheduleUuid,\n },\n )\n\n const handleRefetch = useCallback(async () => {\n await queryClient.invalidateQueries({\n queryKey: [PREPARE_QUERY_KEY, payrollId],\n })\n }, [queryClient, payrollId])\n\n const isInitialLoading = isPrepareLoading && !hasInitialDataRef.current\n const isPaginating = isPrepareFetching && hasInitialDataRef.current\n const isPaginationFetching = isFetchingEmployeeData || isPaginating || !isDataInSync\n const isLoading =\n isInitialLoading || isPayScheduleLoading || (!employeeData && isFetchingEmployeeData)\n\n const headers = employeeData?.httpMeta.response.headers ?? new Headers()\n const pagination: PaginationControlProps = getPaginationProps(headers, isPaginationFetching)\n\n return {\n employeeCompensations: prepareData?.employeeCompensations ?? [],\n employeeDetails: displayedEmployees,\n payPeriod: prepareData?.payPeriod,\n paySchedule: payScheduleData?.payScheduleShow,\n payrollCategory: derivePayrollCategory(prepareData ?? {}),\n pagination,\n isLoading,\n isAlreadyProcessed,\n refetch: handleRefetch,\n }\n}\n"],"names":["PREPARE_QUERY_KEY","FIVE_MINUTES","PREPARE_MAX_ATTEMPTS","isAlreadyProcessedError","error","UnprocessableEntityError","e","usePayrollConfigurationData","companyId","payrollId","disablePrepare","excludedEmployeeUuids","isTransitionPayroll","gustoClient","useGustoEmbeddedContext","queryClient","useQueryClient","currentPage","itemsPerPage","getPaginationProps","usePagination","displayedEmployees","setDisplayedEmployees","useState","isDataInSync","setIsDataInSync","hasInitialDataRef","useRef","employeeData","isFetchingEmployeeData","useEmployeesList","keepPreviousData","employeeDataRef","listedEmployeeUuids","useMemo","missingExcludedUuids","listedSet","uuid","employeeUuids","employeeUuidsKey","prepareData","prepareError","isPrepareLoading","isPrepareFetching","useQuery","signal","result","payrollsPrepare","failureCount","isAlreadyProcessed","useEffect","excludedUuidsKey","excludedEmployeeDetails","results","employeesGet","failedResult","syncData","useCallback","currentEmployeeData","currentUuids","preparedUuids","c","mergedEmployees","employee","payScheduleData","isPayScheduleLoading","usePaySchedulesGet","handleRefetch","isInitialLoading","isPaginating","isPaginationFetching","isLoading","headers","pagination","derivePayrollCategory"],"mappings":"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"}
@@ -1,75 +1,75 @@
1
1
  import { jsx as o, jsxs as p } from "react/jsx-runtime";
2
- import { useForm as v, useWatch as R, FormProvider as _ } from "react-hook-form";
3
- import { zodResolver as T } from "@hookform/resolvers/zod";
2
+ import { useForm as T, useWatch as _, FormProvider as D } from "react-hook-form";
3
+ import { zodResolver as A } from "@hookform/resolvers/zod";
4
4
  import { useTranslation as h } from "react-i18next";
5
5
  import { z as d } from "zod";
6
- import { usePayrollsGeneratePrintableChecksMutation as D } from "@gusto/embedded-api/react-query/payrollsGeneratePrintableChecks";
6
+ import { usePayrollsGeneratePrintableChecksMutation as I } from "@gusto/embedded-api/react-query/payrollsGeneratePrintableChecks";
7
7
  import { PrintingFormat as n } from "@gusto/embedded-api/models/components/printablepayrollchecksbody";
8
- import { useGenerationPoll as A } from "./useGenerationPoll.js";
9
- import { BaseComponent as I } from "../../../Base/Base.js";
10
- import { useBase as G } from "../../../Base/useBase.js";
11
- import { useComponentContext as L } from "../../../../contexts/ComponentAdapter/useComponentContext.js";
12
- import { useComponentDictionary as M, useI18n as b } from "../../../../i18n/I18n.js";
8
+ import { useGenerationPoll as L } from "./useGenerationPoll.js";
9
+ import { BaseComponent as G } from "../../../Base/Base.js";
10
+ import { useBase as H } from "../../../Base/useBase.js";
11
+ import { useComponentContext as b } from "../../../../contexts/ComponentAdapter/useComponentContext.js";
12
+ import { useComponentDictionary as M, useI18n as g } from "../../../../i18n/I18n.js";
13
13
  import { useFlow as x } from "../../../Flow/useFlow.js";
14
14
  import { Flex as B } from "../../../Common/Flex/Flex.js";
15
15
  import { ActionsLayout as w } from "../../../Common/ActionsLayout/ActionsLayout.js";
16
- import { Form as H } from "../../../Common/Form/Form.js";
16
+ import { Form as q } from "../../../Common/Form/Form.js";
17
17
  import { printChecksEvents as m } from "../../../../shared/constants.js";
18
- import { RadioGroupField as q } from "../../../Common/Fields/RadioGroupField/RadioGroupField.js";
19
- import { NumberInputField as K } from "../../../Common/Fields/NumberInputField/NumberInputField.js";
20
- const U = d.object({
18
+ import { RadioGroupField as K } from "../../../Common/Fields/RadioGroupField/RadioGroupField.js";
19
+ import { NumberInputField as U } from "../../../Common/Fields/NumberInputField/NumberInputField.js";
20
+ const j = d.object({
21
21
  printingFormat: d.nativeEnum(n),
22
22
  startingCheckNumber: d.number({ message: "invalidStartingCheckNumber" }).int({ message: "invalidStartingCheckNumber" }).nonnegative({ message: "invalidStartingCheckNumber" }).lt(1e10, { message: "invalidStartingCheckNumber" }).optional()
23
- }), g = "gusto-sdk-print-checks-form", j = (r) => Array.isArray(r) && r.every((e) => typeof e == "object" && e !== null), z = (r) => {
24
- if (r && typeof r == "object" && "errors" in r && j(r.errors)) {
23
+ }), k = "gusto-sdk-print-checks-form", z = (r) => Array.isArray(r) && r.every((e) => typeof e == "object" && e !== null), O = (r) => {
24
+ if (r && typeof r == "object" && "errors" in r && z(r.errors)) {
25
25
  const [e] = r.errors;
26
26
  if (e?.message) return e.message;
27
27
  }
28
28
  return r instanceof Error ? r.message : null;
29
- }, O = (r) => ({
29
+ }, V = (r) => ({
30
30
  printingFormat: r.printingFormat,
31
31
  ...r.printingFormat === n.Bottom && r.startingCheckNumber !== void 0 ? { startingCheckNumber: r.startingCheckNumber } : {}
32
- }), V = (r) => {
32
+ }), W = (r) => {
33
33
  const e = document.createElement("a");
34
34
  e.href = r, e.rel = "noopener noreferrer", document.body.appendChild(e), e.click(), document.body.removeChild(e);
35
35
  };
36
- function W(r) {
37
- return /* @__PURE__ */ o(I, { ...r, children: /* @__PURE__ */ o(J, { ...r, children: r.children }) });
36
+ function J(r) {
37
+ return /* @__PURE__ */ o(G, { ...r, children: /* @__PURE__ */ o(Q, { ...r, children: r.children }) });
38
38
  }
39
- const J = ({ dictionary: r, payrollId: e, isGenerating: i, className: s }) => {
40
- M("Payroll.PrintChecksForm", r), b("Payroll.PrintChecksForm");
41
- const { t } = h("Payroll.PrintChecksForm"), { onEvent: c, baseSubmitHandler: k } = G(), l = v({
42
- resolver: T(U),
39
+ const Q = ({ dictionary: r, payrollId: e, isGenerating: i, className: s }) => {
40
+ M("Payroll.PrintChecksForm", r), g("Payroll.PrintChecksForm");
41
+ const { t } = h("Payroll.PrintChecksForm"), { Heading: f } = b(), { onEvent: c, baseSubmitHandler: E } = H(), l = T({
42
+ resolver: A(j),
43
43
  defaultValues: { printingFormat: n.Top, startingCheckNumber: 0 }
44
- }), f = R({
44
+ }), F = _({
45
45
  name: "printingFormat",
46
46
  control: l.control
47
- }), { mutateAsync: E } = D(), { start: F } = A({
47
+ }), { mutateAsync: N } = I(), { start: y } = L({
48
48
  onSucceeded: (a) => {
49
- c(m.PRINT_CHECKS_GENERATE_SUCCEEDED, { documentUrl: a }), a && V(a);
49
+ c(m.PRINT_CHECKS_GENERATE_SUCCEEDED, { documentUrl: a }), a && W(a);
50
50
  },
51
51
  onFailed: () => {
52
52
  c(m.PRINT_CHECKS_GENERATE_FAILED, { errorMessage: null });
53
53
  }
54
- }), N = async (a) => {
55
- c(m.PRINT_CHECKS_GENERATE_START), await k(a, async (S) => {
54
+ }), P = async (a) => {
55
+ c(m.PRINT_CHECKS_GENERATE_START), await E(a, async (R) => {
56
56
  try {
57
- const C = (await E({
57
+ const C = (await N({
58
58
  request: {
59
59
  payrollUuid: e,
60
- printablePayrollChecksBody: O(S)
60
+ printablePayrollChecksBody: V(R)
61
61
  }
62
62
  })).payrollCheck?.requestUuid;
63
63
  if (!C)
64
64
  throw new Error("Missing requestUuid in generate-printable-checks response");
65
- F(C);
65
+ y(C);
66
66
  } catch (u) {
67
67
  throw c(m.PRINT_CHECKS_GENERATE_FAILED, {
68
- errorMessage: z(u)
68
+ errorMessage: O(u)
69
69
  }), u;
70
70
  }
71
71
  });
72
- }, y = l.formState.errors.startingCheckNumber?.message ? t("validations.startingCheckNumber") : void 0, P = [
72
+ }, S = l.formState.errors.startingCheckNumber?.message ? t("validations.startingCheckNumber") : void 0, v = [
73
73
  {
74
74
  value: n.Top,
75
75
  label: t("customStockLabel"),
@@ -81,30 +81,32 @@ const J = ({ dictionary: r, payrollId: e, isGenerating: i, className: s }) => {
81
81
  description: t("blankStockDescription")
82
82
  }
83
83
  ];
84
- return /* @__PURE__ */ o(_, { ...l, children: /* @__PURE__ */ o(
85
- H,
84
+ return /* @__PURE__ */ o(D, { ...l, children: /* @__PURE__ */ o(
85
+ q,
86
86
  {
87
- id: g,
88
- onSubmit: l.handleSubmit(N),
87
+ id: k,
88
+ onSubmit: l.handleSubmit(P),
89
89
  className: s,
90
90
  children: /* @__PURE__ */ p(B, { flexDirection: "column", gap: 20, children: [
91
+ /* @__PURE__ */ o(f, { as: "h2", children: t("modalTitle") }),
91
92
  /* @__PURE__ */ o(
92
- q,
93
+ K,
93
94
  {
94
95
  name: "printingFormat",
95
96
  label: t("modalTitle"),
96
- options: P,
97
+ shouldVisuallyHideLabel: !0,
98
+ options: v,
97
99
  isRequired: !0,
98
100
  isDisabled: i
99
101
  }
100
102
  ),
101
- f === n.Bottom && /* @__PURE__ */ o(
102
- K,
103
+ F === n.Bottom && /* @__PURE__ */ o(
104
+ U,
103
105
  {
104
106
  name: "startingCheckNumber",
105
107
  label: t("startingCheckNumberLabel"),
106
108
  description: t("startingCheckNumberDescription"),
107
- errorMessage: y,
109
+ errorMessage: S,
108
110
  isDisabled: i,
109
111
  min: 0
110
112
  }
@@ -112,9 +114,9 @@ const J = ({ dictionary: r, payrollId: e, isGenerating: i, className: s }) => {
112
114
  ] })
113
115
  }
114
116
  ) });
115
- }, Q = ({ onEvent: r }) => {
116
- b("Payroll.PrintChecksForm");
117
- const { t: e } = h("Payroll.PrintChecksForm"), { Button: i } = L(), { isGenerating: s } = x();
117
+ }, X = ({ onEvent: r }) => {
118
+ g("Payroll.PrintChecksForm");
119
+ const { t: e } = h("Payroll.PrintChecksForm"), { Button: i } = b(), { isGenerating: s } = x();
118
120
  return /* @__PURE__ */ p(w, { children: [
119
121
  /* @__PURE__ */ o(
120
122
  i,
@@ -127,11 +129,11 @@ const J = ({ dictionary: r, payrollId: e, isGenerating: i, className: s }) => {
127
129
  children: e("cancelCta")
128
130
  }
129
131
  ),
130
- /* @__PURE__ */ o(i, { variant: "primary", type: "submit", form: g, isDisabled: s, children: e(s ? "submitCtaLoading" : "submitCta") })
132
+ /* @__PURE__ */ o(i, { variant: "primary", type: "submit", form: k, isDisabled: s, children: e(s ? "submitCtaLoading" : "submitCta") })
131
133
  ] });
132
134
  };
133
- W.Footer = Q;
135
+ J.Footer = X;
134
136
  export {
135
- W as PrintChecksForm
137
+ J as PrintChecksForm
136
138
  };
137
139
  //# sourceMappingURL=PrintChecksForm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PrintChecksForm.js","sources":["../../../../../src/components/Payroll/PrintChecks/PrintChecksForm/PrintChecksForm.tsx"],"sourcesContent":["import { FormProvider, useForm, useWatch } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { useTranslation } from 'react-i18next'\nimport { z } from 'zod'\nimport { usePayrollsGeneratePrintableChecksMutation } from '@gusto/embedded-api/react-query/payrollsGeneratePrintableChecks'\nimport {\n PrintingFormat,\n type PrintablePayrollChecksBody,\n} from '@gusto/embedded-api/models/components/printablepayrollchecksbody'\nimport { useGenerationPoll } from './useGenerationPoll'\nimport { BaseComponent, useBase, type BaseComponentInterface } from '@/components/Base'\nimport type { OnEventType } from '@/components/Base/useBase'\nimport { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext'\nimport { useComponentDictionary, useI18n } from '@/i18n'\nimport { useFlow, type FlowContextInterface } from '@/components/Flow/useFlow'\nimport { ActionsLayout, Flex, NumberInputField, RadioGroupField } from '@/components/Common'\nimport { Form } from '@/components/Common/Form'\nimport { printChecksEvents, type EventType } from '@/shared/constants'\nimport type { RadioGroupOption } from '@/index'\n\ninterface PrintChecksFormProps extends BaseComponentInterface<'Payroll.PrintChecksForm'> {\n payrollId: string\n /** Whether a generate-and-poll cycle is in flight; disables the fields while true. */\n isGenerating?: boolean\n}\n\n// The Footer is rendered by the top-level orchestrator as a sibling of this component (not a\n// child), so it can only read shared state — like whether a generate-and-poll cycle is in\n// flight — via the machine's FlowContext rather than as a prop. This narrow interface describes\n// only the field Footer needs, rather than depending on the orchestrator's full context type.\ninterface PrintChecksFormFlowContext extends FlowContextInterface {\n isGenerating?: boolean\n}\n\nconst PrintChecksFormSchema = z.object({\n printingFormat: z.nativeEnum(PrintingFormat),\n startingCheckNumber: z\n .number({ message: 'invalidStartingCheckNumber' })\n .int({ message: 'invalidStartingCheckNumber' })\n .nonnegative({ message: 'invalidStartingCheckNumber' })\n .lt(10_000_000_000, { message: 'invalidStartingCheckNumber' })\n .optional(),\n})\n\ntype PrintChecksFormValues = z.infer<typeof PrintChecksFormSchema>\n\nconst PRINT_CHECKS_FORM_ID = 'gusto-sdk-print-checks-form'\n\nconst isErrorList = (val: unknown): val is { message?: string }[] =>\n Array.isArray(val) && val.every(entry => typeof entry === 'object' && entry !== null)\n\nconst extractErrorMessage = (err: unknown): string | null => {\n if (err && typeof err === 'object' && 'errors' in err && isErrorList(err.errors)) {\n const [firstError] = err.errors\n if (firstError?.message) return firstError.message\n }\n return err instanceof Error ? err.message : null\n}\n\nconst buildRequestBody = (data: PrintChecksFormValues): PrintablePayrollChecksBody => ({\n printingFormat: data.printingFormat,\n ...(data.printingFormat === PrintingFormat.Bottom && data.startingCheckNumber !== undefined\n ? { startingCheckNumber: data.startingCheckNumber }\n : {}),\n})\n\n// Navigates directly to `url` via a synthetic anchor click rather than `fetch`-ing it into a blob:\n// the generated-document URL is a signed, cross-origin S3 URL with `response-content-disposition:\n// attachment` baked into its query string, so a direct browser-level request downloads it via that\n// response header — but a `fetch()` from JS is subject to CORS, which the bucket doesn't allow, and\n// fails outright. A plain navigation isn't subject to CORS and never opens a new tab or navigates\n// the host page, since the browser intercepts the download instead of rendering a response.\nconst downloadGeneratedChecks = (url: string) => {\n const link = document.createElement('a')\n link.href = url\n link.rel = 'noopener noreferrer'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\n/** @internal */\nexport function PrintChecksForm(props: PrintChecksFormProps) {\n return (\n <BaseComponent {...props}>\n <Root {...props}>{props.children}</Root>\n </BaseComponent>\n )\n}\n\nconst Root = ({ dictionary, payrollId, isGenerating, className }: PrintChecksFormProps) => {\n useComponentDictionary('Payroll.PrintChecksForm', dictionary)\n useI18n('Payroll.PrintChecksForm')\n const { t } = useTranslation('Payroll.PrintChecksForm')\n const { onEvent, baseSubmitHandler } = useBase()\n\n const formMethods = useForm<PrintChecksFormValues>({\n resolver: zodResolver(PrintChecksFormSchema),\n defaultValues: { printingFormat: PrintingFormat.Top, startingCheckNumber: 0 },\n })\n\n const printingFormat = useWatch<PrintChecksFormValues, 'printingFormat'>({\n name: 'printingFormat',\n control: formMethods.control,\n })\n\n const { mutateAsync } = usePayrollsGeneratePrintableChecksMutation()\n\n const { start: startGenerationPoll } = useGenerationPoll({\n onSucceeded: url => {\n onEvent(printChecksEvents.PRINT_CHECKS_GENERATE_SUCCEEDED, { documentUrl: url })\n if (url) {\n downloadGeneratedChecks(url)\n }\n },\n onFailed: () => {\n onEvent(printChecksEvents.PRINT_CHECKS_GENERATE_FAILED, { errorMessage: null })\n },\n })\n\n const onSubmit = async (formData: PrintChecksFormValues) => {\n onEvent(printChecksEvents.PRINT_CHECKS_GENERATE_START)\n\n await baseSubmitHandler(formData, async submittedData => {\n try {\n const result = await mutateAsync({\n request: {\n payrollUuid: payrollId,\n printablePayrollChecksBody: buildRequestBody(submittedData),\n },\n })\n\n const nextRequestUuid = result.payrollCheck?.requestUuid\n if (!nextRequestUuid) {\n throw new Error('Missing requestUuid in generate-printable-checks response')\n }\n\n startGenerationPoll(nextRequestUuid)\n } catch (err) {\n onEvent(printChecksEvents.PRINT_CHECKS_GENERATE_FAILED, {\n errorMessage: extractErrorMessage(err),\n })\n throw err\n }\n })\n }\n\n const startingCheckNumberErrorCode = formMethods.formState.errors.startingCheckNumber?.message\n const startingCheckNumberErrorMessage = startingCheckNumberErrorCode\n ? t('validations.startingCheckNumber')\n : undefined\n\n const printingFormatOptions: RadioGroupOption[] = [\n {\n value: PrintingFormat.Top,\n label: t('customStockLabel'),\n description: t('customStockDescription'),\n },\n {\n value: PrintingFormat.Bottom,\n label: t('blankStockLabel'),\n description: t('blankStockDescription'),\n },\n ]\n\n return (\n <FormProvider {...formMethods}>\n <Form\n id={PRINT_CHECKS_FORM_ID}\n onSubmit={formMethods.handleSubmit(onSubmit)}\n className={className}\n >\n <Flex flexDirection=\"column\" gap={20}>\n <RadioGroupField\n name=\"printingFormat\"\n label={t('modalTitle')}\n options={printingFormatOptions}\n isRequired\n isDisabled={isGenerating}\n />\n {printingFormat === PrintingFormat.Bottom && (\n <NumberInputField\n name=\"startingCheckNumber\"\n label={t('startingCheckNumberLabel')}\n description={t('startingCheckNumberDescription')}\n errorMessage={startingCheckNumberErrorMessage}\n isDisabled={isGenerating}\n min={0}\n />\n )}\n </Flex>\n </Form>\n </FormProvider>\n )\n}\n\nconst Footer = ({ onEvent }: { onEvent: OnEventType<EventType, unknown> }) => {\n useI18n('Payroll.PrintChecksForm')\n const { t } = useTranslation('Payroll.PrintChecksForm')\n const { Button } = useComponentContext()\n const { isGenerating } = useFlow<PrintChecksFormFlowContext>()\n\n return (\n <ActionsLayout>\n <Button\n variant=\"secondary\"\n onClick={() => {\n onEvent(printChecksEvents.PRINT_CHECKS_CANCEL)\n }}\n isDisabled={isGenerating}\n >\n {t('cancelCta')}\n </Button>\n <Button variant=\"primary\" type=\"submit\" form={PRINT_CHECKS_FORM_ID} isDisabled={isGenerating}>\n {isGenerating ? t('submitCtaLoading') : t('submitCta')}\n </Button>\n </ActionsLayout>\n )\n}\nPrintChecksForm.Footer = Footer\n"],"names":["PrintChecksFormSchema","z","PrintingFormat","PRINT_CHECKS_FORM_ID","isErrorList","val","entry","extractErrorMessage","err","firstError","buildRequestBody","data","downloadGeneratedChecks","url","link","PrintChecksForm","props","jsx","BaseComponent","Root","dictionary","payrollId","isGenerating","className","useComponentDictionary","useI18n","useTranslation","onEvent","baseSubmitHandler","useBase","formMethods","useForm","zodResolver","printingFormat","useWatch","mutateAsync","usePayrollsGeneratePrintableChecksMutation","startGenerationPoll","useGenerationPoll","printChecksEvents","onSubmit","formData","submittedData","nextRequestUuid","startingCheckNumberErrorMessage","printingFormatOptions","FormProvider","Form","jsxs","Flex","RadioGroupField","NumberInputField","Footer","t","Button","useComponentContext","useFlow","ActionsLayout"],"mappings":"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"}
1
+ {"version":3,"file":"PrintChecksForm.js","sources":["../../../../../src/components/Payroll/PrintChecks/PrintChecksForm/PrintChecksForm.tsx"],"sourcesContent":["import { FormProvider, useForm, useWatch } from 'react-hook-form'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { useTranslation } from 'react-i18next'\nimport { z } from 'zod'\nimport { usePayrollsGeneratePrintableChecksMutation } from '@gusto/embedded-api/react-query/payrollsGeneratePrintableChecks'\nimport {\n PrintingFormat,\n type PrintablePayrollChecksBody,\n} from '@gusto/embedded-api/models/components/printablepayrollchecksbody'\nimport { useGenerationPoll } from './useGenerationPoll'\nimport { BaseComponent, useBase, type BaseComponentInterface } from '@/components/Base'\nimport type { OnEventType } from '@/components/Base/useBase'\nimport { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext'\nimport { useComponentDictionary, useI18n } from '@/i18n'\nimport { useFlow, type FlowContextInterface } from '@/components/Flow/useFlow'\nimport { ActionsLayout, Flex, NumberInputField, RadioGroupField } from '@/components/Common'\nimport { Form } from '@/components/Common/Form'\nimport { printChecksEvents, type EventType } from '@/shared/constants'\nimport type { RadioGroupOption } from '@/index'\n\ninterface PrintChecksFormProps extends BaseComponentInterface<'Payroll.PrintChecksForm'> {\n payrollId: string\n /** Whether a generate-and-poll cycle is in flight; disables the fields while true. */\n isGenerating?: boolean\n}\n\n// The Footer is rendered by the top-level orchestrator as a sibling of this component (not a\n// child), so it can only read shared state — like whether a generate-and-poll cycle is in\n// flight — via the machine's FlowContext rather than as a prop. This narrow interface describes\n// only the field Footer needs, rather than depending on the orchestrator's full context type.\ninterface PrintChecksFormFlowContext extends FlowContextInterface {\n isGenerating?: boolean\n}\n\nconst PrintChecksFormSchema = z.object({\n printingFormat: z.nativeEnum(PrintingFormat),\n startingCheckNumber: z\n .number({ message: 'invalidStartingCheckNumber' })\n .int({ message: 'invalidStartingCheckNumber' })\n .nonnegative({ message: 'invalidStartingCheckNumber' })\n .lt(10_000_000_000, { message: 'invalidStartingCheckNumber' })\n .optional(),\n})\n\ntype PrintChecksFormValues = z.infer<typeof PrintChecksFormSchema>\n\nconst PRINT_CHECKS_FORM_ID = 'gusto-sdk-print-checks-form'\n\nconst isErrorList = (val: unknown): val is { message?: string }[] =>\n Array.isArray(val) && val.every(entry => typeof entry === 'object' && entry !== null)\n\nconst extractErrorMessage = (err: unknown): string | null => {\n if (err && typeof err === 'object' && 'errors' in err && isErrorList(err.errors)) {\n const [firstError] = err.errors\n if (firstError?.message) return firstError.message\n }\n return err instanceof Error ? err.message : null\n}\n\nconst buildRequestBody = (data: PrintChecksFormValues): PrintablePayrollChecksBody => ({\n printingFormat: data.printingFormat,\n ...(data.printingFormat === PrintingFormat.Bottom && data.startingCheckNumber !== undefined\n ? { startingCheckNumber: data.startingCheckNumber }\n : {}),\n})\n\n// Navigates directly to `url` via a synthetic anchor click rather than `fetch`-ing it into a blob:\n// the generated-document URL is a signed, cross-origin S3 URL with `response-content-disposition:\n// attachment` baked into its query string, so a direct browser-level request downloads it via that\n// response header — but a `fetch()` from JS is subject to CORS, which the bucket doesn't allow, and\n// fails outright. A plain navigation isn't subject to CORS and never opens a new tab or navigates\n// the host page, since the browser intercepts the download instead of rendering a response.\nconst downloadGeneratedChecks = (url: string) => {\n const link = document.createElement('a')\n link.href = url\n link.rel = 'noopener noreferrer'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\n/** @internal */\nexport function PrintChecksForm(props: PrintChecksFormProps) {\n return (\n <BaseComponent {...props}>\n <Root {...props}>{props.children}</Root>\n </BaseComponent>\n )\n}\n\nconst Root = ({ dictionary, payrollId, isGenerating, className }: PrintChecksFormProps) => {\n useComponentDictionary('Payroll.PrintChecksForm', dictionary)\n useI18n('Payroll.PrintChecksForm')\n const { t } = useTranslation('Payroll.PrintChecksForm')\n const { Heading } = useComponentContext()\n const { onEvent, baseSubmitHandler } = useBase()\n\n const formMethods = useForm<PrintChecksFormValues>({\n resolver: zodResolver(PrintChecksFormSchema),\n defaultValues: { printingFormat: PrintingFormat.Top, startingCheckNumber: 0 },\n })\n\n const printingFormat = useWatch<PrintChecksFormValues, 'printingFormat'>({\n name: 'printingFormat',\n control: formMethods.control,\n })\n\n const { mutateAsync } = usePayrollsGeneratePrintableChecksMutation()\n\n const { start: startGenerationPoll } = useGenerationPoll({\n onSucceeded: url => {\n onEvent(printChecksEvents.PRINT_CHECKS_GENERATE_SUCCEEDED, { documentUrl: url })\n if (url) {\n downloadGeneratedChecks(url)\n }\n },\n onFailed: () => {\n onEvent(printChecksEvents.PRINT_CHECKS_GENERATE_FAILED, { errorMessage: null })\n },\n })\n\n const onSubmit = async (formData: PrintChecksFormValues) => {\n onEvent(printChecksEvents.PRINT_CHECKS_GENERATE_START)\n\n await baseSubmitHandler(formData, async submittedData => {\n try {\n const result = await mutateAsync({\n request: {\n payrollUuid: payrollId,\n printablePayrollChecksBody: buildRequestBody(submittedData),\n },\n })\n\n const nextRequestUuid = result.payrollCheck?.requestUuid\n if (!nextRequestUuid) {\n throw new Error('Missing requestUuid in generate-printable-checks response')\n }\n\n startGenerationPoll(nextRequestUuid)\n } catch (err) {\n onEvent(printChecksEvents.PRINT_CHECKS_GENERATE_FAILED, {\n errorMessage: extractErrorMessage(err),\n })\n throw err\n }\n })\n }\n\n const startingCheckNumberErrorCode = formMethods.formState.errors.startingCheckNumber?.message\n const startingCheckNumberErrorMessage = startingCheckNumberErrorCode\n ? t('validations.startingCheckNumber')\n : undefined\n\n const printingFormatOptions: RadioGroupOption[] = [\n {\n value: PrintingFormat.Top,\n label: t('customStockLabel'),\n description: t('customStockDescription'),\n },\n {\n value: PrintingFormat.Bottom,\n label: t('blankStockLabel'),\n description: t('blankStockDescription'),\n },\n ]\n\n return (\n <FormProvider {...formMethods}>\n <Form\n id={PRINT_CHECKS_FORM_ID}\n onSubmit={formMethods.handleSubmit(onSubmit)}\n className={className}\n >\n <Flex flexDirection=\"column\" gap={20}>\n <Heading as=\"h2\">{t('modalTitle')}</Heading>\n <RadioGroupField\n name=\"printingFormat\"\n label={t('modalTitle')}\n shouldVisuallyHideLabel\n options={printingFormatOptions}\n isRequired\n isDisabled={isGenerating}\n />\n {printingFormat === PrintingFormat.Bottom && (\n <NumberInputField\n name=\"startingCheckNumber\"\n label={t('startingCheckNumberLabel')}\n description={t('startingCheckNumberDescription')}\n errorMessage={startingCheckNumberErrorMessage}\n isDisabled={isGenerating}\n min={0}\n />\n )}\n </Flex>\n </Form>\n </FormProvider>\n )\n}\n\nconst Footer = ({ onEvent }: { onEvent: OnEventType<EventType, unknown> }) => {\n useI18n('Payroll.PrintChecksForm')\n const { t } = useTranslation('Payroll.PrintChecksForm')\n const { Button } = useComponentContext()\n const { isGenerating } = useFlow<PrintChecksFormFlowContext>()\n\n return (\n <ActionsLayout>\n <Button\n variant=\"secondary\"\n onClick={() => {\n onEvent(printChecksEvents.PRINT_CHECKS_CANCEL)\n }}\n isDisabled={isGenerating}\n >\n {t('cancelCta')}\n </Button>\n <Button variant=\"primary\" type=\"submit\" form={PRINT_CHECKS_FORM_ID} isDisabled={isGenerating}>\n {isGenerating ? t('submitCtaLoading') : t('submitCta')}\n </Button>\n </ActionsLayout>\n )\n}\nPrintChecksForm.Footer = Footer\n"],"names":["PrintChecksFormSchema","z","PrintingFormat","PRINT_CHECKS_FORM_ID","isErrorList","val","entry","extractErrorMessage","err","firstError","buildRequestBody","data","downloadGeneratedChecks","url","link","PrintChecksForm","props","jsx","BaseComponent","Root","dictionary","payrollId","isGenerating","className","useComponentDictionary","useI18n","useTranslation","Heading","useComponentContext","onEvent","baseSubmitHandler","useBase","formMethods","useForm","zodResolver","printingFormat","useWatch","mutateAsync","usePayrollsGeneratePrintableChecksMutation","startGenerationPoll","useGenerationPoll","printChecksEvents","onSubmit","formData","submittedData","nextRequestUuid","startingCheckNumberErrorMessage","printingFormatOptions","FormProvider","Form","jsxs","Flex","RadioGroupField","NumberInputField","Footer","t","Button","useFlow","ActionsLayout"],"mappings":"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"}
@@ -1,14 +1,15 @@
1
1
  import { jsx as u } from "react/jsx-runtime";
2
2
  import { QueryClientProvider as E } from "@tanstack/react-query";
3
- import { GustoEmbeddedProvider as R } from "@gusto/embedded-api/react-query/_context";
4
- import { GustoEmbeddedCore as g } from "@gusto/embedded-api/core";
3
+ import { GustoEmbeddedProvider as g } from "@gusto/embedded-api/react-query/_context";
4
+ import { GustoEmbeddedCore as R } from "@gusto/embedded-api/core";
5
5
  import { SDKHooks as q } from "@gusto/embedded-api/hooks/hooks";
6
6
  import { useMemo as m } from "react";
7
- import { apiVersionHook as C } from "./apiVersionHook.js";
7
+ import { apiVersionHook as l } from "./apiVersionHook.js";
8
8
  import { apiVersionMismatchHook as a } from "./apiVersionMismatchHook.js";
9
- import { informationRequestEnumHook as b } from "./informationRequestEnumHook.js";
10
- import { createSdkQueryClient as l } from "./createSdkQueryClient.js";
11
- function P({
9
+ import { informationRequestEnumHook as A } from "./informationRequestEnumHook.js";
10
+ import { payrollDeductionAmountHook as C } from "./payrollDeductionAmountHook.js";
11
+ import { createSdkQueryClient as S } from "./createSdkQueryClient.js";
12
+ function Q({
12
13
  url: s,
13
14
  headers: i,
14
15
  hooks: r,
@@ -16,12 +17,12 @@ function P({
16
17
  queryClient: f
17
18
  }) {
18
19
  const p = m(() => {
19
- const t = new g({
20
+ const t = new R({
20
21
  serverURL: s
21
22
  }), e = t._options.hooks || new q();
22
- if (e.registerBeforeRequestHook(C), e.registerAfterSuccessHook(a), e.registerAfterErrorHook(a), e.registerAfterSuccessHook(b), i) {
23
+ if (e.registerBeforeRequestHook(l), e.registerAfterSuccessHook(a), e.registerAfterErrorHook(a), e.registerAfterSuccessHook(A), e.registerAfterSuccessHook(C), i) {
23
24
  const o = {
24
- beforeRequest: (S, n) => (new Headers(i).forEach((c, k) => {
25
+ beforeRequest: (b, n) => (new Headers(i).forEach((c, k) => {
25
26
  c && n.headers.set(k, c);
26
27
  }), n)
27
28
  };
@@ -36,10 +37,10 @@ function P({
36
37
  }), r?.afterError && r.afterError.forEach((o) => {
37
38
  e.registerAfterErrorHook(o);
38
39
  }), t._options.hooks || (t._options.hooks = e), t;
39
- }, [s, i, r]), d = m(() => f ?? l(), [f]);
40
- return /* @__PURE__ */ u(E, { client: d, children: /* @__PURE__ */ u(R, { client: p, children: H }) });
40
+ }, [s, i, r]), d = m(() => f ?? S(), [f]);
41
+ return /* @__PURE__ */ u(E, { client: d, children: /* @__PURE__ */ u(g, { client: p, children: H }) });
41
42
  }
42
43
  export {
43
- P as ApiProvider
44
+ Q as ApiProvider
44
45
  };
45
46
  //# sourceMappingURL=ApiProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApiProvider.js","sources":["../../../src/contexts/ApiProvider/ApiProvider.tsx"],"sourcesContent":["import { QueryClientProvider, type QueryClient } from '@tanstack/react-query'\nimport { GustoEmbeddedProvider } from '@gusto/embedded-api/react-query/_context'\nimport { GustoEmbeddedCore } from '@gusto/embedded-api/core'\nimport { SDKHooks as NativeSDKHooks } from '@gusto/embedded-api/hooks/hooks'\nimport { useMemo } from 'react'\nimport { apiVersionHook } from './apiVersionHook'\nimport { apiVersionMismatchHook } from './apiVersionMismatchHook'\nimport { informationRequestEnumHook } from './informationRequestEnumHook'\nimport { createSdkQueryClient } from './createSdkQueryClient'\nimport type { SDKHooks, BeforeRequestHook } from '@/types/hooks'\n\n/**\n * Props for {@link ApiProvider}.\n *\n * @internal\n */\nexport interface ApiProviderProps {\n /** Base URL the SDK uses for all `@gusto/embedded-api-v-2026-06-15` requests. */\n url: string\n /** Default headers applied to every SDK request, in addition to the `X-Gusto-API-Version` header set automatically. */\n headers?: HeadersInit\n /** Lifecycle hooks for intercepting and modifying SDK requests and responses. */\n hooks?: SDKHooks\n /** Subtree that renders inside the API + React Query providers. */\n children: React.ReactNode\n /** Optional React Query client. When omitted, a client is created with the SDK's defaults (auto-invalidation on mutation success). */\n queryClient?: QueryClient\n}\n\n/**\n * Wires the `@gusto/embedded-api-v-2026-06-15` client and a React Query client into the React tree.\n *\n * @remarks\n * Registers the SDK's `X-Gusto-API-Version` header on every request, warns via `console.warn` if a\n * response reports a different `X-Gusto-API-Version` than was requested (e.g. a proxy rewriting the\n * header), applies any default `headers`, and registers user-supplied lifecycle hooks\n * (`beforeCreateRequest`, `beforeRequest`, `afterSuccess`, `afterError`). When no `queryClient` is\n * supplied, one is created with the SDK's defaults so\n * successful mutations under the `['@gusto/embedded-api-v-2026-06-15']` key invalidate every SDK\n * query automatically. Partners who supply their own `QueryClient` are responsible for matching that\n * contract.\n *\n * Typically wrapped by {@link GustoProvider}; use directly only when composing the provider stack\n * manually.\n *\n * @param props - See {@link ApiProviderProps}.\n * @returns A React subtree wrapped in `QueryClientProvider` and the embedded API context.\n * @internal\n */\nexport function ApiProvider({\n url,\n headers,\n hooks,\n children,\n queryClient: queryClientFromProps,\n}: ApiProviderProps) {\n const gustoClient = useMemo(() => {\n const client = new GustoEmbeddedCore({\n serverURL: url,\n })\n\n const sdkHooks = client._options.hooks || new NativeSDKHooks()\n\n sdkHooks.registerBeforeRequestHook(apiVersionHook)\n sdkHooks.registerAfterSuccessHook(apiVersionMismatchHook)\n sdkHooks.registerAfterErrorHook(apiVersionMismatchHook)\n sdkHooks.registerAfterSuccessHook(informationRequestEnumHook)\n\n if (headers) {\n const defaultHeaderHook: BeforeRequestHook = {\n beforeRequest: (context, request) => {\n const headersInstance = new Headers(headers)\n headersInstance.forEach((headerValue, headerName) => {\n if (headerValue) {\n request.headers.set(headerName, headerValue)\n }\n })\n return request\n },\n }\n sdkHooks.registerBeforeRequestHook(defaultHeaderHook)\n }\n\n if (hooks?.beforeCreateRequest) {\n hooks.beforeCreateRequest.forEach(hook => {\n sdkHooks.registerBeforeCreateRequestHook(hook)\n })\n }\n\n if (hooks?.beforeRequest) {\n hooks.beforeRequest.forEach(hook => {\n sdkHooks.registerBeforeRequestHook(hook)\n })\n }\n\n if (hooks?.afterSuccess) {\n hooks.afterSuccess.forEach(hook => {\n sdkHooks.registerAfterSuccessHook(hook)\n })\n }\n\n if (hooks?.afterError) {\n hooks.afterError.forEach(hook => {\n sdkHooks.registerAfterErrorHook(hook)\n })\n }\n\n if (!client._options.hooks) {\n client._options.hooks = sdkHooks\n }\n\n return client\n }, [url, headers, hooks])\n\n const queryClient = useMemo(() => {\n return queryClientFromProps ?? createSdkQueryClient()\n }, [queryClientFromProps])\n\n return (\n <QueryClientProvider client={queryClient}>\n <GustoEmbeddedProvider client={gustoClient}>{children}</GustoEmbeddedProvider>\n </QueryClientProvider>\n )\n}\n"],"names":["ApiProvider","url","headers","hooks","children","queryClientFromProps","gustoClient","useMemo","client","GustoEmbeddedCore","sdkHooks","NativeSDKHooks","apiVersionHook","apiVersionMismatchHook","informationRequestEnumHook","defaultHeaderHook","context","request","headerValue","headerName","hook","queryClient","createSdkQueryClient","jsx","QueryClientProvider","GustoEmbeddedProvider"],"mappings":";;;;;;;;;;AAiDO,SAASA,EAAY;AAAA,EAC1B,KAAAC;AAAA,EACA,SAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,aAAaC;AACf,GAAqB;AACnB,QAAMC,IAAcC,EAAQ,MAAM;AAChC,UAAMC,IAAS,IAAIC,EAAkB;AAAA,MACnC,WAAWR;AAAA,IAAA,CACZ,GAEKS,IAAWF,EAAO,SAAS,SAAS,IAAIG,EAAA;AAO9C,QALAD,EAAS,0BAA0BE,CAAc,GACjDF,EAAS,yBAAyBG,CAAsB,GACxDH,EAAS,uBAAuBG,CAAsB,GACtDH,EAAS,yBAAyBI,CAA0B,GAExDZ,GAAS;AACX,YAAMa,IAAuC;AAAA,QAC3C,eAAe,CAACC,GAASC,OACC,IAAI,QAAQf,CAAO,EAC3B,QAAQ,CAACgB,GAAaC,MAAe;AACnD,UAAID,KACFD,EAAQ,QAAQ,IAAIE,GAAYD,CAAW;AAAA,QAE/C,CAAC,GACMD;AAAA,MACT;AAEF,MAAAP,EAAS,0BAA0BK,CAAiB;AAAA,IACtD;AAEA,WAAIZ,GAAO,uBACTA,EAAM,oBAAoB,QAAQ,CAAAiB,MAAQ;AACxC,MAAAV,EAAS,gCAAgCU,CAAI;AAAA,IAC/C,CAAC,GAGCjB,GAAO,iBACTA,EAAM,cAAc,QAAQ,CAAAiB,MAAQ;AAClC,MAAAV,EAAS,0BAA0BU,CAAI;AAAA,IACzC,CAAC,GAGCjB,GAAO,gBACTA,EAAM,aAAa,QAAQ,CAAAiB,MAAQ;AACjC,MAAAV,EAAS,yBAAyBU,CAAI;AAAA,IACxC,CAAC,GAGCjB,GAAO,cACTA,EAAM,WAAW,QAAQ,CAAAiB,MAAQ;AAC/B,MAAAV,EAAS,uBAAuBU,CAAI;AAAA,IACtC,CAAC,GAGEZ,EAAO,SAAS,UACnBA,EAAO,SAAS,QAAQE,IAGnBF;AAAA,EACT,GAAG,CAACP,GAAKC,GAASC,CAAK,CAAC,GAElBkB,IAAcd,EAAQ,MACnBF,KAAwBiB,EAAA,GAC9B,CAACjB,CAAoB,CAAC;AAEzB,SACE,gBAAAkB,EAACC,KAAoB,QAAQH,GAC3B,4BAACI,GAAA,EAAsB,QAAQnB,GAAc,UAAAF,EAAA,CAAS,EAAA,CACxD;AAEJ;"}
1
+ {"version":3,"file":"ApiProvider.js","sources":["../../../src/contexts/ApiProvider/ApiProvider.tsx"],"sourcesContent":["import { QueryClientProvider, type QueryClient } from '@tanstack/react-query'\nimport { GustoEmbeddedProvider } from '@gusto/embedded-api/react-query/_context'\nimport { GustoEmbeddedCore } from '@gusto/embedded-api/core'\nimport { SDKHooks as NativeSDKHooks } from '@gusto/embedded-api/hooks/hooks'\nimport { useMemo } from 'react'\nimport { apiVersionHook } from './apiVersionHook'\nimport { apiVersionMismatchHook } from './apiVersionMismatchHook'\nimport { informationRequestEnumHook } from './informationRequestEnumHook'\nimport { payrollDeductionAmountHook } from './payrollDeductionAmountHook'\nimport { createSdkQueryClient } from './createSdkQueryClient'\nimport type { SDKHooks, BeforeRequestHook } from '@/types/hooks'\n\n/**\n * Props for {@link ApiProvider}.\n *\n * @internal\n */\nexport interface ApiProviderProps {\n /** Base URL the SDK uses for all `@gusto/embedded-api-v-2026-06-15` requests. */\n url: string\n /** Default headers applied to every SDK request, in addition to the `X-Gusto-API-Version` header set automatically. */\n headers?: HeadersInit\n /** Lifecycle hooks for intercepting and modifying SDK requests and responses. */\n hooks?: SDKHooks\n /** Subtree that renders inside the API + React Query providers. */\n children: React.ReactNode\n /** Optional React Query client. When omitted, a client is created with the SDK's defaults (auto-invalidation on mutation success). */\n queryClient?: QueryClient\n}\n\n/**\n * Wires the `@gusto/embedded-api-v-2026-06-15` client and a React Query client into the React tree.\n *\n * @remarks\n * Registers the SDK's `X-Gusto-API-Version` header on every request, warns via `console.warn` if a\n * response reports a different `X-Gusto-API-Version` than was requested (e.g. a proxy rewriting the\n * header), applies any default `headers`, and registers user-supplied lifecycle hooks\n * (`beforeCreateRequest`, `beforeRequest`, `afterSuccess`, `afterError`). When no `queryClient` is\n * supplied, one is created with the SDK's defaults so\n * successful mutations under the `['@gusto/embedded-api-v-2026-06-15']` key invalidate every SDK\n * query automatically. Partners who supply their own `QueryClient` are responsible for matching that\n * contract.\n *\n * Typically wrapped by {@link GustoProvider}; use directly only when composing the provider stack\n * manually.\n *\n * @param props - See {@link ApiProviderProps}.\n * @returns A React subtree wrapped in `QueryClientProvider` and the embedded API context.\n * @internal\n */\nexport function ApiProvider({\n url,\n headers,\n hooks,\n children,\n queryClient: queryClientFromProps,\n}: ApiProviderProps) {\n const gustoClient = useMemo(() => {\n const client = new GustoEmbeddedCore({\n serverURL: url,\n })\n\n const sdkHooks = client._options.hooks || new NativeSDKHooks()\n\n sdkHooks.registerBeforeRequestHook(apiVersionHook)\n sdkHooks.registerAfterSuccessHook(apiVersionMismatchHook)\n sdkHooks.registerAfterErrorHook(apiVersionMismatchHook)\n sdkHooks.registerAfterSuccessHook(informationRequestEnumHook)\n sdkHooks.registerAfterSuccessHook(payrollDeductionAmountHook)\n\n if (headers) {\n const defaultHeaderHook: BeforeRequestHook = {\n beforeRequest: (context, request) => {\n const headersInstance = new Headers(headers)\n headersInstance.forEach((headerValue, headerName) => {\n if (headerValue) {\n request.headers.set(headerName, headerValue)\n }\n })\n return request\n },\n }\n sdkHooks.registerBeforeRequestHook(defaultHeaderHook)\n }\n\n if (hooks?.beforeCreateRequest) {\n hooks.beforeCreateRequest.forEach(hook => {\n sdkHooks.registerBeforeCreateRequestHook(hook)\n })\n }\n\n if (hooks?.beforeRequest) {\n hooks.beforeRequest.forEach(hook => {\n sdkHooks.registerBeforeRequestHook(hook)\n })\n }\n\n if (hooks?.afterSuccess) {\n hooks.afterSuccess.forEach(hook => {\n sdkHooks.registerAfterSuccessHook(hook)\n })\n }\n\n if (hooks?.afterError) {\n hooks.afterError.forEach(hook => {\n sdkHooks.registerAfterErrorHook(hook)\n })\n }\n\n if (!client._options.hooks) {\n client._options.hooks = sdkHooks\n }\n\n return client\n }, [url, headers, hooks])\n\n const queryClient = useMemo(() => {\n return queryClientFromProps ?? createSdkQueryClient()\n }, [queryClientFromProps])\n\n return (\n <QueryClientProvider client={queryClient}>\n <GustoEmbeddedProvider client={gustoClient}>{children}</GustoEmbeddedProvider>\n </QueryClientProvider>\n )\n}\n"],"names":["ApiProvider","url","headers","hooks","children","queryClientFromProps","gustoClient","useMemo","client","GustoEmbeddedCore","sdkHooks","NativeSDKHooks","apiVersionHook","apiVersionMismatchHook","informationRequestEnumHook","payrollDeductionAmountHook","defaultHeaderHook","context","request","headerValue","headerName","hook","queryClient","createSdkQueryClient","jsx","QueryClientProvider","GustoEmbeddedProvider"],"mappings":";;;;;;;;;;;AAkDO,SAASA,EAAY;AAAA,EAC1B,KAAAC;AAAA,EACA,SAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,aAAaC;AACf,GAAqB;AACnB,QAAMC,IAAcC,EAAQ,MAAM;AAChC,UAAMC,IAAS,IAAIC,EAAkB;AAAA,MACnC,WAAWR;AAAA,IAAA,CACZ,GAEKS,IAAWF,EAAO,SAAS,SAAS,IAAIG,EAAA;AAQ9C,QANAD,EAAS,0BAA0BE,CAAc,GACjDF,EAAS,yBAAyBG,CAAsB,GACxDH,EAAS,uBAAuBG,CAAsB,GACtDH,EAAS,yBAAyBI,CAA0B,GAC5DJ,EAAS,yBAAyBK,CAA0B,GAExDb,GAAS;AACX,YAAMc,IAAuC;AAAA,QAC3C,eAAe,CAACC,GAASC,OACC,IAAI,QAAQhB,CAAO,EAC3B,QAAQ,CAACiB,GAAaC,MAAe;AACnD,UAAID,KACFD,EAAQ,QAAQ,IAAIE,GAAYD,CAAW;AAAA,QAE/C,CAAC,GACMD;AAAA,MACT;AAEF,MAAAR,EAAS,0BAA0BM,CAAiB;AAAA,IACtD;AAEA,WAAIb,GAAO,uBACTA,EAAM,oBAAoB,QAAQ,CAAAkB,MAAQ;AACxC,MAAAX,EAAS,gCAAgCW,CAAI;AAAA,IAC/C,CAAC,GAGClB,GAAO,iBACTA,EAAM,cAAc,QAAQ,CAAAkB,MAAQ;AAClC,MAAAX,EAAS,0BAA0BW,CAAI;AAAA,IACzC,CAAC,GAGClB,GAAO,gBACTA,EAAM,aAAa,QAAQ,CAAAkB,MAAQ;AACjC,MAAAX,EAAS,yBAAyBW,CAAI;AAAA,IACxC,CAAC,GAGClB,GAAO,cACTA,EAAM,WAAW,QAAQ,CAAAkB,MAAQ;AAC/B,MAAAX,EAAS,uBAAuBW,CAAI;AAAA,IACtC,CAAC,GAGEb,EAAO,SAAS,UACnBA,EAAO,SAAS,QAAQE,IAGnBF;AAAA,EACT,GAAG,CAACP,GAAKC,GAASC,CAAK,CAAC,GAElBmB,IAAcf,EAAQ,MACnBF,KAAwBkB,EAAA,GAC9B,CAAClB,CAAoB,CAAC;AAEzB,SACE,gBAAAmB,EAACC,KAAoB,QAAQH,GAC3B,4BAACI,GAAA,EAAsB,QAAQpB,GAAc,UAAAF,EAAA,CAAS,EAAA,CACxD;AAEJ;"}
@@ -0,0 +1,36 @@
1
+ const u = /* @__PURE__ */ new Set([
2
+ "put-v1-companies-company_id-payrolls-payroll_id-prepare",
3
+ "put-v1-companies-company_id-payrolls",
4
+ "post-v1-companies-company_id-payrolls"
5
+ ]), r = (o) => o !== null && typeof o == "object" && !Array.isArray(o), y = {
6
+ afterSuccess: async (o, t) => {
7
+ if (!u.has(o.operationID)) return t;
8
+ let n;
9
+ try {
10
+ n = await t.clone().json();
11
+ } catch {
12
+ return t;
13
+ }
14
+ if (!r(n) || !Array.isArray(n.employee_compensations)) return t;
15
+ let s = !1;
16
+ for (const a of n.employee_compensations)
17
+ if (!(!r(a) || !Array.isArray(a.deductions)))
18
+ for (const e of a.deductions) {
19
+ if (!r(e) || typeof e.amount != "string" || !/^-?\d+(?:\.\d+)?$/.test(e.amount))
20
+ continue;
21
+ const c = Number(e.amount);
22
+ Number.isFinite(c) && (e.amount = c, s = !0);
23
+ }
24
+ if (!s) return t;
25
+ const i = new Headers(t.headers);
26
+ return i.delete("content-length"), new Response(JSON.stringify(n), {
27
+ status: t.status,
28
+ statusText: t.statusText,
29
+ headers: i
30
+ });
31
+ }
32
+ };
33
+ export {
34
+ y as payrollDeductionAmountHook
35
+ };
36
+ //# sourceMappingURL=payrollDeductionAmountHook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payrollDeductionAmountHook.js","sources":["../../../src/contexts/ApiProvider/payrollDeductionAmountHook.ts"],"sourcesContent":["import type { AfterSuccessHook } from '@/types/hooks'\n\nconst PAYROLL_OPERATIONS = new Set([\n 'put-v1-companies-company_id-payrolls-payroll_id-prepare',\n 'put-v1-companies-company_id-payrolls',\n 'post-v1-companies-company_id-payrolls',\n])\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n value !== null && typeof value === 'object' && !Array.isArray(value)\n\n/**\n * Normalizes string deduction amounts for payroll responses whose generated schema expects numbers.\n *\n * @remarks\n * API version 2026-06-15 returns decimal strings, including percentage deductions. The generated\n * prepare, update, and off-cycle response schemas still require numbers. Remove this compatibility\n * hook once those schemas match the API. Invalid amounts remain unchanged so validation rejects them.\n *\n * @internal\n */\nexport const payrollDeductionAmountHook: AfterSuccessHook = {\n afterSuccess: async (context, response) => {\n if (!PAYROLL_OPERATIONS.has(context.operationID)) return response\n\n let body: unknown\n try {\n body = await response.clone().json()\n } catch {\n return response\n }\n\n if (!isRecord(body) || !Array.isArray(body.employee_compensations)) return response\n\n let hasChanges = false\n for (const compensation of body.employee_compensations) {\n if (!isRecord(compensation) || !Array.isArray(compensation.deductions)) continue\n\n for (const deduction of compensation.deductions) {\n if (\n !isRecord(deduction) ||\n typeof deduction.amount !== 'string' ||\n !/^-?\\d+(?:\\.\\d+)?$/.test(deduction.amount)\n ) {\n continue\n }\n\n const amount = Number(deduction.amount)\n if (!Number.isFinite(amount)) continue\n\n deduction.amount = amount\n hasChanges = true\n }\n }\n\n if (!hasChanges) return response\n\n const headers = new Headers(response.headers)\n headers.delete('content-length')\n return new Response(JSON.stringify(body), {\n status: response.status,\n statusText: response.statusText,\n headers,\n })\n },\n}\n"],"names":["PAYROLL_OPERATIONS","isRecord","value","payrollDeductionAmountHook","context","response","body","hasChanges","compensation","deduction","amount","headers"],"mappings":"AAEA,MAAMA,wBAAyB,IAAI;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,CAAC,GAEKC,IAAW,CAACC,MAChBA,MAAU,QAAQ,OAAOA,KAAU,YAAY,CAAC,MAAM,QAAQA,CAAK,GAYxDC,IAA+C;AAAA,EAC1D,cAAc,OAAOC,GAASC,MAAa;AACzC,QAAI,CAACL,EAAmB,IAAII,EAAQ,WAAW,EAAG,QAAOC;AAEzD,QAAIC;AACJ,QAAI;AACF,MAAAA,IAAO,MAAMD,EAAS,MAAA,EAAQ,KAAA;AAAA,IAChC,QAAQ;AACN,aAAOA;AAAA,IACT;AAEA,QAAI,CAACJ,EAASK,CAAI,KAAK,CAAC,MAAM,QAAQA,EAAK,sBAAsB,EAAG,QAAOD;AAE3E,QAAIE,IAAa;AACjB,eAAWC,KAAgBF,EAAK;AAC9B,UAAI,GAACL,EAASO,CAAY,KAAK,CAAC,MAAM,QAAQA,EAAa,UAAU;AAErE,mBAAWC,KAAaD,EAAa,YAAY;AAC/C,cACE,CAACP,EAASQ,CAAS,KACnB,OAAOA,EAAU,UAAW,YAC5B,CAAC,oBAAoB,KAAKA,EAAU,MAAM;AAE1C;AAGF,gBAAMC,IAAS,OAAOD,EAAU,MAAM;AACtC,UAAK,OAAO,SAASC,CAAM,MAE3BD,EAAU,SAASC,GACnBH,IAAa;AAAA,QACf;AAGF,QAAI,CAACA,EAAY,QAAOF;AAExB,UAAMM,IAAU,IAAI,QAAQN,EAAS,OAAO;AAC5C,WAAAM,EAAQ,OAAO,gBAAgB,GACxB,IAAI,SAAS,KAAK,UAAUL,CAAI,GAAG;AAAA,MACxC,QAAQD,EAAS;AAAA,MACjB,YAAYA,EAAS;AAAA,MACrB,SAAAM;AAAA,IAAA,CACD;AAAA,EACH;AACF;"}
@@ -1,4 +1,4 @@
1
- const e = "@gusto/embedded-react-sdk", o = "0.56.6";
1
+ const e = "@gusto/embedded-react-sdk", o = "0.56.7";
2
2
  export {
3
3
  e as name,
4
4
  o as version
@@ -0,0 +1,67 @@
1
+ import { HttpHandler, HttpResponseResolver } from 'msw';
2
+ /**
3
+ * Shared, parameterizable mock data + MSW handlers for the PayrollList container tests.
4
+ *
5
+ * All shapes are the snake_case JSON the API returns (the SDK client normalizes
6
+ * to camelCase), so these plug directly into MSW resolvers.
7
+ */
8
+ export declare const COMPANY_ID = "company-123";
9
+ export declare const createListPayroll: (overrides?: Record<string, unknown>) => {
10
+ payroll_uuid: string;
11
+ processed: boolean;
12
+ off_cycle: boolean;
13
+ external: boolean;
14
+ payroll_type: string;
15
+ check_date: string;
16
+ payroll_deadline: string;
17
+ pay_period: {
18
+ start_date: string;
19
+ end_date: string;
20
+ pay_schedule_uuid: string;
21
+ };
22
+ };
23
+ export declare const createOffCyclePayroll: (offCycleReason: string, overrides?: Record<string, unknown>) => {
24
+ payroll_uuid: string;
25
+ processed: boolean;
26
+ off_cycle: boolean;
27
+ external: boolean;
28
+ payroll_type: string;
29
+ check_date: string;
30
+ payroll_deadline: string;
31
+ pay_period: {
32
+ start_date: string;
33
+ end_date: string;
34
+ pay_schedule_uuid: string;
35
+ };
36
+ };
37
+ export declare const createPaySchedule: (overrides?: Record<string, unknown>) => {
38
+ uuid: string;
39
+ frequency: string;
40
+ anchor_pay_date: string;
41
+ anchor_end_of_pay_period: string;
42
+ custom_name: string;
43
+ active: boolean;
44
+ version: string;
45
+ };
46
+ export declare const createTransitionPayPeriod: () => {
47
+ start_date: string;
48
+ end_date: string;
49
+ pay_schedule_uuid: string;
50
+ payroll: {
51
+ processed: boolean;
52
+ payroll_type: string;
53
+ };
54
+ };
55
+ interface PayrollListHandlerOptions {
56
+ payrolls?: Array<Record<string, unknown>>;
57
+ payrollsHeaders?: Record<string, string>;
58
+ payrollsResolver?: HttpResponseResolver;
59
+ paySchedules?: Array<Record<string, unknown>>;
60
+ blockers?: Array<Record<string, unknown>>;
61
+ wireInRequests?: Array<Record<string, unknown>>;
62
+ payPeriods?: Array<Record<string, unknown>>;
63
+ }
64
+ export declare const buildPayrollListHandlers: ({ payrolls, payrollsHeaders, payrollsResolver, paySchedules, blockers, wireInRequests, payPeriods, }?: PayrollListHandlerOptions) => HttpHandler[];
65
+ export declare const handleSkipPayroll: (resolver: HttpResponseResolver) => HttpHandler;
66
+ export declare const handleDeletePayroll: (resolver: HttpResponseResolver) => HttpHandler;
67
+ export {};
@@ -0,0 +1,12 @@
1
+ import { AfterSuccessHook } from '../../types/hooks';
2
+ /**
3
+ * Normalizes string deduction amounts for payroll responses whose generated schema expects numbers.
4
+ *
5
+ * @remarks
6
+ * API version 2026-06-15 returns decimal strings, including percentage deductions. The generated
7
+ * prepare, update, and off-cycle response schemas still require numbers. Remove this compatibility
8
+ * hook once those schemas match the API. Invalid amounts remain unchanged so validation rejects them.
9
+ *
10
+ * @internal
11
+ */
12
+ export declare const payrollDeductionAmountHook: AfterSuccessHook;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gusto/embedded-react-sdk",
3
- "version": "0.56.6",
3
+ "version": "0.56.7",
4
4
  "homepage": "https://github.com/Gusto/embedded-react-sdk",
5
5
  "bugs": {
6
6
  "url": "https://github.com/Gusto/embedded-react-sdk/issues"
@@ -125,7 +125,7 @@
125
125
  "ajv": "^8.20.0",
126
126
  "axe-core": "^4.13.0",
127
127
  "cspell": "^10.3.3",
128
- "dotenv": "^18.0.2",
128
+ "dotenv": "^18.0.3",
129
129
  "eslint": "^9.39.5",
130
130
  "eslint-plugin-import": "^2.31.0",
131
131
  "eslint-plugin-jsx-a11y": "^6.10.2",
@@ -147,18 +147,18 @@
147
147
  "npm-run-all": "^4.1.5",
148
148
  "pixelmatch": "^7.2.0",
149
149
  "pngjs": "^7.0.0",
150
- "prettier": "^3.9.8",
150
+ "prettier": "^3.9.9",
151
151
  "prism-react-renderer": "^2.4.1",
152
152
  "react-dnd": "^16.0.1",
153
153
  "react-dnd-html5-backend": "^16.0.1",
154
154
  "react-router-dom": "^7.18.4",
155
- "release-it": "^21.1.0",
156
- "sass-embedded": "^1.104.1",
155
+ "release-it": "^21.1.1",
156
+ "sass-embedded": "^1.105.0",
157
157
  "storybook": "^10.5.5",
158
158
  "stylelint-config-standard": "^40.0.0",
159
159
  "ts-morph": "^28.0.0",
160
160
  "tsx": "^4.23.15",
161
- "typescript-eslint": "^8.70.0",
161
+ "typescript-eslint": "^8.70.1",
162
162
  "vite": "^6.4.3",
163
163
  "vite-plugin-checker": "^0.14.5",
164
164
  "vite-plugin-circular-dependency": "^0.6.0",
@@ -180,7 +180,7 @@
180
180
  "js-yaml": "^4.3.2",
181
181
  "uuid": "^11.1.1",
182
182
  "@babel/core": "^7.29.6",
183
- "markdown-it": "^14.2.0",
183
+ "markdown-it": "^14.3.2",
184
184
  "conventional-commits-parser": "^7.1.0",
185
185
  "conventional-commits-filter": "^5.0.0"
186
186
  },
@@ -192,7 +192,7 @@
192
192
  "@internationalized/number": "^3.6.8",
193
193
  "classnames": "^2.5.1",
194
194
  "deepmerge": "^4.3.1",
195
- "dompurify": "^3.4.15",
195
+ "dompurify": "^3.4.16",
196
196
  "i18next": "^26.4.2",
197
197
  "react-aria": "^3.47.0",
198
198
  "react-aria-components": "1.16.0",