Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions docs/reference/endpoint-inventory.json
Original file line number Diff line number Diff line change
Expand Up @@ -2636,24 +2636,29 @@
"Employee.EmployeeListFlow": {
"blocks": [
"Employee.DashboardFlow",
"Employee.OnboardingFlow",
"Employee.OnboardingExecutionFlow",
"Employee.TerminationFlow",
"EmployeeManagement.EmployeeList"
]
},
"Employee.OnboardingFlow": {
"Employee.OnboardingExecutionFlow": {
"blocks": [
"Employee.Compensation",
"Employee.Deductions",
"Employee.EmployeeDocuments",
"Employee.EmployeeList",
"Employee.OnboardingSummary",
"Employee.PaymentMethod",
"Employee.Profile",
"EmployeeOnboarding.FederalTaxes",
"EmployeeOnboarding.StateTaxes"
]
},
"Employee.OnboardingFlow": {
"blocks": [
"Employee.EmployeeList",
"Employee.OnboardingExecutionFlow"
]
},
"Employee.SelfOnboardingFlow": {
"blocks": [
"Employee.DocumentSigner",
Expand Down Expand Up @@ -2692,7 +2697,7 @@
"EmployeeManagement.DashboardFlow",
"EmployeeManagement.EmployeeList",
"EmployeeManagement.TerminationFlow",
"EmployeeOnboarding.OnboardingFlow"
"EmployeeOnboarding.OnboardingExecutionFlow"
]
},
"EmployeeManagement.TerminationFlow": {
Expand All @@ -2703,19 +2708,24 @@
"Payroll.PayrollLanding"
]
},
"EmployeeOnboarding.OnboardingFlow": {
"EmployeeOnboarding.OnboardingExecutionFlow": {
"blocks": [
"Employee.EmployeeDocuments",
"Employee.PaymentMethod",
"EmployeeOnboarding.Compensation",
"EmployeeOnboarding.Deductions",
"EmployeeOnboarding.EmployeeList",
"EmployeeOnboarding.FederalTaxes",
"EmployeeOnboarding.OnboardingSummary",
"EmployeeOnboarding.Profile",
"EmployeeOnboarding.StateTaxes"
]
},
"EmployeeOnboarding.OnboardingFlow": {
"blocks": [
"EmployeeOnboarding.EmployeeList",
"EmployeeOnboarding.OnboardingExecutionFlow"
]
},
"EmployeeOnboarding.SelfOnboardingFlow": {
"blocks": [
"Employee.PaymentMethod",
Expand Down
10 changes: 6 additions & 4 deletions docs/reference/endpoint-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -489,14 +489,16 @@ Flows compose multiple blocks into a single workflow. The endpoint list for a fl
| **Contractor.PaymentFlow** | Contractor.CreatePayment, Contractor.PaymentHistory, Contractor.PaymentStatement, Contractor.PaymentSummary, Contractor.PaymentsList, InformationRequests.InformationRequestsFlow |
| **ContractorOnboarding.OnboardingFlow** | ContractorOnboarding.Address, ContractorOnboarding.ContractorList, ContractorOnboarding.ContractorProfile, ContractorOnboarding.ContractorSubmit, ContractorOnboarding.NewHireReport, ContractorOnboarding.PaymentMethod |
| **Employee.DashboardFlow** | Employee.Compensation, Employee.Deductions, Employee.HomeAddress, Employee.PaymentMethod, Employee.WorkAddress, EmployeeManagement.DocumentManager, EmployeeManagement.FederalTaxes, EmployeeManagement.Profile, EmployeeManagement.StateTaxes, EmployeeOnboarding.PaymentMethod |
| **Employee.EmployeeListFlow** | Employee.DashboardFlow, Employee.OnboardingFlow, Employee.TerminationFlow, EmployeeManagement.EmployeeList |
| **Employee.OnboardingFlow** | Employee.Compensation, Employee.Deductions, Employee.EmployeeDocuments, Employee.EmployeeList, Employee.OnboardingSummary, Employee.PaymentMethod, Employee.Profile, EmployeeOnboarding.FederalTaxes, EmployeeOnboarding.StateTaxes |
| **Employee.EmployeeListFlow** | Employee.DashboardFlow, Employee.OnboardingExecutionFlow, Employee.TerminationFlow, EmployeeManagement.EmployeeList |
| **Employee.OnboardingExecutionFlow** | Employee.Compensation, Employee.Deductions, Employee.EmployeeDocuments, Employee.OnboardingSummary, Employee.PaymentMethod, Employee.Profile, EmployeeOnboarding.FederalTaxes, EmployeeOnboarding.StateTaxes |
| **Employee.OnboardingFlow** | Employee.EmployeeList, Employee.OnboardingExecutionFlow |
| **Employee.SelfOnboardingFlow** | Employee.DocumentSigner, Employee.Landing, Employee.OnboardingSummary, Employee.PaymentMethod, Employee.Profile, EmployeeOnboarding.FederalTaxes, EmployeeOnboarding.StateTaxes |
| **Employee.TerminationFlow** | Employee.TerminateEmployee, Employee.TerminationSummary, Payroll.DismissalFlow, Payroll.PayrollLanding |
| **EmployeeManagement.DashboardFlow** | Employee.PaymentMethod, EmployeeManagement.DocumentManager, EmployeeManagement.FederalTaxes, EmployeeManagement.HomeAddress, EmployeeManagement.Profile, EmployeeManagement.StateTaxes, EmployeeManagement.WorkAddress, EmployeeOnboarding.Compensation, EmployeeOnboarding.Deductions, EmployeeOnboarding.PaymentMethod |
| **EmployeeManagement.EmployeeListFlow** | EmployeeManagement.DashboardFlow, EmployeeManagement.EmployeeList, EmployeeManagement.TerminationFlow, EmployeeOnboarding.OnboardingFlow |
| **EmployeeManagement.EmployeeListFlow** | EmployeeManagement.DashboardFlow, EmployeeManagement.EmployeeList, EmployeeManagement.TerminationFlow, EmployeeOnboarding.OnboardingExecutionFlow |
| **EmployeeManagement.TerminationFlow** | EmployeeManagement.TerminateEmployee, EmployeeManagement.TerminationSummary, Payroll.DismissalFlow, Payroll.PayrollLanding |
| **EmployeeOnboarding.OnboardingFlow** | Employee.EmployeeDocuments, Employee.PaymentMethod, EmployeeOnboarding.Compensation, EmployeeOnboarding.Deductions, EmployeeOnboarding.EmployeeList, EmployeeOnboarding.FederalTaxes, EmployeeOnboarding.OnboardingSummary, EmployeeOnboarding.Profile, EmployeeOnboarding.StateTaxes |
| **EmployeeOnboarding.OnboardingExecutionFlow** | Employee.EmployeeDocuments, Employee.PaymentMethod, EmployeeOnboarding.Compensation, EmployeeOnboarding.Deductions, EmployeeOnboarding.FederalTaxes, EmployeeOnboarding.OnboardingSummary, EmployeeOnboarding.Profile, EmployeeOnboarding.StateTaxes |
| **EmployeeOnboarding.OnboardingFlow** | EmployeeOnboarding.EmployeeList, EmployeeOnboarding.OnboardingExecutionFlow |
| **EmployeeOnboarding.SelfOnboardingFlow** | Employee.PaymentMethod, EmployeeOnboarding.DocumentSigner, EmployeeOnboarding.FederalTaxes, EmployeeOnboarding.Landing, EmployeeOnboarding.OnboardingSummary, EmployeeOnboarding.Profile, EmployeeOnboarding.StateTaxes |
| **InformationRequests.InformationRequestsFlow** | InformationRequests.InformationRequestForm, InformationRequests.InformationRequestList |
| **Payroll.DismissalFlow** | Payroll.PayrollExecutionFlow |
Expand Down
1 change: 1 addition & 0 deletions sdk-app/src/generated-registry-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const ENTITY_REQUIREMENTS: Record<string, string[]> = {
'EmployeeOnboarding.EmploymentEligibility': ['employeeId'],
'EmployeeOnboarding.FederalTaxes': ['employeeId'],
'EmployeeOnboarding.Landing': ['employeeId', 'companyId'],
'EmployeeOnboarding.OnboardingExecutionFlow': ['companyId'],
'EmployeeOnboarding.OnboardingFlow': ['companyId'],
'EmployeeOnboarding.OnboardingSummary': ['employeeId'],
'EmployeeOnboarding.PaymentMethod': ['employeeId'],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { beforeEach, describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { EmployeeListFlow } from './EmployeeListFlow'
import { server } from '@/test/mocks/server'
import { GustoProvider } from '@/contexts'
import { API_BASE_URL } from '@/test/constants'
import {
createEmployee,
getCompanyEmployees,
getEmployee,
getEmployeeOnboardingStatus,
} from '@/test/mocks/apis/employees'
import { getCompany } from '@/test/mocks/apis/company'
import { getCompanyLocations } from '@/test/mocks/apis/company_locations'
import { getEmployeeWorkAddresses } from '@/test/mocks/apis/employee_work_addresses'
import { getEmployeeHomeAddresses } from '@/test/mocks/apis/employee_home_addresses'

describe('EmployeeListFlow', () => {
beforeEach(() => {
server.use(
getCompanyEmployees('123'),
getEmployee,
getCompany,
getCompanyLocations,
getEmployeeWorkAddresses,
getEmployeeHomeAddresses,
getEmployeeOnboardingStatus,
createEmployee,
)
})

it('renders the management list initially', async () => {
render(
<GustoProvider config={{ baseUrl: API_BASE_URL }}>
<EmployeeListFlow companyId="123" onEvent={() => {}} />
</GustoProvider>,
)

await screen.findByRole('button', { name: /Add/i })
expect(await screen.findByText(/Maximus/i)).toBeInTheDocument()
})

it('lands on the Profile step when adding an employee — skips the redundant onboarding list', async () => {
const user = userEvent.setup()
render(
<GustoProvider config={{ baseUrl: API_BASE_URL }}>
<EmployeeListFlow companyId="123" onEvent={() => {}} />
</GustoProvider>,
)

await user.click(await screen.findByRole('button', { name: /Add/i }))

await screen.findByLabelText(/social/i)
expect(screen.getByLabelText(/first name/i)).toBeInTheDocument()
expect(screen.getByLabelText(/last name/i)).toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ManagementEmployeeList } from '../EmployeeList/management/ManagementEmployeeList'
import { DashboardFlow } from '../Dashboard'
import { TerminationFlow } from '../Terminations/TerminationFlow/TerminationFlow'
import { OnboardingFlow } from '../OnboardingFlow/OnboardingFlow'
import { OnboardingExecutionFlow } from '../OnboardingExecutionFlow/OnboardingExecutionFlow'
import { useFlow, type FlowContextInterface } from '@/components/Flow/useFlow'
import type { BaseComponentInterface } from '@/components/Base'
import { ensureRequired } from '@/helpers/ensureRequired'
Expand Down Expand Up @@ -36,7 +36,7 @@ export function TerminationFlowContextual() {
)
}

export function OnboardingFlowContextual() {
export function OnboardingExecutionFlowContextual() {
const { companyId, onEvent } = useFlow<EmployeeListFlowContextInterface>()
return <OnboardingFlow companyId={ensureRequired(companyId)} onEvent={onEvent} />
return <OnboardingExecutionFlow companyId={ensureRequired(companyId)} onEvent={onEvent} />
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { transition, reduce, state } from 'robot3'
import {
DashboardFlowContextual,
EmployeeListContextual,
OnboardingFlowContextual,
OnboardingExecutionFlowContextual,
TerminationFlowContextual,
type EmployeeListFlowContextInterface,
} from './EmployeeListFlowComponents'
Expand Down Expand Up @@ -71,7 +71,7 @@ export const employeeListStateMachine = {
reduce(
(ctx: EmployeeListFlowContextInterface): EmployeeListFlowContextInterface => ({
...ctx,
component: OnboardingFlowContextual,
component: OnboardingExecutionFlowContextual,
header: backToListHeader,
}),
),
Expand All @@ -85,5 +85,7 @@ export const employeeListStateMachine = {
),
onboard: state<MachineTransition>(
transition(componentEvents.EMPLOYEE_RETURN_TO_LIST, 'list', returnToList),
transition(componentEvents.EMPLOYEES_LIST, 'list', returnToList),
transition(componentEvents.CANCEL, 'list', returnToList),
),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { createMachine } from 'robot3'
import { useMemo } from 'react'
import {
onboardingExecutionMachine,
INITIAL_COMPONENT_MAP,
type OnboardingExecutionInitialState,
} from './onboardingExecutionStateMachine'
import {
type OnboardingContextInterface,
type OnboardingDefaultValues,
} from './OnboardingExecutionFlowComponents'
import { Flow } from '@/components/Flow/Flow'
import type { OnEventType } from '@/components/Base/useBase'
import type { EventType, EmployeeOnboardingStatus } from '@/shared/constants'

export interface OnboardingExecutionFlowProps {
companyId: string
onEvent: OnEventType<EventType, unknown>
initialState?: OnboardingExecutionInitialState
initialEmployeeId?: string
initialOnboardingStatus?: (typeof EmployeeOnboardingStatus)[keyof typeof EmployeeOnboardingStatus]
defaultValues?: OnboardingDefaultValues
isAdmin?: boolean
isSelfOnboardingEnabled?: boolean
withEmployeeI9?: boolean
}

export function OnboardingExecutionFlow({
companyId,
onEvent,
initialState = 'employeeProfile',
initialEmployeeId,
initialOnboardingStatus,
defaultValues,
isAdmin = true,
isSelfOnboardingEnabled = true,
withEmployeeI9 = false,
}: OnboardingExecutionFlowProps) {
const machine = useMemo(
() =>
createMachine(
initialState,
onboardingExecutionMachine,
(initialContext: OnboardingContextInterface) => ({
...initialContext,
component: INITIAL_COMPONENT_MAP[initialState],
companyId,
employeeId: initialEmployeeId,
onboardingStatus: initialOnboardingStatus,
defaultValues,
isAdmin,
isSelfOnboardingEnabled,
withEmployeeI9,
}),
),
[
companyId,
initialState,
initialEmployeeId,
initialOnboardingStatus,
defaultValues,
isAdmin,
isSelfOnboardingEnabled,
withEmployeeI9,
],
)

return <Flow machine={machine} onEvent={onEvent} />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { PaymentMethodBankAccount } from '@gusto/embedded-api-v-2025-11-15/models/components/paymentmethodbankaccount'
import { Deductions } from '../Deductions/Deductions'
import { FederalTaxes } from '../FederalTaxes/onboarding/FederalTaxes'
import { StateTaxes } from '../StateTaxes/onboarding/StateTaxes'
import type { ProfileDefaultValues } from '../Profile/onboarding/Profile'
import type { CompensationDefaultValues } from '../Compensation'
import { ensureRequired } from '@/helpers/ensureRequired'
import { useFlow, type FlowContextInterface } from '@/components/Flow/useFlow'
import type { EmployeeOnboardingStatus } from '@/shared/constants'
import type { RequireAtLeastOne } from '@/types/Helpers'

export type OnboardingDefaultValues = RequireAtLeastOne<{
profile?: ProfileDefaultValues
compensation?: CompensationDefaultValues
}>

export interface OnboardingContextInterface extends FlowContextInterface {
companyId: string
employeeId?: string
isAdmin?: boolean
onboardingStatus?: (typeof EmployeeOnboardingStatus)[keyof typeof EmployeeOnboardingStatus]
startDate?: string
paymentMethod?: PaymentMethodBankAccount
defaultValues?: OnboardingDefaultValues
isSelfOnboardingEnabled?: boolean
withEmployeeI9?: boolean
}

export function FederalTaxesContextual() {
const { employeeId, onEvent } = useFlow<OnboardingContextInterface>()
return <FederalTaxes onEvent={onEvent} employeeId={ensureRequired(employeeId)} />
}

export function StateTaxesContextual() {
const { employeeId, onEvent, isAdmin } = useFlow<OnboardingContextInterface>()
return <StateTaxes onEvent={onEvent} employeeId={ensureRequired(employeeId)} isAdmin={isAdmin} />
}

export function DeductionsContextual() {
const { employeeId, onEvent } = useFlow<OnboardingContextInterface>()
return <Deductions onEvent={onEvent} employeeId={ensureRequired(employeeId)} />
}
12 changes: 12 additions & 0 deletions src/components/Employee/OnboardingExecutionFlow/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export {
OnboardingExecutionFlow,
type OnboardingExecutionFlowProps,
} from './OnboardingExecutionFlow'
export {
onboardingExecutionMachine,
type OnboardingExecutionInitialState,
} from './onboardingExecutionStateMachine'
export type {
OnboardingContextInterface,
OnboardingDefaultValues,
} from './OnboardingExecutionFlowComponents'
Loading
Loading