diff --git a/.reports/embedded-react-sdk.api.md b/.reports/embedded-react-sdk.api.md index f6a392395..ccc4697a5 100644 --- a/.reports/embedded-react-sdk.api.md +++ b/.reports/embedded-react-sdk.api.md @@ -4239,6 +4239,8 @@ declare namespace Payroll { PayrollBlockerListProps, RecoveryCases, RecoveryCasesProps, + PrintChecks, + PrintChecksProps, OffCyclePayPeriodDateFormData, OffCyclePayrollDateType, OffCycleCreation, @@ -4590,6 +4592,16 @@ export type PreparerSelectFieldProps = HookFieldProps>; +// @public +function PrintChecks(input: PrintChecksProps): JSX; + +// @public +interface PrintChecksProps extends Omit, 'onEvent'> { + companyId: string; + onEvent?: BaseComponentInterface['onEvent']; + payrollId: string; +} + // @public function Profile(input: ProfileProps): JSX; diff --git a/docs/guides/endpoint-inventory.json b/docs/guides/endpoint-inventory.json index 2bff12d5a..1536d107f 100644 --- a/docs/guides/endpoint-inventory.json +++ b/docs/guides/endpoint-inventory.json @@ -384,6 +384,32 @@ "recoveryCaseUuid" ] }, + "Payroll.PrintChecks": { + "endpoints": [ + { + "method": "GET", + "path": "/v1/companies/:companyId/payrolls/:payrollId", + "docsUrl": "https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-v1-companies-company_id-payrolls-payroll_id" + }, + { + "method": "GET", + "path": "/v1/generated_documents/:documentType/:requestUuid", + "docsUrl": "https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-v1-generated_documents-document_type-request_uuid" + }, + { + "method": "POST", + "path": "/v1/payrolls/:payrollUuid/generated_documents/printable_payroll_checks", + "docsUrl": "https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/post-v1-payrolls-payroll_uuid-generated_documents-printable_payroll_checks" + } + ], + "variables": [ + "companyId", + "documentType", + "payrollId", + "payrollUuid", + "requestUuid" + ] + }, "Payroll.OffCycleCreation": { "endpoints": [ { diff --git a/docs/guides/endpoint-reference.md b/docs/guides/endpoint-reference.md index 624342f7c..4d1422673 100644 --- a/docs/guides/endpoint-reference.md +++ b/docs/guides/endpoint-reference.md @@ -447,6 +447,9 @@ import inventory from '@gusto/embedded-react-sdk/endpoint-inventory.json' | | GET | [`/v1/companies/:companyUuid/recovery_cases`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-recovery-cases) | | **Payroll.RecoveryCases** | GET | [`/v1/companies/:companyUuid/recovery_cases`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-recovery-cases) | | | PUT | [`/v1/recovery_cases/:recoveryCaseUuid/redebit`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/redebit-recovery-case) | +| **Payroll.PrintChecks** | GET | [`/v1/companies/:companyId/payrolls/:payrollId`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-v1-companies-company_id-payrolls-payroll_id) | +| | GET | [`/v1/generated_documents/:documentType/:requestUuid`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-v1-generated_documents-document_type-request_uuid) | +| | POST | [`/v1/payrolls/:payrollUuid/generated_documents/printable_payroll_checks`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/post-v1-payrolls-payroll_uuid-generated_documents-printable_payroll_checks) | | **Payroll.OffCycleCreation** | GET | [`/v1/companies/:companyId/employees`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-v1-companies-company_id-employees) | | | POST | [`/v1/companies/:companyId/payrolls`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/post-v1-companies-company_id-payrolls) | | | GET | [`/v1/companies/:companyUuid/payment_configs`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-v1-company-payment-configs) | diff --git a/docs/reference/blocks.md b/docs/reference/blocks.md index ef3b6e8fd..08b107960 100644 --- a/docs/reference/blocks.md +++ b/docs/reference/blocks.md @@ -132,6 +132,7 @@ Individual form and UI components with SDK logic built in — use these for cust | [Payroll.PayrollList](payroll/blocks#payrolllist) | Lists upcoming payrolls and lets users start running them. | | [Payroll.PayrollOverview](payroll/blocks#payrolloverview) | Final review screen for a calculated payroll before submission, with submit, cancel, and edit controls. After submission, tracks processing status and surfaces the receipt and per-employee paystub downloads once complete. | | [Payroll.PayrollReceipts](payroll/blocks#payrollreceipts) | Displays a detailed receipt for a completed payroll, including the debited total, per-category breakdown, tax breakdown, and a per-employee summary of payment method, garnishments, reimbursements, taxes, and net pay. | +| [Payroll.PrintChecks](payroll/blocks#printchecks) | Displays a banner prompting the user to print checks for employees paid by check on a processed payroll, and walks them through choosing check stock and generating the check PDF. | | [Payroll.RecoveryCases](payroll/blocks#recoverycases) | Displays open recovery cases for a company and provides an in-modal resubmit workflow for resolving them. | | [Payroll.TransitionCreation](payroll/blocks#transitioncreation) | Creation form for transition payrolls covering the gap between an old and new pay schedule. | | [TimeOff.AddEmployeesHoliday](time-off/blocks#addemployeesholiday) | Employee selection screen for assigning employees to a company's holiday pay policy. | diff --git a/docs/reference/index.mdx b/docs/reference/index.mdx index 4ade1effe..1403c7dfb 100644 --- a/docs/reference/index.mdx +++ b/docs/reference/index.mdx @@ -12,7 +12,7 @@ custom_edit_url: null ## Browse by domain - + --- diff --git a/docs/reference/payroll/blocks.md b/docs/reference/payroll/blocks.md index 0af8d1198..7198bae0d 100644 --- a/docs/reference/payroll/blocks.md +++ b/docs/reference/payroll/blocks.md @@ -736,6 +736,55 @@ _Inherits `children`, `className`, `defaultValues`, `FallbackComponent`, `Loader *** + + +## PrintChecks + +Displays a banner prompting the user to print checks for employees paid by check on a +processed payroll, and walks them through choosing check stock and generating the check PDF. + +
+ +### PrintChecksProps + + + +Props for [PrintChecks](#printchecks). + +| Property | Type | Description | +| ------ | ------ | ------ | +| `companyId` | `string` | Identifier of the company that owns the payroll. | +| `payrollId` | `string` | Identifier of the payroll to generate printable checks for. | +| `onEvent?` | [`OnEventType`](../events.md#oneventtype)\<[`EventType`](../events.md#eventtype), `unknown`\> | Callback invoked each time the component emits an event. | + +_Inherits `children`, `className`, `defaultValues`, `dictionary`, `FallbackComponent`, `LoaderComponent` from Omit._ + +
+ +### Events + +| Event | Description | Data | +| ----- | ----------- | ---- | +| `payroll/printChecks/start` | User opened the print-checks modal from the banner | — | +| `payroll/printChecks/generate/start` | User submitted the print-checks form | — | +| `payroll/printChecks/generate/succeeded` | Printable checks finished generating | `{ documentUrl }` | +| `payroll/printChecks/generate/failed` | The print-checks request was rejected or generation failed | `{ errorMessage }` | +| `payroll/printChecks/retry` | User retried after a failed generation | — | +| `payroll/printChecks/cancel` | User cancelled the print-checks form | — | +| `payroll/printChecks/close` | User closed the failure or summary screen | — | + +
+ +### Endpoints + +| Method | Path | +| --- | --- | +| GET | [`/v1/companies/:companyId/payrolls/:payrollId`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-v1-companies-company_id-payrolls-payroll_id) | +| GET | [`/v1/generated_documents/:documentType/:requestUuid`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/get-v1-generated_documents-document_type-request_uuid) | +| POST | [`/v1/payrolls/:payrollUuid/generated_documents/printable_payroll_checks`](https://docs.gusto.com/embedded-payroll/v2026-06-15/reference/post-v1-payrolls-payroll_uuid-generated_documents-printable_payroll_checks) | + +*** + ## RecoveryCases diff --git a/docs/reference/payroll/index.mdx b/docs/reference/payroll/index.mdx index 8a97b1413..595d2b00e 100644 --- a/docs/reference/payroll/index.mdx +++ b/docs/reference/payroll/index.mdx @@ -23,4 +23,4 @@ Flows and blocks for running and managing payroll across a company's pay schedul import { Payroll } from '@gusto/embedded-react-sdk' ``` - + diff --git a/docs/reference/payroll/namespace.md b/docs/reference/payroll/namespace.md index d115a11db..c3b44936f 100644 --- a/docs/reference/payroll/namespace.md +++ b/docs/reference/payroll/namespace.md @@ -45,5 +45,6 @@ import { Payroll } from '@gusto/embedded-react-sdk' | [PayrollList](blocks.md#payrolllist) | Lists upcoming payrolls and lets users start running them. | | [PayrollOverview](blocks.md#payrolloverview) | Final review screen for a calculated payroll before submission, with submit, cancel, and edit controls. After submission, tracks processing status and surfaces the receipt and per-employee paystub downloads once complete. | | [PayrollReceipts](blocks.md#payrollreceipts) | Displays a detailed receipt for a completed payroll, including the debited total, per-category breakdown, tax breakdown, and a per-employee summary of payment method, garnishments, reimbursements, taxes, and net pay. | +| [PrintChecks](blocks.md#printchecks) | Displays a banner prompting the user to print checks for employees paid by check on a processed payroll, and walks them through choosing check stock and generating the check PDF. | | [RecoveryCases](blocks.md#recoverycases) | Displays open recovery cases for a company and provides an in-modal resubmit workflow for resolving them. | | [TransitionCreation](blocks.md#transitioncreation) | Creation form for transition payrolls covering the gap between an old and new pay schedule. | diff --git a/sdk-app/src/generated-registry-data.ts b/sdk-app/src/generated-registry-data.ts index 46e52e689..1a196e3fa 100644 --- a/sdk-app/src/generated-registry-data.ts +++ b/sdk-app/src/generated-registry-data.ts @@ -141,6 +141,7 @@ export const ENTITY_REQUIREMENTS: Record = { 'Payroll.PayrollList': ['companyId'], 'Payroll.PayrollOverview': ['companyId', 'payrollId'], 'Payroll.PayrollReceipts': ['payrollId'], + 'Payroll.PrintChecks': ['companyId', 'payrollId'], 'Payroll.RecoveryCases': ['companyId'], 'Payroll.TransitionCreation': ['companyId'], 'Payroll.TransitionFlow': ['companyId'], diff --git a/src/components/Payroll/PrintChecks/PrintChecks.test.tsx b/src/components/Payroll/PrintChecks/PrintChecks.test.tsx new file mode 100644 index 000000000..4ec1acae0 --- /dev/null +++ b/src/components/Payroll/PrintChecks/PrintChecks.test.tsx @@ -0,0 +1,123 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { HttpResponse } from 'msw' +import { PrintChecks } from './PrintChecks' +import { + handlePayrollsGeneratePrintableChecks, + handleGeneratedDocumentsGet, + createPayrollCheck, + createGeneratedDocument, +} from '@/test/mocks/apis/printable_payroll_checks' +import { server } from '@/test/mocks/server' +import { renderWithProviders } from '@/test-utils/renderWithProviders' +import { printChecksEvents } from '@/shared/constants' + +const checkCompensation = { + employeeUuid: 'emp-check-1', + excluded: false, + paymentMethod: 'Check', +} + +vi.mock('@gusto/embedded-api/react-query/payrollsGet', () => ({ + usePayrollsGet: () => ({ + data: { + payrollShow: { + processed: true, + employeeCompensations: [checkCompensation], + }, + }, + }), +})) + +describe('PrintChecks', () => { + const onEvent = vi.fn() + const user = userEvent.setup() + + const defaultProps = { + companyId: 'company-1', + payrollId: 'payroll-1', + onEvent, + } + + beforeEach(() => { + vi.clearAllMocks() + // The download is triggered via a synthetic anchor click rather than a real navigation — + // jsdom throws "Not implemented: navigation" if this isn't stubbed. + vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => {}) + }) + + it('opens the form from the banner CTA and cancels back to the banner', async () => { + renderWithProviders() + + await user.click(await screen.findByRole('button', { name: 'View and print checks' })) + + expect(await screen.findByText('Choose check stock')).toBeInTheDocument() + expect(onEvent).toHaveBeenCalledWith(printChecksEvents.PRINT_CHECKS_START, undefined) + + await user.click(screen.getByRole('button', { name: 'Cancel' })) + + await waitFor(() => { + expect(screen.queryByText('Choose check stock')).toBeNull() + }) + }) + + it('walks through a successful generate flow to the summary screen and back', async () => { + server.use( + handlePayrollsGeneratePrintableChecks(() => + HttpResponse.json(createPayrollCheck(), { status: 200 }), + ), + ) + server.use( + handleGeneratedDocumentsGet(() => + HttpResponse.json( + createGeneratedDocument({ + status: 'succeeded', + document_urls: ['https://example.com/checks.pdf'], + }), + ), + ), + ) + + renderWithProviders() + + await user.click(await screen.findByRole('button', { name: 'View and print checks' })) + await user.click(screen.getByRole('button', { name: 'View checks' })) + + expect(await screen.findByText('Your checks are ready')).toBeInTheDocument() + expect(screen.getByRole('link', { name: 'View checks' })).toHaveAttribute( + 'href', + 'https://example.com/checks.pdf', + ) + + await user.click(screen.getByRole('button', { name: 'Close' })) + + await waitFor(() => { + expect(screen.queryByText('Your checks are ready')).toBeNull() + }) + }) + + it('walks through a failed generate flow and allows retrying', async () => { + server.use( + handlePayrollsGeneratePrintableChecks(() => + HttpResponse.json(createPayrollCheck(), { status: 200 }), + ), + ) + server.use( + handleGeneratedDocumentsGet(() => + HttpResponse.json(createGeneratedDocument({ status: 'failed', document_urls: [] })), + ), + ) + + renderWithProviders() + + await user.click(await screen.findByRole('button', { name: 'View and print checks' })) + await user.click(screen.getByRole('button', { name: 'View checks' })) + + expect(await screen.findByText("We couldn't generate your checks")).toBeInTheDocument() + + await user.click(screen.getByRole('button', { name: 'Try again' })) + + expect(await screen.findByText('Choose check stock')).toBeInTheDocument() + }) +}) diff --git a/src/components/Payroll/PrintChecks/PrintChecks.tsx b/src/components/Payroll/PrintChecks/PrintChecks.tsx new file mode 100644 index 000000000..ac39353d1 --- /dev/null +++ b/src/components/Payroll/PrintChecks/PrintChecks.tsx @@ -0,0 +1,106 @@ +import { createMachine } from 'robot3' +import { useMachine } from 'react-robot' +import { useMemo, useState } from 'react' +import { PrintChecksBanner } from './PrintChecksBanner' +import { printChecksMachine } from './printChecksStateMachine' +import { type PrintChecksContextInterface } from './PrintChecksComponents' +import type { PrintChecksProps } from './types' +import { BaseComponent } from '@/components/Base' +import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' +import { FlowContext } from '@/components/Flow/useFlow' +import { printChecksEvents, type EventType } from '@/shared/constants' + +/** + * Displays a banner prompting the user to print checks for employees paid by check on a + * processed payroll, and walks them through choosing check stock and generating the check PDF. + * + * @events + * | Event | Description | Data | + * | ----- | ----------- | ---- | + * | `payroll/printChecks/start` | User opened the print-checks modal from the banner | — | + * | `payroll/printChecks/generate/start` | User submitted the print-checks form | — | + * | `payroll/printChecks/generate/succeeded` | Printable checks finished generating | `{ documentUrl }` | + * | `payroll/printChecks/generate/failed` | The print-checks request was rejected or generation failed | `{ errorMessage }` | + * | `payroll/printChecks/retry` | User retried after a failed generation | — | + * | `payroll/printChecks/cancel` | User cancelled the print-checks form | — | + * | `payroll/printChecks/close` | User closed the failure or summary screen | — | + * + * @param props - {@link PrintChecksProps} + * @returns The print-checks banner and modal flow. + * @public + */ +export function PrintChecks({ onEvent = () => {}, ...props }: PrintChecksProps) { + return ( + + + + ) +} + +function Root({ companyId, payrollId, onEvent = () => {} }: PrintChecksProps) { + const { Modal } = useComponentContext() + const [isModalOpen, setIsModalOpen] = useState(false) + + const printChecksMachineInstance = useMemo( + () => + createMachine('banner', printChecksMachine, (): PrintChecksContextInterface => ({ + component: null, + companyId, + payrollId, + onEvent: handleEvent, + })), + [companyId, payrollId], + ) + const [current, send] = useMachine(printChecksMachineInstance) + + function handleEvent(type: EventType, data?: unknown): void { + send({ type, payload: data }) + + if (type === printChecksEvents.PRINT_CHECKS_START) { + setIsModalOpen(true) + } + + if ( + type === printChecksEvents.PRINT_CHECKS_CANCEL || + type === printChecksEvents.PRINT_CHECKS_CLOSE + ) { + setIsModalOpen(false) + } + + onEvent(type, data) + } + + const handleStartPrintChecks = () => { + handleEvent(printChecksEvents.PRINT_CHECKS_START) + } + + const handleCloseModal = () => { + setIsModalOpen(false) + } + + const CurrentComponent = current.context.component + const Footer = CurrentComponent?.Footer || undefined + + return ( + + + } + > + {CurrentComponent && } + + + ) +} diff --git a/src/components/Payroll/PrintChecks/PrintChecksComponents.tsx b/src/components/Payroll/PrintChecks/PrintChecksComponents.tsx new file mode 100644 index 000000000..e3c4e2b74 --- /dev/null +++ b/src/components/Payroll/PrintChecks/PrintChecksComponents.tsx @@ -0,0 +1,61 @@ +import { PrintChecksForm } from './PrintChecksForm' +import { PrintChecksFailure } from './PrintChecksFailure' +import { PrintChecksSummary } from './PrintChecksSummary' +import { useFlow } from '@/components/Flow/useFlow' +import type { FlowContextInterface } from '@/components/Flow/useFlow' +import type { CommonComponentInterface } from '@/components/Base' +import type { EventType } from '@/types/Helpers' +import type { OnEventType } from '@/components/Base/useBase' + +/** + * Flow-machine context shared across the print-checks states. + * + * @internal + */ +export interface PrintChecksContextInterface extends FlowContextInterface { + /** Company identifier. */ + companyId: string + /** Payroll being printed. */ + payrollId: string + /** URL of the generated checks PDF, once generation succeeds. */ + documentUrl?: string + /** Error message surfaced on the failure screen. */ + errorMessage?: string + /** Whether a generate-and-poll cycle is in flight, shared between the form body and its footer. */ + isGenerating?: boolean + /** Component to render inside the modal for the current state, with an optional footer slot. */ + component: + | (React.ComponentType & { + Footer?: React.ComponentType<{ + onEvent: OnEventType + }> + }) + | null +} + +/** @internal */ +export function PrintChecksFormContextual() { + const { payrollId, isGenerating, onEvent } = useFlow() + + return +} + +PrintChecksFormContextual.Footer = PrintChecksForm.Footer + +/** @internal */ +export function PrintChecksFailureContextual() { + const { errorMessage, onEvent } = useFlow() + + return +} + +PrintChecksFailureContextual.Footer = PrintChecksFailure.Footer + +/** @internal */ +export function PrintChecksSummaryContextual() { + const { documentUrl, onEvent } = useFlow() + + return +} + +PrintChecksSummaryContextual.Footer = PrintChecksSummary.Footer diff --git a/src/components/Payroll/PrintChecks/index.ts b/src/components/Payroll/PrintChecks/index.ts new file mode 100644 index 000000000..4bc806098 --- /dev/null +++ b/src/components/Payroll/PrintChecks/index.ts @@ -0,0 +1,2 @@ +export { PrintChecks } from './PrintChecks' +export type { PrintChecksProps } from './types' diff --git a/src/components/Payroll/PrintChecks/printChecksStateMachine.tsx b/src/components/Payroll/PrintChecks/printChecksStateMachine.tsx new file mode 100644 index 000000000..612451835 --- /dev/null +++ b/src/components/Payroll/PrintChecks/printChecksStateMachine.tsx @@ -0,0 +1,135 @@ +import { state, transition, reduce } from 'robot3' +import type { PrintChecksContextInterface } from './PrintChecksComponents' +import { + PrintChecksFormContextual, + PrintChecksFailureContextual, + PrintChecksSummaryContextual, +} from './PrintChecksComponents' +import { printChecksEvents } from '@/shared/constants' +import type { MachineEventType, MachineTransition } from '@/types/Helpers' + +/** + * Payload shapes for each print-checks state machine event. + * + * @internal + */ +export type EventPayloads = { + /** Banner CTA pressed to begin the print-checks flow. */ + [printChecksEvents.PRINT_CHECKS_START]: undefined + /** Form submitted; a generate-and-poll cycle has started. */ + [printChecksEvents.PRINT_CHECKS_GENERATE_START]: undefined + /** Generation succeeded; carries the generated checks document URL. */ + [printChecksEvents.PRINT_CHECKS_GENERATE_SUCCEEDED]: { + documentUrl: string | null + } + /** Generation failed; carries the error message to surface. */ + [printChecksEvents.PRINT_CHECKS_GENERATE_FAILED]: { + errorMessage: string | null + } + /** User retried after a failure. */ + [printChecksEvents.PRINT_CHECKS_RETRY]: undefined + /** Form cancelled. */ + [printChecksEvents.PRINT_CHECKS_CANCEL]: undefined + /** Failure or summary screen closed. */ + [printChecksEvents.PRINT_CHECKS_CLOSE]: undefined +} + +/** @internal */ +export const printChecksMachine = { + banner: state( + transition( + printChecksEvents.PRINT_CHECKS_START, + 'form', + reduce((ctx: PrintChecksContextInterface): PrintChecksContextInterface => ({ + ...ctx, + component: PrintChecksFormContextual, + })), + ), + ), + form: state( + transition( + printChecksEvents.PRINT_CHECKS_GENERATE_START, + 'form', + reduce((ctx: PrintChecksContextInterface): PrintChecksContextInterface => ({ + ...ctx, + isGenerating: true, + })), + ), + transition( + printChecksEvents.PRINT_CHECKS_GENERATE_SUCCEEDED, + 'summary', + reduce( + ( + ctx: PrintChecksContextInterface, + ev: MachineEventType< + EventPayloads, + typeof printChecksEvents.PRINT_CHECKS_GENERATE_SUCCEEDED + >, + ): PrintChecksContextInterface => ({ + ...ctx, + component: PrintChecksSummaryContextual, + documentUrl: ev.payload.documentUrl ?? undefined, + isGenerating: false, + }), + ), + ), + transition( + printChecksEvents.PRINT_CHECKS_GENERATE_FAILED, + 'failure', + reduce( + ( + ctx: PrintChecksContextInterface, + ev: MachineEventType< + EventPayloads, + typeof printChecksEvents.PRINT_CHECKS_GENERATE_FAILED + >, + ): PrintChecksContextInterface => ({ + ...ctx, + component: PrintChecksFailureContextual, + errorMessage: ev.payload.errorMessage ?? undefined, + isGenerating: false, + }), + ), + ), + transition( + printChecksEvents.PRINT_CHECKS_CANCEL, + 'banner', + reduce((ctx: PrintChecksContextInterface): PrintChecksContextInterface => ({ + ...ctx, + component: null, + isGenerating: false, + })), + ), + ), + failure: state( + transition( + printChecksEvents.PRINT_CHECKS_RETRY, + 'form', + reduce((ctx: PrintChecksContextInterface): PrintChecksContextInterface => ({ + ...ctx, + component: PrintChecksFormContextual, + errorMessage: undefined, + })), + ), + transition( + printChecksEvents.PRINT_CHECKS_CLOSE, + 'banner', + reduce((ctx: PrintChecksContextInterface): PrintChecksContextInterface => ({ + ...ctx, + component: null, + errorMessage: undefined, + })), + ), + ), + summary: state( + transition( + printChecksEvents.PRINT_CHECKS_CLOSE, + 'banner', + reduce((ctx: PrintChecksContextInterface): PrintChecksContextInterface => ({ + ...ctx, + component: null, + documentUrl: undefined, + })), + ), + ), +} diff --git a/src/components/Payroll/PrintChecks/types.ts b/src/components/Payroll/PrintChecks/types.ts new file mode 100644 index 000000000..9bc1cacbc --- /dev/null +++ b/src/components/Payroll/PrintChecks/types.ts @@ -0,0 +1,15 @@ +import type { BaseComponentInterface } from '@/components/Base' + +/** + * Props for {@link PrintChecks}. + * + * @public + */ +export interface PrintChecksProps extends Omit, 'onEvent'> { + /** Identifier of the company that owns the payroll. */ + companyId: string + /** Identifier of the payroll to generate printable checks for. */ + payrollId: string + /** Callback invoked each time the component emits an event. */ + onEvent?: BaseComponentInterface['onEvent'] +} diff --git a/src/components/Payroll/index.ts b/src/components/Payroll/index.ts index 37d306da1..06e79deec 100644 --- a/src/components/Payroll/index.ts +++ b/src/components/Payroll/index.ts @@ -38,6 +38,8 @@ export { PayrollBlockerList, type ApiPayrollBlocker } from './PayrollBlocker' export type { PayrollBlockerListProps } from './PayrollBlocker/components/PayrollBlockerList' export { RecoveryCases } from './RecoveryCases/RecoveryCases' export type { RecoveryCasesProps } from './RecoveryCases/RecoveryCases' +export { PrintChecks } from './PrintChecks/PrintChecks' +export type { PrintChecksProps } from './PrintChecks' export type { OffCyclePayPeriodDateFormData, OffCyclePayrollDateType,