diff --git a/package-lock.json b/package-lock.json index 78656f7818..5a85b28e5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,8 +23,6 @@ "react-error-boundary": "^6.1.3", "react-hook-form": "^7.85.0", "react-i18next": "^17.0.11", - "react-robot": "^1.2.1", - "robot3": "^1.2.0", "zod": "^4.3.6" }, "devDependencies": { @@ -23239,19 +23237,6 @@ "dev": true, "license": "MIT" }, - "node_modules/react-robot": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/react-robot/-/react-robot-1.2.1.tgz", - "integrity": "sha512-FGX25Z1VFLxB05uFLRqg+MUqtcv1ZiugNjdIu35EYcJ0zDoc40H6yKi4VrEq+v49YTAa14khgTzRb+IM8YG/LA==", - "license": "BSD-2-Clause", - "dependencies": { - "robot-hooks": "^1.1.0" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18.2.0 || ^19.0.0", - "robot3": "^1.0.0" - } - }, "node_modules/react-router": { "version": "7.18.2", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.2.tgz", @@ -23851,21 +23836,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/robot-hooks": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/robot-hooks/-/robot-hooks-1.1.0.tgz", - "integrity": "sha512-42LgnUjW0gL0CZw9v9GJz+JtjAG4L+IluuhlA0jRgmYH1L+JqcyKKRQ4RSrZgyFJcStOYPKSqd5GneCDkdzZhw==", - "license": "BSD-2-Clause", - "peerDependencies": { - "robot3": "^1.0.2" - } - }, - "node_modules/robot3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/robot3/-/robot3-1.2.0.tgz", - "integrity": "sha512-Xin8KHqCKrD9Rqk1ZzZQYjsb6S9DRggcfwBqnVPeM3DLtNCJLxWWTrPJDYm3E+ZiTO7H3VMdgyPSkIbuYnYP2Q==", - "license": "BSD-2-Clause" - }, "node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", diff --git a/package.json b/package.json index 2139e2bcba..8342ec0259 100644 --- a/package.json +++ b/package.json @@ -198,8 +198,6 @@ "react-error-boundary": "^6.1.3", "react-hook-form": "^7.85.0", "react-i18next": "^17.0.11", - "react-robot": "^1.2.1", - "robot3": "^1.2.0", "zod": "^4.3.6" }, "sideEffects": [ diff --git a/sdk-app/src/design/prototypes/agent-payments/AgentPaymentsFlow.tsx b/sdk-app/src/design/prototypes/agent-payments/AgentPaymentsFlow.tsx index 199a17bcca..5e2b159311 100644 --- a/sdk-app/src/design/prototypes/agent-payments/AgentPaymentsFlow.tsx +++ b/sdk-app/src/design/prototypes/agent-payments/AgentPaymentsFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { agentPaymentsMachine } from './agentPaymentsStateMachine' import type { @@ -6,6 +5,7 @@ import type { AgentPaymentsFlowContextInterface, } from './AgentPaymentsFlowComponents' import { AgentPaymentsListContextual } from './AgentPaymentsFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' export const AgentPaymentsFlow = ({ companyId, onEvent }: AgentPaymentsFlowProps) => { diff --git a/sdk-app/src/design/prototypes/agent-payments/agentPaymentsStateMachine.ts b/sdk-app/src/design/prototypes/agent-payments/agentPaymentsStateMachine.ts index b324a0d740..9248fbaf90 100644 --- a/sdk-app/src/design/prototypes/agent-payments/agentPaymentsStateMachine.ts +++ b/sdk-app/src/design/prototypes/agent-payments/agentPaymentsStateMachine.ts @@ -1,10 +1,10 @@ -import { transition, reduce, state } from 'robot3' import { AgentPaymentsListContextual, AgentPaymentDetailContextual, type AgentPaymentsFlowContextInterface, } from './AgentPaymentsFlowComponents' import { agentPaymentsEvents } from './events' +import { transition, reduce, state } from '@/lib/state-machine' import type { MachineTransition } from '@/types/Helpers' const createReducer = (props: Partial) => { diff --git a/sdk-app/src/design/prototypes/contractor-management/ContractorProfile/contractorProfileStateMachine.ts b/sdk-app/src/design/prototypes/contractor-management/ContractorProfile/contractorProfileStateMachine.ts index 3b5aae91f3..ce79d41b6a 100644 --- a/sdk-app/src/design/prototypes/contractor-management/ContractorProfile/contractorProfileStateMachine.ts +++ b/sdk-app/src/design/prototypes/contractor-management/ContractorProfile/contractorProfileStateMachine.ts @@ -1,4 +1,3 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { ContractorProfileContextInterface } from './ContractorProfileComponents' import { @@ -9,6 +8,7 @@ import { EditCompensationContextual, EditBasicDetailsContextual, } from './ContractorProfileComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/sdk-app/src/design/prototypes/contractor-management/ContractorProfile/index.tsx b/sdk-app/src/design/prototypes/contractor-management/ContractorProfile/index.tsx index 7e98ca9cf1..8a934c8d24 100644 --- a/sdk-app/src/design/prototypes/contractor-management/ContractorProfile/index.tsx +++ b/sdk-app/src/design/prototypes/contractor-management/ContractorProfile/index.tsx @@ -1,10 +1,10 @@ import { useMemo } from 'react' import { useOutletContext, useParams } from 'react-router-dom' -import { createMachine } from 'robot3' import type { EntityIds } from '../../../../useEntities' import { contractorProfileStateMachine } from './contractorProfileStateMachine' import type { ContractorProfileContextInterface } from './ContractorProfileComponents' import { ProfileViewContextual } from './ContractorProfileComponents' +import { createMachine } from '@/lib/state-machine' import { EmptyData } from '@/components/Common' import { Flow } from '@/components/Flow/Flow' import { BaseComponent, useBase } from '@/components/Base' diff --git a/sdk-app/src/design/prototypes/tax-filings/TaxFilingsFlow.tsx b/sdk-app/src/design/prototypes/tax-filings/TaxFilingsFlow.tsx index 4f0c5f028b..ff8562a8aa 100644 --- a/sdk-app/src/design/prototypes/tax-filings/TaxFilingsFlow.tsx +++ b/sdk-app/src/design/prototypes/tax-filings/TaxFilingsFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { taxFilingsMachine } from './taxFilingsStateMachine' import type { @@ -6,6 +5,7 @@ import type { TaxFilingsFlowContextInterface, } from './TaxFilingsFlowComponents' import { TaxFilingsListContextual } from './TaxFilingsFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' export const TaxFilingsFlow = ({ companyId, onEvent }: TaxFilingsFlowProps) => { diff --git a/sdk-app/src/design/prototypes/tax-filings/taxFilingsStateMachine.ts b/sdk-app/src/design/prototypes/tax-filings/taxFilingsStateMachine.ts index ac6c9da1c2..9372fe05ab 100644 --- a/sdk-app/src/design/prototypes/tax-filings/taxFilingsStateMachine.ts +++ b/sdk-app/src/design/prototypes/tax-filings/taxFilingsStateMachine.ts @@ -1,10 +1,10 @@ -import { transition, reduce, state } from 'robot3' import { taxFilingsEvents } from './events' import { TaxFilingsListContextual, TaxFilingDetailContextual, type TaxFilingsFlowContextInterface, } from './TaxFilingsFlowComponents' +import { transition, reduce, state } from '@/lib/state-machine' import type { MachineTransition } from '@/types/Helpers' const createReducer = (props: Partial) => { diff --git a/src/components/Common/FlowBreadcrumbs/breadcrumbTransitionHelpers.ts b/src/components/Common/FlowBreadcrumbs/breadcrumbTransitionHelpers.ts index bd3afb2ad8..aa7921f639 100644 --- a/src/components/Common/FlowBreadcrumbs/breadcrumbTransitionHelpers.ts +++ b/src/components/Common/FlowBreadcrumbs/breadcrumbTransitionHelpers.ts @@ -1,4 +1,4 @@ -import { guard, reduce, transition } from 'robot3' +import { guard, reduce, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' type BreadcrumbNavigateEvent = { @@ -8,9 +8,8 @@ type BreadcrumbNavigateEvent = { } } -/* eslint-disable @typescript-eslint/no-unnecessary-type-parameters */ /** - * Builds a factory that produces robot3 transitions handling a + * Builds a factory that produces transitions handling a * `breadcrumb/navigate` event for a given target state. * * @remarks @@ -22,11 +21,10 @@ type BreadcrumbNavigateEvent = { * * @typeParam TContext - The state machine context shape. * @returns A factory `(targetState, canNavigate?) => transition` that emits a - * guarded robot3 transition for the `breadcrumb/navigate` event. + * guarded transition for the `breadcrumb/navigate` event. * @internal */ export const createBreadcrumbNavigateTransition = () => { - /* eslint-enable @typescript-eslint/no-unnecessary-type-parameters */ return (targetState: string, canNavigate?: (ctx: TContext) => boolean) => transition( componentEvents.BREADCRUMB_NAVIGATE, diff --git a/src/components/Company/BankAccount/BankAccount.tsx b/src/components/Company/BankAccount/BankAccount.tsx index 1e1e4ee36b..cc5ab914ec 100644 --- a/src/components/Company/BankAccount/BankAccount.tsx +++ b/src/components/Company/BankAccount/BankAccount.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { useBankAccountsGetSuspense } from '@gusto/embedded-api/react-query/bankAccountsGet' import { @@ -7,6 +6,7 @@ import { } from './BankAccountComponents' import { bankAccountStateMachine } from './stateMachine' import { BankAccountListContextual } from './BankAccountComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseComponent, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Company/BankAccount/stateMachine.ts b/src/components/Company/BankAccount/stateMachine.ts index 6f4729484e..73bf0c137f 100644 --- a/src/components/Company/BankAccount/stateMachine.ts +++ b/src/components/Company/BankAccount/stateMachine.ts @@ -1,10 +1,10 @@ -import { state, transition, reduce } from 'robot3' import type { BankAccountContextInterface, EventPayloads } from './BankAccountComponents' import { BankAccountFormContextual, BankAccountVerifyContextual, BankAccountListContextual, } from './BankAccountComponents' +import { state, transition, reduce } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Company/DocumentSigner/DocumentSigner.tsx b/src/components/Company/DocumentSigner/DocumentSigner.tsx index 5b8b324bbb..84f8584d28 100644 --- a/src/components/Company/DocumentSigner/DocumentSigner.tsx +++ b/src/components/Company/DocumentSigner/DocumentSigner.tsx @@ -1,9 +1,9 @@ -import { createMachine } from 'robot3' import { useSignatoriesListSuspense } from '@gusto/embedded-api/react-query/signatoriesList' import { useMemo } from 'react' import { AssignSignatory, DocumentList } from './documentSignerStateMachine' import { documentSignerMachine } from './stateMachine' import type { DocumentSignerContextInterface } from './useDocumentSigner' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseComponent, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Company/DocumentSigner/assignSignatoryState.tsx b/src/components/Company/DocumentSigner/assignSignatoryState.tsx index ea4524914e..ca283ade1c 100644 --- a/src/components/Company/DocumentSigner/assignSignatoryState.tsx +++ b/src/components/Company/DocumentSigner/assignSignatoryState.tsx @@ -1,7 +1,7 @@ -import { state, transition, reduce } from 'robot3' import type { EventPayloads } from './documentSignerStateMachine' import { DocumentList } from './documentSignerStateMachine' import type { DocumentSignerContextInterface } from './useDocumentSigner' +import { state, transition, reduce } from '@/lib/state-machine' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import { companyEvents } from '@/shared/constants' diff --git a/src/components/Company/DocumentSigner/stateMachine.ts b/src/components/Company/DocumentSigner/stateMachine.ts index cf77279a1a..af8de89246 100644 --- a/src/components/Company/DocumentSigner/stateMachine.ts +++ b/src/components/Company/DocumentSigner/stateMachine.ts @@ -1,8 +1,8 @@ -import { state, transition, reduce } from 'robot3' import type { EventPayloads } from './documentSignerStateMachine' import { SignatureForm, AssignSignatory, DocumentList } from './documentSignerStateMachine' import { assignSignatoryState } from './assignSignatoryState' import type { DocumentSignerContextInterface } from './useDocumentSigner' +import { state, transition, reduce } from '@/lib/state-machine' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import { companyEvents } from '@/shared/constants' diff --git a/src/components/Company/Locations/Locations.tsx b/src/components/Company/Locations/Locations.tsx index 055e945c35..004f0753ab 100644 --- a/src/components/Company/Locations/Locations.tsx +++ b/src/components/Company/Locations/Locations.tsx @@ -1,8 +1,8 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { type LocationsContextInterface } from './locationsStateMachine' import { locationsStateMachine } from './stateMachine' import { LocationsListContextual } from './locationsStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Company/Locations/stateMachine.ts b/src/components/Company/Locations/stateMachine.ts index 61f58c0ae8..cfaad90950 100644 --- a/src/components/Company/Locations/stateMachine.ts +++ b/src/components/Company/Locations/stateMachine.ts @@ -1,6 +1,6 @@ -import { state, transition, reduce } from 'robot3' import type { LocationsContextInterface, EventPayloads } from './locationsStateMachine' import { LocationFormContextual, LocationsListContextual } from './locationsStateMachine' +import { state, transition, reduce } from '@/lib/state-machine' import { companyEvents, componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Company/OnboardingFlow/OnboardingFlow.tsx b/src/components/Company/OnboardingFlow/OnboardingFlow.tsx index 86de230a20..8a546aceb4 100644 --- a/src/components/Company/OnboardingFlow/OnboardingFlow.tsx +++ b/src/components/Company/OnboardingFlow/OnboardingFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { onboardingMachine } from './onboardingStateMachine' import type { OnboardingFlowProps } from './OnboardingFlowComponents' @@ -6,6 +5,7 @@ import { OnboardingOverviewContextual, type OnboardingFlowContextInterface, } from './OnboardingFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' export type { OnboardingFlowProps, OnboardingFlowDefaultValues } from './OnboardingFlowComponents' diff --git a/src/components/Company/OnboardingFlow/onboardingStateMachine.ts b/src/components/Company/OnboardingFlow/onboardingStateMachine.ts index cf9ba6f984..ce0328cf55 100644 --- a/src/components/Company/OnboardingFlow/onboardingStateMachine.ts +++ b/src/components/Company/OnboardingFlow/onboardingStateMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state } from 'robot3' import { BankAccountContextual, DocumentSignerContextual, @@ -11,6 +10,7 @@ import { StateTaxesContextual, type OnboardingFlowContextInterface, } from './OnboardingFlowComponents' +import { transition, reduce, state } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' import type { FlowHeaderConfig } from '@/components/Flow/useFlow' diff --git a/src/components/Company/PaySchedule/PaySchedule.tsx b/src/components/Company/PaySchedule/PaySchedule.tsx index ce7d63b012..8e6e7a7479 100644 --- a/src/components/Company/PaySchedule/PaySchedule.tsx +++ b/src/components/Company/PaySchedule/PaySchedule.tsx @@ -1,10 +1,10 @@ import { useMemo } from 'react' -import { createMachine } from 'robot3' import { usePaySchedulesGetAllSuspense } from '@gusto/embedded-api/react-query/paySchedulesGetAll' import { payScheduleStateMachine } from './payScheduleStateMachine' import type { PayScheduleContextInterface } from './PayScheduleComponents' import { PayScheduleFormContextual, PayScheduleListContextual } from './PayScheduleComponents' import type { PayScheduleFormData } from './shared/usePayScheduleForm/payScheduleSchema' +import { createMachine } from '@/lib/state-machine' import type { BaseComponentInterface } from '@/components/Base' import { BaseComponent, useBase } from '@/components/Base' import type { BaseComponentKeys } from '@/components/Base/Base' diff --git a/src/components/Company/PaySchedule/payScheduleStateMachine.ts b/src/components/Company/PaySchedule/payScheduleStateMachine.ts index f106cfbcc0..705b601086 100644 --- a/src/components/Company/PaySchedule/payScheduleStateMachine.ts +++ b/src/components/Company/PaySchedule/payScheduleStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { PayScheduleContextInterface } from './PayScheduleComponents' import { PayScheduleFormContextual, PayScheduleListContextual } from './PayScheduleComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Company/StateTaxes/StateTaxes.tsx b/src/components/Company/StateTaxes/StateTaxes.tsx index 0ca9415f19..9fcba1cfd5 100644 --- a/src/components/Company/StateTaxes/StateTaxes.tsx +++ b/src/components/Company/StateTaxes/StateTaxes.tsx @@ -1,8 +1,8 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { stateTaxesStateMachine } from './stateTaxesStateMachine' import type { StateTaxesContextInterface } from './StateTaxesComponents' import { StateTaxesListContextual } from './StateTaxesComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Company/StateTaxes/stateTaxesStateMachine.tsx b/src/components/Company/StateTaxes/stateTaxesStateMachine.tsx index 6bdc915aa9..904a72387b 100644 --- a/src/components/Company/StateTaxes/stateTaxesStateMachine.tsx +++ b/src/components/Company/StateTaxes/stateTaxesStateMachine.tsx @@ -1,4 +1,3 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { StateTaxesContextInterface } from './StateTaxesComponents' import { @@ -6,6 +5,7 @@ import { StateTaxesListContextual, TaxRateManagementContextual, } from './StateTaxesComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Contractor/Address/management/Address.tsx b/src/components/Contractor/Address/management/Address.tsx index 3ff694483a..2b6e82017e 100644 --- a/src/components/Contractor/Address/management/Address.tsx +++ b/src/components/Contractor/Address/management/Address.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { CardContextual, type AddressContextInterface } from './AddressComponents' import { addressStateMachine } from './addressStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Contractor/Address/management/addressStateMachine.ts b/src/components/Contractor/Address/management/addressStateMachine.ts index 7672e0bf6b..d69370ff8d 100644 --- a/src/components/Contractor/Address/management/addressStateMachine.ts +++ b/src/components/Contractor/Address/management/addressStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { AddressContextInterface } from './AddressComponents' import { CardContextual, AddressEditFormContextual } from './AddressComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Contractor/Compensation/management/Compensation.tsx b/src/components/Contractor/Compensation/management/Compensation.tsx index e20a9f4fba..7c393f575d 100644 --- a/src/components/Contractor/Compensation/management/Compensation.tsx +++ b/src/components/Contractor/Compensation/management/Compensation.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { CardContextual, type CompensationContextInterface } from './CompensationComponents' import { compensationStateMachine } from './compensationStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Contractor/Compensation/management/compensationStateMachine.ts b/src/components/Contractor/Compensation/management/compensationStateMachine.ts index 49eb6b5335..1a87089b87 100644 --- a/src/components/Contractor/Compensation/management/compensationStateMachine.ts +++ b/src/components/Contractor/Compensation/management/compensationStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { CompensationContextInterface } from './CompensationComponents' import { CardContextual, CompensationEditFormContextual } from './CompensationComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Contractor/Dashboard/DashboardFlow.tsx b/src/components/Contractor/Dashboard/DashboardFlow.tsx index 037330d9a9..ff2a0ac7a5 100644 --- a/src/components/Contractor/Dashboard/DashboardFlow.tsx +++ b/src/components/Contractor/Dashboard/DashboardFlow.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { dashboardStateMachine } from './dashboardStateMachine' import { type DashboardContextInterface, DashboardViewContextual } from './DashboardComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { BaseComponentInterface } from '@/components/Base' diff --git a/src/components/Contractor/Dashboard/dashboardStateMachine.ts b/src/components/Contractor/Dashboard/dashboardStateMachine.ts index 096e013192..4f5bd1b56a 100644 --- a/src/components/Contractor/Dashboard/dashboardStateMachine.ts +++ b/src/components/Contractor/Dashboard/dashboardStateMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state } from 'robot3' import type { DashboardTab } from './Dashboard' import { DashboardViewContextual, @@ -8,6 +7,7 @@ import { CompensationEditFormContextual, type DashboardContextInterface, } from './DashboardComponents' +import { transition, reduce, state } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Contractor/Documents/onboarding/DocumentSigner/DocumentSigner.tsx b/src/components/Contractor/Documents/onboarding/DocumentSigner/DocumentSigner.tsx index 4d40252194..2b93079120 100644 --- a/src/components/Contractor/Documents/onboarding/DocumentSigner/DocumentSigner.tsx +++ b/src/components/Contractor/Documents/onboarding/DocumentSigner/DocumentSigner.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import type { DocumentsListProps } from '../DocumentsList' import { @@ -6,6 +5,7 @@ import { type DocumentSignerContextInterface, } from './documentSignerStateMachine' import { documentSignerMachine } from './stateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseComponent, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Contractor/Documents/onboarding/DocumentSigner/stateMachine.ts b/src/components/Contractor/Documents/onboarding/DocumentSigner/stateMachine.ts index de5477b673..485d9de59d 100644 --- a/src/components/Contractor/Documents/onboarding/DocumentSigner/stateMachine.ts +++ b/src/components/Contractor/Documents/onboarding/DocumentSigner/stateMachine.ts @@ -1,6 +1,6 @@ -import { state, transition, reduce } from 'robot3' import type { DocumentSignerContextInterface, EventPayloads } from './documentSignerStateMachine' import { SignatureFormContextual, DocumentsListContextual } from './documentSignerStateMachine' +import { state, transition, reduce } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Contractor/OnboardingFlow/OnboardingFlow.tsx b/src/components/Contractor/OnboardingFlow/OnboardingFlow.tsx index 81f31edffd..b0e482ac77 100644 --- a/src/components/Contractor/OnboardingFlow/OnboardingFlow.tsx +++ b/src/components/Contractor/OnboardingFlow/OnboardingFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { onboardingMachine } from './onboardingStateMachine' import type { OnboardingFlowProps } from './OnboardingFlowComponents' @@ -6,6 +5,7 @@ import { ContractorListContextual, type OnboardingFlowContextInterface, } from './OnboardingFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' /** diff --git a/src/components/Contractor/OnboardingFlow/onboardingStateMachine.test.ts b/src/components/Contractor/OnboardingFlow/onboardingStateMachine.test.ts index ae60bcf777..9902b52e44 100644 --- a/src/components/Contractor/OnboardingFlow/onboardingStateMachine.test.ts +++ b/src/components/Contractor/OnboardingFlow/onboardingStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret } from 'robot3' +import { createMachine, interpret } from '@/lib/state-machine' import { onboardingMachine } from './onboardingStateMachine' import { ContractorListContextual, diff --git a/src/components/Contractor/OnboardingFlow/onboardingStateMachine.ts b/src/components/Contractor/OnboardingFlow/onboardingStateMachine.ts index 118e105389..436cdf63fc 100644 --- a/src/components/Contractor/OnboardingFlow/onboardingStateMachine.ts +++ b/src/components/Contractor/OnboardingFlow/onboardingStateMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state, guard } from 'robot3' import type { Contractor } from '@gusto/embedded-api/models/components/contractor' import { AddressContextual, @@ -10,6 +9,7 @@ import { SubmitContextual, type OnboardingFlowContextInterface, } from './OnboardingFlowComponents' +import { transition, reduce, state, guard } from '@/lib/state-machine' import { componentEvents, ContractorOnboardingStatus } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import type { FlowHeaderConfig } from '@/components/Flow/useFlow' diff --git a/src/components/Contractor/PaymentMethod/management/PaymentMethod.tsx b/src/components/Contractor/PaymentMethod/management/PaymentMethod.tsx index d4f29cc6ee..ad1d6062ab 100644 --- a/src/components/Contractor/PaymentMethod/management/PaymentMethod.tsx +++ b/src/components/Contractor/PaymentMethod/management/PaymentMethod.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { CardContextual, type PaymentMethodContextInterface } from './PaymentMethodComponents' import { paymentMethodStateMachine } from './paymentMethodStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Contractor/PaymentMethod/management/paymentMethodStateMachine.ts b/src/components/Contractor/PaymentMethod/management/paymentMethodStateMachine.ts index 16baad0a07..eabf64595e 100644 --- a/src/components/Contractor/PaymentMethod/management/paymentMethodStateMachine.ts +++ b/src/components/Contractor/PaymentMethod/management/paymentMethodStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { PaymentMethodContextInterface } from './PaymentMethodComponents' import { CardContextual, PaymentMethodEditFormContextual } from './PaymentMethodComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Contractor/Payments/CreatePaymentFlow/CreatePaymentFlow.tsx b/src/components/Contractor/Payments/CreatePaymentFlow/CreatePaymentFlow.tsx index bdbe7061fe..fbc5eeb4a2 100644 --- a/src/components/Contractor/Payments/CreatePaymentFlow/CreatePaymentFlow.tsx +++ b/src/components/Contractor/Payments/CreatePaymentFlow/CreatePaymentFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useState } from 'react' import { createPaymentBreadcrumbsNodes, createPaymentMachine } from './createPaymentMachine' import { @@ -6,6 +5,7 @@ import { type CreatePaymentFlowContextInterface, type CreatePaymentFlowProps, } from './CreatePaymentFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { FlowBreadcrumb } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' import { buildBreadcrumbs, updateBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Contractor/Payments/CreatePaymentFlow/createPaymentMachine.test.ts b/src/components/Contractor/Payments/CreatePaymentFlow/createPaymentMachine.test.ts index 165a6aef6b..3914944241 100644 --- a/src/components/Contractor/Payments/CreatePaymentFlow/createPaymentMachine.test.ts +++ b/src/components/Contractor/Payments/CreatePaymentFlow/createPaymentMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { createPaymentMachine, createPaymentBreadcrumbsNodes } from './createPaymentMachine' import type { CreatePaymentFlowContextInterface } from './CreatePaymentFlowComponents' import { componentEvents, payrollWireEvents } from '@/shared/constants' diff --git a/src/components/Contractor/Payments/CreatePaymentFlow/createPaymentMachine.ts b/src/components/Contractor/Payments/CreatePaymentFlow/createPaymentMachine.ts index e7c3a6a1c7..62032cfc5a 100644 --- a/src/components/Contractor/Payments/CreatePaymentFlow/createPaymentMachine.ts +++ b/src/components/Contractor/Payments/CreatePaymentFlow/createPaymentMachine.ts @@ -1,10 +1,10 @@ -import { reduce, state, transition } from 'robot3' import type { ContractorPaymentGroup } from '@gusto/embedded-api/models/components/contractorpaymentgroup' import type { WireInRequest } from '@gusto/embedded-api/models/components/wireinrequest' import { PaymentSummaryContextual, type CreatePaymentFlowContextInterface, } from './CreatePaymentFlowComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { payrollWireEvents, componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import { updateBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Contractor/Payments/HistoricalPaymentFlow/HistoricalPaymentFlow.tsx b/src/components/Contractor/Payments/HistoricalPaymentFlow/HistoricalPaymentFlow.tsx index cf6b3c6d9c..c4c2f17aba 100644 --- a/src/components/Contractor/Payments/HistoricalPaymentFlow/HistoricalPaymentFlow.tsx +++ b/src/components/Contractor/Payments/HistoricalPaymentFlow/HistoricalPaymentFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useState } from 'react' import { historicalPaymentMachine } from './historicalPaymentMachine' import { @@ -6,6 +5,7 @@ import { type HistoricalPaymentFlowContextInterface, type HistoricalPaymentFlowProps, } from './HistoricalPaymentFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { FlowBreadcrumb } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' import { updateBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Contractor/Payments/HistoricalPaymentFlow/historicalPaymentMachine.ts b/src/components/Contractor/Payments/HistoricalPaymentFlow/historicalPaymentMachine.ts index e1111019dd..21a6fe869d 100644 --- a/src/components/Contractor/Payments/HistoricalPaymentFlow/historicalPaymentMachine.ts +++ b/src/components/Contractor/Payments/HistoricalPaymentFlow/historicalPaymentMachine.ts @@ -1,9 +1,9 @@ -import { reduce, state, transition } from 'robot3' import type { ContractorPaymentGroup } from '@gusto/embedded-api/models/components/contractorpaymentgroup' import { HistoricalPaymentSummaryContextual, type HistoricalPaymentFlowContextInterface, } from './HistoricalPaymentFlowComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import { updateBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Contractor/Payments/PaymentFlow/PaymentFlow.tsx b/src/components/Contractor/Payments/PaymentFlow/PaymentFlow.tsx index fca997925c..a240fb708f 100644 --- a/src/components/Contractor/Payments/PaymentFlow/PaymentFlow.tsx +++ b/src/components/Contractor/Payments/PaymentFlow/PaymentFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { paymentFlowBreadcrumbsNodes, paymentMachine } from './paymentStateMachine' import { @@ -6,6 +5,7 @@ import { type PaymentFlowContextInterface, type PaymentFlowProps, } from './PaymentFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { buildBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Contractor/Payments/PaymentFlow/paymentStateMachine.test.ts b/src/components/Contractor/Payments/PaymentFlow/paymentStateMachine.test.ts index 51912663ea..245c99615a 100644 --- a/src/components/Contractor/Payments/PaymentFlow/paymentStateMachine.test.ts +++ b/src/components/Contractor/Payments/PaymentFlow/paymentStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { paymentMachine, paymentFlowBreadcrumbsNodes } from './paymentStateMachine' import type { PaymentFlowContextInterface } from './PaymentFlowComponents' import { componentEvents, informationRequestEvents, payrollWireEvents } from '@/shared/constants' diff --git a/src/components/Contractor/Payments/PaymentFlow/paymentStateMachine.ts b/src/components/Contractor/Payments/PaymentFlow/paymentStateMachine.ts index ceee4445e7..b78769096d 100644 --- a/src/components/Contractor/Payments/PaymentFlow/paymentStateMachine.ts +++ b/src/components/Contractor/Payments/PaymentFlow/paymentStateMachine.ts @@ -1,4 +1,3 @@ -import { reduce, state, transition } from 'robot3' import type { WireInRequest } from '@gusto/embedded-api/models/components/wireinrequest' import { CreatePaymentFlowContextual, @@ -8,6 +7,7 @@ import { type PaymentFlowContextInterface, ViewPaymentFlowContextual, } from './PaymentFlowComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents, informationRequestEvents, payrollWireEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import { patchBreadcrumbsHeader } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Contractor/Payments/ViewPaymentFlow/ViewPaymentFlow.tsx b/src/components/Contractor/Payments/ViewPaymentFlow/ViewPaymentFlow.tsx index 5f229d00ac..87da268578 100644 --- a/src/components/Contractor/Payments/ViewPaymentFlow/ViewPaymentFlow.tsx +++ b/src/components/Contractor/Payments/ViewPaymentFlow/ViewPaymentFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useState } from 'react' import { viewPaymentBreadcrumbsNodes, viewPaymentMachine } from './viewPaymentMachine' import { @@ -6,6 +5,7 @@ import { type ViewPaymentFlowContextInterface, type ViewPaymentFlowProps, } from './ViewPaymentFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { FlowBreadcrumb } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' import { buildBreadcrumbs, updateBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Contractor/Payments/ViewPaymentFlow/viewPaymentMachine.test.ts b/src/components/Contractor/Payments/ViewPaymentFlow/viewPaymentMachine.test.ts index d46b76a579..2f84ae5f64 100644 --- a/src/components/Contractor/Payments/ViewPaymentFlow/viewPaymentMachine.test.ts +++ b/src/components/Contractor/Payments/ViewPaymentFlow/viewPaymentMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { viewPaymentMachine, viewPaymentBreadcrumbsNodes } from './viewPaymentMachine' import type { ViewPaymentFlowContextInterface } from './ViewPaymentFlowComponents' import { componentEvents } from '@/shared/constants' diff --git a/src/components/Contractor/Payments/ViewPaymentFlow/viewPaymentMachine.ts b/src/components/Contractor/Payments/ViewPaymentFlow/viewPaymentMachine.ts index fdd654bd42..0511f126e7 100644 --- a/src/components/Contractor/Payments/ViewPaymentFlow/viewPaymentMachine.ts +++ b/src/components/Contractor/Payments/ViewPaymentFlow/viewPaymentMachine.ts @@ -1,4 +1,3 @@ -import { reduce, state, transition } from 'robot3' import type { Contractor } from '@gusto/embedded-api/models/components/contractor' import { getContractorDisplayName } from '../../shared/helpers' import { @@ -6,6 +5,7 @@ import { PaymentStatementContextual, type ViewPaymentFlowContextInterface, } from './ViewPaymentFlowComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import { updateBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Contractor/Profile/management/Profile.tsx b/src/components/Contractor/Profile/management/Profile.tsx index 7f8b6f8214..2f32ac3c3c 100644 --- a/src/components/Contractor/Profile/management/Profile.tsx +++ b/src/components/Contractor/Profile/management/Profile.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { CardContextual, type ProfileContextInterface } from './ProfileComponents' import { profileStateMachine } from './profileStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Contractor/Profile/management/profileStateMachine.ts b/src/components/Contractor/Profile/management/profileStateMachine.ts index 21aadcc5c0..d3ba25faa8 100644 --- a/src/components/Contractor/Profile/management/profileStateMachine.ts +++ b/src/components/Contractor/Profile/management/profileStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { ProfileContextInterface } from './ProfileComponents' import { CardContextual, ProfileEditFormContextual } from './ProfileComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Contractor/SelfOnboardingFlow/SelfOnboardingFlow.tsx b/src/components/Contractor/SelfOnboardingFlow/SelfOnboardingFlow.tsx index fcb52193d2..1cf5752466 100644 --- a/src/components/Contractor/SelfOnboardingFlow/SelfOnboardingFlow.tsx +++ b/src/components/Contractor/SelfOnboardingFlow/SelfOnboardingFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import type { SelfOnboardingContextInterface, @@ -6,6 +5,7 @@ import type { } from './SelfOnboardingComponents' import { Landing } from './SelfOnboardingComponents' import { contractorSelfOnboardingMachine } from './selfOnboardingMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' export type { SelfOnboardingFlowProps } from './SelfOnboardingComponents' diff --git a/src/components/Contractor/SelfOnboardingFlow/selfOnboardingMachine.ts b/src/components/Contractor/SelfOnboardingFlow/selfOnboardingMachine.ts index a67c280c86..733f91c273 100644 --- a/src/components/Contractor/SelfOnboardingFlow/selfOnboardingMachine.ts +++ b/src/components/Contractor/SelfOnboardingFlow/selfOnboardingMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state } from 'robot3' import type { SelfOnboardingContextInterface } from './SelfOnboardingComponents' import { Profile, @@ -7,6 +6,7 @@ import { DocumentSigner, OnboardingSummary, } from './SelfOnboardingComponents' +import { transition, reduce, state } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/Compensation/management/Compensation.tsx b/src/components/Employee/Compensation/management/Compensation.tsx index 216656bf2d..7c87c9fb1f 100644 --- a/src/components/Employee/Compensation/management/Compensation.tsx +++ b/src/components/Employee/Compensation/management/Compensation.tsx @@ -1,10 +1,10 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { CompensationCardContextual, type CompensationContextInterface, } from './CompensationComponents' import { compensationStateMachine } from './compensationStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/Compensation/management/compensationStateMachine.ts b/src/components/Employee/Compensation/management/compensationStateMachine.ts index 977da646f6..5a3fa13a01 100644 --- a/src/components/Employee/Compensation/management/compensationStateMachine.ts +++ b/src/components/Employee/Compensation/management/compensationStateMachine.ts @@ -1,4 +1,3 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { CompensationContextInterface } from './CompensationComponents' import { @@ -7,6 +6,7 @@ import { CompensationAddJobFormContextual, CompensationAddAnotherJobFormContextual, } from './CompensationComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/Compensation/onboarding/Compensation.test.tsx b/src/components/Employee/Compensation/onboarding/Compensation.test.tsx index 4bd40be010..be42ff35f2 100644 --- a/src/components/Employee/Compensation/onboarding/Compensation.test.tsx +++ b/src/components/Employee/Compensation/onboarding/Compensation.test.tsx @@ -504,7 +504,7 @@ describe('Compensation', () => { // Regression test for SDK-1169: after leaving and returning to a still-mounted // Compensation component, "Add new job"/"Edit" silently stopped navigating. Root - // cause: `done` was modeled as a robot3 final state (no transitions out), so a host + // cause: `done` was modeled as a final state (no transitions out), so a host // that doesn't unmount Compensation once `employee/compensation/done` fires was // left with a jobs list whose controls could never navigate again. The fix removes // the terminal state entirely — Flow re-emits the DONE event to the parent diff --git a/src/components/Employee/Compensation/onboarding/Compensation.tsx b/src/components/Employee/Compensation/onboarding/Compensation.tsx index 26c3e09456..53effa74fe 100644 --- a/src/components/Employee/Compensation/onboarding/Compensation.tsx +++ b/src/components/Employee/Compensation/onboarding/Compensation.tsx @@ -1,5 +1,4 @@ import { useMemo, useState } from 'react' -import { createMachine } from 'robot3' import { useTranslation } from 'react-i18next' import { useJobsAndCompensationsGetJobsSuspense } from '@gusto/embedded-api/react-query/jobsAndCompensationsGetJobs' import { type Job } from '@gusto/embedded-api/models/components/job' @@ -11,6 +10,7 @@ import { type CompensationFlowContextInterface, } from './CompensationFlowComponents' import { compensationStateMachine } from './compensationStateMachine' +import { createMachine } from '@/lib/state-machine' import type { RequireAtLeastOne } from '@/types/Helpers' import type { PAY_PERIODS } from '@/shared/constants' import { FlsaStatus } from '@/shared/constants' diff --git a/src/components/Employee/Compensation/onboarding/compensationStateMachine.test.ts b/src/components/Employee/Compensation/onboarding/compensationStateMachine.test.ts index fda7391602..243032a2d6 100644 --- a/src/components/Employee/Compensation/onboarding/compensationStateMachine.test.ts +++ b/src/components/Employee/Compensation/onboarding/compensationStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { compensationStateMachine } from './compensationStateMachine' import type { CompensationFlowContextInterface } from './CompensationFlowComponents' import { componentEvents } from '@/shared/constants' @@ -31,8 +31,8 @@ function send(service: ReturnType, type: string, payload?: describe('compensationStateMachine', () => { // Regression test for SDK-1169: Add new job/Edit silently stopped navigating after // leaving and returning to a still-mounted Compensation component. `done` used to be - // a robot3 final state (no transitions out), so once EMPLOYEE_COMPENSATION_DONE - // fired, every subsequent event was a documented robot3 no-op and the machine could + // a final state (no transitions out), so once EMPLOYEE_COMPENSATION_DONE + // fired, every subsequent event was a no-op and the machine could // never advance. EMPLOYEE_COMPENSATION_DONE now has no transition at all: the // machine stays in `viewJobs`, and Flow re-emits the event to the parent regardless. it('SDK-1169: keeps handling EMPLOYEE_JOB_ADD/EMPLOYEE_JOB_EDIT after DONE fires', () => { diff --git a/src/components/Employee/Compensation/onboarding/compensationStateMachine.ts b/src/components/Employee/Compensation/onboarding/compensationStateMachine.ts index 7ce1024406..2252c89253 100644 --- a/src/components/Employee/Compensation/onboarding/compensationStateMachine.ts +++ b/src/components/Employee/Compensation/onboarding/compensationStateMachine.ts @@ -1,10 +1,10 @@ -import { reduce, state, transition } from 'robot3' import { EditCompensationContextual, JobsListContextual, type CompensationFlowContextInterface, type EventPayloads, } from './CompensationFlowComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' @@ -12,7 +12,7 @@ import type { MachineEventType, MachineTransition } from '@/types/Helpers' * `EMPLOYEE_COMPENSATION_DONE` deliberately has no transition out of `initialEditJob` or * `viewJobs`. `Flow` re-emits every event to the upstream `onEvent` regardless of whether the * local machine has a matching transition, so the parent flow still advances/unmounts this - * component on that signal. Modeling completion as a robot3 final state instead left `component` + * component on that signal. Modeling completion as a final state instead left `component` * pointing at a step whose controls could never fire another transition — if a host doesn't * unmount immediately, the screen would look interactive but be permanently dead (SDK-1169). * Staying put means a host that keeps this component mounted past completion keeps a fully diff --git a/src/components/Employee/Dashboard/DashboardFlow.tsx b/src/components/Employee/Dashboard/DashboardFlow.tsx index a0afef8c33..701c750bf6 100644 --- a/src/components/Employee/Dashboard/DashboardFlow.tsx +++ b/src/components/Employee/Dashboard/DashboardFlow.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { dashboardStateMachine } from './dashboardStateMachine' import { type DashboardContextInterface, DashboardViewContextual } from './DashboardComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { BaseComponentInterface } from '@/components/Base' diff --git a/src/components/Employee/Dashboard/dashboardStateMachine.test.ts b/src/components/Employee/Dashboard/dashboardStateMachine.test.ts index 0757a63efa..864a7a375b 100644 --- a/src/components/Employee/Dashboard/dashboardStateMachine.test.ts +++ b/src/components/Employee/Dashboard/dashboardStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { dashboardStateMachine } from './dashboardStateMachine' import { DashboardViewContextual, type DashboardContextInterface } from './DashboardComponents' import { componentEvents } from '@/shared/constants' diff --git a/src/components/Employee/Dashboard/dashboardStateMachine.ts b/src/components/Employee/Dashboard/dashboardStateMachine.ts index eedbef5773..de0c15b4ad 100644 --- a/src/components/Employee/Dashboard/dashboardStateMachine.ts +++ b/src/components/Employee/Dashboard/dashboardStateMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state } from 'robot3' import type { Garnishment } from '@gusto/embedded-api/models/components/garnishment' import type { DashboardTab } from './Dashboard' import { @@ -17,6 +16,7 @@ import { AddAnotherJobContextual, type DashboardContextInterface, } from './DashboardComponents' +import { transition, reduce, state } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/Deductions/management/Deductions.tsx b/src/components/Employee/Deductions/management/Deductions.tsx index 292693c755..319ab4f0b7 100644 --- a/src/components/Employee/Deductions/management/Deductions.tsx +++ b/src/components/Employee/Deductions/management/Deductions.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { DeductionsCardContextual, type DeductionsContextInterface } from './DeductionsComponents' import { deductionsStateMachine } from './deductionsStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/Deductions/management/deductionsStateMachine.ts b/src/components/Employee/Deductions/management/deductionsStateMachine.ts index a1919d05c4..c37561b700 100644 --- a/src/components/Employee/Deductions/management/deductionsStateMachine.ts +++ b/src/components/Employee/Deductions/management/deductionsStateMachine.ts @@ -1,8 +1,8 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { Garnishment } from '@gusto/embedded-api/models/components/garnishment' import type { DeductionsContextInterface } from './DeductionsComponents' import { DeductionsCardContextual, DeductionsEditFormContextual } from './DeductionsComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/Deductions/onboarding/Deductions.tsx b/src/components/Employee/Deductions/onboarding/Deductions.tsx index da651d741c..93c85b9abc 100644 --- a/src/components/Employee/Deductions/onboarding/Deductions.tsx +++ b/src/components/Employee/Deductions/onboarding/Deductions.tsx @@ -1,10 +1,10 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { DeductionsListContextual, type DeductionsContextInterface, } from './deductionsContextualComponents' import { deductionsMachine } from './stateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base/Base' import { useComponentDictionary, useI18n } from '@/i18n' diff --git a/src/components/Employee/Deductions/onboarding/stateMachine.test.ts b/src/components/Employee/Deductions/onboarding/stateMachine.test.ts index 85d077cf27..5426f592f4 100644 --- a/src/components/Employee/Deductions/onboarding/stateMachine.test.ts +++ b/src/components/Employee/Deductions/onboarding/stateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { deductionsMachine } from './stateMachine' import type { DeductionsContextInterface } from './deductionsContextualComponents' import { componentEvents } from '@/shared/constants' @@ -23,7 +23,7 @@ function send(service: ReturnType, type: string, payload?: } describe('deductionsMachine', () => { - // Regression test for SDK-1169: `done` used to be a robot3 final state (no + // Regression test for SDK-1169: `done` used to be a final state (no // transitions out) reached from `list` on EMPLOYEE_DEDUCTION_DONE. A host that kept // this component mounted past that signal was left with a deductions list whose // Add/Edit controls could never fire another transition. EMPLOYEE_DEDUCTION_DONE now diff --git a/src/components/Employee/Deductions/onboarding/stateMachine.ts b/src/components/Employee/Deductions/onboarding/stateMachine.ts index 0dfe5244b3..96531079e0 100644 --- a/src/components/Employee/Deductions/onboarding/stateMachine.ts +++ b/src/components/Employee/Deductions/onboarding/stateMachine.ts @@ -1,9 +1,9 @@ -import { state, transition, reduce } from 'robot3' import type { DeductionsContextInterface, EventPayloads } from './deductionsContextualComponents' import { DeductionsListContextual, DeductionsFormContextual, } from './deductionsContextualComponents' +import { state, transition, reduce } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' @@ -11,7 +11,7 @@ import type { MachineEventType, MachineTransition } from '@/types/Helpers' * `EMPLOYEE_DEDUCTION_DONE` deliberately has no transition out of `list`. `Flow` re-emits every * event to the upstream `onEvent` regardless of whether the local machine has a matching * transition, so the parent flow still advances/unmounts this component on that signal. Modeling - * completion as a robot3 final state instead left `component` pointing at a step whose controls + * completion as a final state instead left `component` pointing at a step whose controls * could never fire another transition — if a host doesn't unmount immediately, the screen would * look interactive but be permanently dead (see SDK-1169, the same bug in * `Compensation`'s onboarding machine). Staying in `list` means a host that keeps this component diff --git a/src/components/Employee/Documents/management/Documents.tsx b/src/components/Employee/Documents/management/Documents.tsx index 9f90d261dd..91ec698592 100644 --- a/src/components/Employee/Documents/management/Documents.tsx +++ b/src/components/Employee/Documents/management/Documents.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { DocumentsCardContextual, type DocumentsContextInterface } from './DocumentsComponents' import { documentsStateMachine } from './documentsStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/Documents/management/documentsStateMachine.ts b/src/components/Employee/Documents/management/documentsStateMachine.ts index 72c084e763..f8ec2bec7b 100644 --- a/src/components/Employee/Documents/management/documentsStateMachine.ts +++ b/src/components/Employee/Documents/management/documentsStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { DocumentsContextInterface } from './DocumentsComponents' import { DocumentsCardContextual, DocumentManagerContextual } from './DocumentsComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/Documents/onboarding/DocumentSigner/DocumentSigner.tsx b/src/components/Employee/Documents/onboarding/DocumentSigner/DocumentSigner.tsx index 690d4b01c7..f9c79f77d5 100644 --- a/src/components/Employee/Documents/onboarding/DocumentSigner/DocumentSigner.tsx +++ b/src/components/Employee/Documents/onboarding/DocumentSigner/DocumentSigner.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { useEmployeesGetSuspense } from '@gusto/embedded-api/react-query/employeesGet' import { useEmployeeFormsListSuspense } from '@gusto/embedded-api/react-query/employeeFormsList' @@ -8,6 +7,7 @@ import { type DocumentSignerContextInterface, } from './documentSignerStateMachine' import { documentSignerMachine } from './stateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseComponent, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/Documents/onboarding/DocumentSigner/stateMachine.test.ts b/src/components/Employee/Documents/onboarding/DocumentSigner/stateMachine.test.ts index 76352805d0..62dc901e58 100644 --- a/src/components/Employee/Documents/onboarding/DocumentSigner/stateMachine.test.ts +++ b/src/components/Employee/Documents/onboarding/DocumentSigner/stateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { documentSignerMachine } from './stateMachine' import type { DocumentSignerContextInterface } from './documentSignerStateMachine' import { componentEvents } from '@/shared/constants' @@ -27,7 +27,7 @@ function send(service: ReturnType, type: string, payload?: } describe('documentSignerMachine', () => { - // Regression test for SDK-1169: `done` used to be a robot3 final state (no + // Regression test for SDK-1169: `done` used to be a final state (no // transitions out) reached from `index` on EMPLOYEE_FORMS_DONE. A host that kept // this component mounted past that signal was left with a document list whose // "view form to sign" controls could never fire another transition. diff --git a/src/components/Employee/Documents/onboarding/DocumentSigner/stateMachine.ts b/src/components/Employee/Documents/onboarding/DocumentSigner/stateMachine.ts index 5bcc842df7..9f48b9055b 100644 --- a/src/components/Employee/Documents/onboarding/DocumentSigner/stateMachine.ts +++ b/src/components/Employee/Documents/onboarding/DocumentSigner/stateMachine.ts @@ -1,4 +1,3 @@ -import { state, transition, reduce } from 'robot3' import type { DocumentSignerContextInterface, EventPayloads } from './documentSignerStateMachine' import { SignatureFormContextual, @@ -6,6 +5,7 @@ import { I9SignatureFormContextual, EmploymentEligibilityContextual, } from './documentSignerStateMachine' +import { state, transition, reduce } from '@/lib/state-machine' import { componentEvents, I9_FORM_NAME } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' @@ -13,7 +13,7 @@ import type { MachineEventType, MachineTransition } from '@/types/Helpers' * `EMPLOYEE_FORMS_DONE` deliberately has no transition out of `index`. `Flow` re-emits every * event to the upstream `onEvent` regardless of whether the local machine has a matching * transition, so the parent flow still advances/unmounts this component on that signal. Modeling - * completion as a robot3 final state instead left `component` pointing at a step whose controls + * completion as a final state instead left `component` pointing at a step whose controls * could never fire another transition — if a host doesn't unmount immediately, the screen would * look interactive but be permanently dead (see SDK-1169, the same bug in * `Compensation`'s onboarding machine). Staying in `index` means a host that keeps this diff --git a/src/components/Employee/EmployeeListFlow/EmployeeListFlow.tsx b/src/components/Employee/EmployeeListFlow/EmployeeListFlow.tsx index 46c646f390..3c6aefcbe0 100644 --- a/src/components/Employee/EmployeeListFlow/EmployeeListFlow.tsx +++ b/src/components/Employee/EmployeeListFlow/EmployeeListFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { employeeListStateMachine } from './employeeListStateMachine' import { @@ -6,6 +5,7 @@ import { type EmployeeListFlowContextInterface, type EmployeeListFlowProps, } from './EmployeeListFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' /** diff --git a/src/components/Employee/EmployeeListFlow/employeeListStateMachine.ts b/src/components/Employee/EmployeeListFlow/employeeListStateMachine.ts index 4881f966c0..2e9bc53f9d 100644 --- a/src/components/Employee/EmployeeListFlow/employeeListStateMachine.ts +++ b/src/components/Employee/EmployeeListFlow/employeeListStateMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state } from 'robot3' import { DashboardFlowContextual, EmployeeListContextual, @@ -6,6 +5,7 @@ import { TerminationFlowContextual, type EmployeeListFlowContextInterface, } from './EmployeeListFlowComponents' +import { transition, reduce, state } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import type { FlowHeaderConfig } from '@/components/Flow/useFlow' diff --git a/src/components/Employee/FederalTaxes/management/FederalTaxes.tsx b/src/components/Employee/FederalTaxes/management/FederalTaxes.tsx index 412d605a46..be91f1a288 100644 --- a/src/components/Employee/FederalTaxes/management/FederalTaxes.tsx +++ b/src/components/Employee/FederalTaxes/management/FederalTaxes.tsx @@ -1,10 +1,10 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { FederalTaxesCardContextual, type FederalTaxesContextInterface, } from './FederalTaxesComponents' import { federalTaxesStateMachine } from './federalTaxesStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/FederalTaxes/management/federalTaxesStateMachine.ts b/src/components/Employee/FederalTaxes/management/federalTaxesStateMachine.ts index 44db5a2965..3904660edc 100644 --- a/src/components/Employee/FederalTaxes/management/federalTaxesStateMachine.ts +++ b/src/components/Employee/FederalTaxes/management/federalTaxesStateMachine.ts @@ -1,10 +1,10 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { FederalTaxesContextInterface } from './FederalTaxesComponents' import { FederalTaxesCardContextual, FederalTaxesEditFormContextual, } from './FederalTaxesComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/HomeAddress/management/HomeAddress.tsx b/src/components/Employee/HomeAddress/management/HomeAddress.tsx index 0f2219a0d0..4a99d259b7 100644 --- a/src/components/Employee/HomeAddress/management/HomeAddress.tsx +++ b/src/components/Employee/HomeAddress/management/HomeAddress.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { CardContextual, type HomeAddressContextInterface } from './HomeAddressComponents' import { homeAddressStateMachine } from './homeAddressStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/HomeAddress/management/homeAddressStateMachine.ts b/src/components/Employee/HomeAddress/management/homeAddressStateMachine.ts index 3913b72a53..109850c831 100644 --- a/src/components/Employee/HomeAddress/management/homeAddressStateMachine.ts +++ b/src/components/Employee/HomeAddress/management/homeAddressStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { HomeAddressContextInterface } from './HomeAddressComponents' import { CardContextual, HomeAddressEditFormContextual } from './HomeAddressComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/OnboardingExecutionFlow/OnboardingExecutionFlow.tsx b/src/components/Employee/OnboardingExecutionFlow/OnboardingExecutionFlow.tsx index 2320d8ee5c..e7ac45841c 100644 --- a/src/components/Employee/OnboardingExecutionFlow/OnboardingExecutionFlow.tsx +++ b/src/components/Employee/OnboardingExecutionFlow/OnboardingExecutionFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { onboardingExecutionMachine, @@ -9,6 +8,7 @@ import { type OnboardingContextInterface, type OnboardingDefaultValues, } from './OnboardingExecutionFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { OnEventType } from '@/components/Base/useBase' import type { EventType, EmployeeOnboardingStatus } from '@/shared/constants' diff --git a/src/components/Employee/OnboardingExecutionFlow/onboardingExecutionStateMachine.ts b/src/components/Employee/OnboardingExecutionFlow/onboardingExecutionStateMachine.ts index d29571ce21..ea66601807 100644 --- a/src/components/Employee/OnboardingExecutionFlow/onboardingExecutionStateMachine.ts +++ b/src/components/Employee/OnboardingExecutionFlow/onboardingExecutionStateMachine.ts @@ -1,10 +1,10 @@ -import { transition, reduce, state, guard } from 'robot3' import { FederalTaxesContextual, StateTaxesContextual, DeductionsContextual, type OnboardingContextInterface, } from './OnboardingExecutionFlowComponents' +import { transition, reduce, state, guard } from '@/lib/state-machine' import { componentEvents, EmployeeSelfOnboardingStatuses, diff --git a/src/components/Employee/OnboardingFlow/OnboardingFlow.tsx b/src/components/Employee/OnboardingFlow/OnboardingFlow.tsx index ad501f9c91..e8dc27206f 100644 --- a/src/components/Employee/OnboardingFlow/OnboardingFlow.tsx +++ b/src/components/Employee/OnboardingFlow/OnboardingFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { employeeOnboardingMachine } from './onboardingStateMachine' import { @@ -6,6 +5,7 @@ import { type OnboardingContextInterface, EmployeeListContextual, } from './OnboardingFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { BaseComponentInterface } from '@/components/Base' import type { RequireAtLeastOne } from '@/types/Helpers' diff --git a/src/components/Employee/OnboardingFlow/onboardingStateMachine.ts b/src/components/Employee/OnboardingFlow/onboardingStateMachine.ts index 425b517783..42d2ca4a63 100644 --- a/src/components/Employee/OnboardingFlow/onboardingStateMachine.ts +++ b/src/components/Employee/OnboardingFlow/onboardingStateMachine.ts @@ -1,9 +1,9 @@ -import { transition, reduce, state } from 'robot3' import { EmployeeListContextual, OnboardingExecutionFlowContextual, type OnboardingContextInterface, } from './OnboardingFlowComponents' +import { transition, reduce, state } from '@/lib/state-machine' import { componentEvents, type EmployeeOnboardingStatus } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/PaymentMethod/management/PaymentMethod.tsx b/src/components/Employee/PaymentMethod/management/PaymentMethod.tsx index e66f1b2326..4d4304c117 100644 --- a/src/components/Employee/PaymentMethod/management/PaymentMethod.tsx +++ b/src/components/Employee/PaymentMethod/management/PaymentMethod.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import type { PaymentMethodContextInterface } from './PaymentMethodComponents' import { @@ -7,6 +6,7 @@ import { PaymentMethodSplitFormContextual, } from './PaymentMethodComponents' import { paymentMethodStateMachine } from './paymentMethodStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/PaymentMethod/management/paymentMethodStateMachine.ts b/src/components/Employee/PaymentMethod/management/paymentMethodStateMachine.ts index 9f4eca45cd..be4d983443 100644 --- a/src/components/Employee/PaymentMethod/management/paymentMethodStateMachine.ts +++ b/src/components/Employee/PaymentMethod/management/paymentMethodStateMachine.ts @@ -1,4 +1,3 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { PaymentMethodContextInterface, @@ -9,6 +8,7 @@ import { PaymentMethodBankFormContextual, PaymentMethodSplitFormContextual, } from './PaymentMethodComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/PaymentMethod/onboarding/PaymentMethod.tsx b/src/components/Employee/PaymentMethod/onboarding/PaymentMethod.tsx index 8933b1143e..600fd96618 100644 --- a/src/components/Employee/PaymentMethod/onboarding/PaymentMethod.tsx +++ b/src/components/Employee/PaymentMethod/onboarding/PaymentMethod.tsx @@ -1,9 +1,9 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import type { OnboardingContextInterface } from '../../OnboardingFlow/OnboardingFlowComponents' import type { PaymentMethodContextInterface } from './PaymentMethodComponents' import { ListViewContextual } from './PaymentMethodComponents' import { paymentMethodStateMachine } from './paymentMethodStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { useFlow } from '@/components/Flow/useFlow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' diff --git a/src/components/Employee/PaymentMethod/onboarding/paymentMethodStateMachine.ts b/src/components/Employee/PaymentMethod/onboarding/paymentMethodStateMachine.ts index 54a0e0ad77..726fc335cd 100644 --- a/src/components/Employee/PaymentMethod/onboarding/paymentMethodStateMachine.ts +++ b/src/components/Employee/PaymentMethod/onboarding/paymentMethodStateMachine.ts @@ -1,4 +1,3 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { PaymentMethodContextInterface } from './PaymentMethodComponents' import { @@ -6,6 +5,7 @@ import { BankFormContextual, SplitViewContextual, } from './PaymentMethodComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/Profile/management/Profile.tsx b/src/components/Employee/Profile/management/Profile.tsx index 51be21b8cf..f2b7803442 100644 --- a/src/components/Employee/Profile/management/Profile.tsx +++ b/src/components/Employee/Profile/management/Profile.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { CardContextual, type ProfileContextInterface } from './ProfileComponents' import { profileStateMachine } from './profileStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/Profile/management/profileStateMachine.ts b/src/components/Employee/Profile/management/profileStateMachine.ts index d19f909223..5dd4d1e40b 100644 --- a/src/components/Employee/Profile/management/profileStateMachine.ts +++ b/src/components/Employee/Profile/management/profileStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { ProfileContextInterface } from './ProfileComponents' import { CardContextual, ProfileEditFormContextual } from './ProfileComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/SelfOnboardingFlow/SelfOnboardingFlow.tsx b/src/components/Employee/SelfOnboardingFlow/SelfOnboardingFlow.tsx index 12dab43d54..f39cb721c4 100644 --- a/src/components/Employee/SelfOnboardingFlow/SelfOnboardingFlow.tsx +++ b/src/components/Employee/SelfOnboardingFlow/SelfOnboardingFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import type { SelfOnboardingContextInterface, @@ -6,6 +5,7 @@ import type { } from './SelfOnboardingComponents' import { Landing } from './SelfOnboardingComponents' import { employeeSelfOnboardingMachine } from './selfOnboardingMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' export type { SelfOnboardingFlowProps } from './SelfOnboardingComponents' diff --git a/src/components/Employee/SelfOnboardingFlow/selfOnboardingMachine.ts b/src/components/Employee/SelfOnboardingFlow/selfOnboardingMachine.ts index 2d55d75f1e..2179186498 100644 --- a/src/components/Employee/SelfOnboardingFlow/selfOnboardingMachine.ts +++ b/src/components/Employee/SelfOnboardingFlow/selfOnboardingMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state } from 'robot3' import type { SelfOnboardingContextInterface } from './SelfOnboardingComponents' import { Profile, @@ -8,6 +7,7 @@ import { OnboardingSummary, DocumentSigner, } from './SelfOnboardingComponents' +import { transition, reduce, state } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/StateTaxes/management/StateTaxes.tsx b/src/components/Employee/StateTaxes/management/StateTaxes.tsx index 903c527d76..a21ea608d1 100644 --- a/src/components/Employee/StateTaxes/management/StateTaxes.tsx +++ b/src/components/Employee/StateTaxes/management/StateTaxes.tsx @@ -1,7 +1,7 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { StateTaxesCardContextual, type StateTaxesContextInterface } from './StateTaxesComponents' import { stateTaxesStateMachine } from './stateTaxesStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/StateTaxes/management/stateTaxesStateMachine.ts b/src/components/Employee/StateTaxes/management/stateTaxesStateMachine.ts index 7084de0d94..5e51dbe82c 100644 --- a/src/components/Employee/StateTaxes/management/stateTaxesStateMachine.ts +++ b/src/components/Employee/StateTaxes/management/stateTaxesStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { StateTaxesContextInterface, StateTaxesSuccessAlertCode } from './StateTaxesComponents' import { StateTaxesCardContextual, StateTaxesEditFormContextual } from './StateTaxesComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Employee/Terminations/TerminationFlow/TerminationFlow.tsx b/src/components/Employee/Terminations/TerminationFlow/TerminationFlow.tsx index 3f2da76c1c..e69e246c9d 100644 --- a/src/components/Employee/Terminations/TerminationFlow/TerminationFlow.tsx +++ b/src/components/Employee/Terminations/TerminationFlow/TerminationFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { terminationMachine, terminationBreadcrumbNodes } from './terminationStateMachine' import type { @@ -6,6 +5,7 @@ import type { TerminationFlowContextInterface, } from './TerminationFlowComponents' import { TerminateEmployeeContextual } from './TerminationFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { buildBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Employee/Terminations/TerminationFlow/terminationStateMachine.test.ts b/src/components/Employee/Terminations/TerminationFlow/terminationStateMachine.test.ts index 0e4e5318f1..c46693777b 100644 --- a/src/components/Employee/Terminations/TerminationFlow/terminationStateMachine.test.ts +++ b/src/components/Employee/Terminations/TerminationFlow/terminationStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { terminationMachine, terminationBreadcrumbNodes } from './terminationStateMachine' import type { TerminationFlowContextInterface } from './TerminationFlowComponents' import { componentEvents } from '@/shared/constants' diff --git a/src/components/Employee/Terminations/TerminationFlow/terminationStateMachine.ts b/src/components/Employee/Terminations/TerminationFlow/terminationStateMachine.ts index 6bb55d8203..a228632f8b 100644 --- a/src/components/Employee/Terminations/TerminationFlow/terminationStateMachine.ts +++ b/src/components/Employee/Terminations/TerminationFlow/terminationStateMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state, guard } from 'robot3' import type { PayrollOption } from '../types' import type { TerminationFlowContextInterface, @@ -10,6 +9,7 @@ import { DismissalFlowContextual, PayrollLandingContextual, } from './TerminationFlowComponents' +import { transition, reduce, state, guard } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import type { BreadcrumbNodes } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' diff --git a/src/components/Employee/WorkAddress/management/WorkAddress.tsx b/src/components/Employee/WorkAddress/management/WorkAddress.tsx index 572b73f55a..659b3e78d8 100644 --- a/src/components/Employee/WorkAddress/management/WorkAddress.tsx +++ b/src/components/Employee/WorkAddress/management/WorkAddress.tsx @@ -1,10 +1,10 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { WorkAddressCardContextual, type WorkAddressContextInterface, } from './WorkAddressComponents' import { workAddressStateMachine } from './workAddressStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { useComponentDictionary } from '@/i18n/I18n' diff --git a/src/components/Employee/WorkAddress/management/workAddressStateMachine.ts b/src/components/Employee/WorkAddress/management/workAddressStateMachine.ts index b0c28309db..bd4d4f6df1 100644 --- a/src/components/Employee/WorkAddress/management/workAddressStateMachine.ts +++ b/src/components/Employee/WorkAddress/management/workAddressStateMachine.ts @@ -1,7 +1,7 @@ -import { reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import type { WorkAddressContextInterface } from './WorkAddressComponents' import { WorkAddressCardContextual, WorkAddressEditFormContextual } from './WorkAddressComponents' +import { reduce, state, transition } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Flow/Flow.test.tsx b/src/components/Flow/Flow.test.tsx index dddd311072..d333c7e14c 100644 --- a/src/components/Flow/Flow.test.tsx +++ b/src/components/Flow/Flow.test.tsx @@ -1,11 +1,11 @@ import { describe, expect, it, vi } from 'vitest' import { screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { createMachine, reduce, state, transition } from 'robot3' import type { ComponentType } from 'react' import { Flow } from './Flow' import type { FlowContextInterface } from './useFlow' import { useFlow } from './useFlow' +import { createMachine, reduce, state, transition } from '@/lib/state-machine' import { componentEvents, type EventType } from '@/shared/constants' import { renderWithProviders } from '@/test-utils/renderWithProviders' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/components/Flow/Flow.tsx b/src/components/Flow/Flow.tsx index c99f43823d..bfd8784574 100644 --- a/src/components/Flow/Flow.tsx +++ b/src/components/Flow/Flow.tsx @@ -1,11 +1,10 @@ import { Suspense } from 'react' -import { useMachine } from 'react-robot' -import { type Machine, type SendFunction } from 'robot3' import type { OnEventType } from '../Base/useBase' import { Flex } from '../Common/Flex' import type { FlowContextInterface } from './useFlow' import { FlowContext } from './useFlow' import { FlowHeader } from './FlowHeader' +import { useMachine, type Machine } from '@/lib/state-machine' import { useLoadingIndicator } from '@/contexts/LoadingIndicatorProvider/useLoadingIndicator' import { type EventType } from '@/shared/constants' @@ -35,16 +34,15 @@ type FlowProps = { } /** - * Drives a robot3 state machine that orchestrates a multi-step SDK flow, rendering the active + * Drives a state machine that orchestrates a multi-step SDK flow, rendering the active * step component inside a {@link FlowContext} provider with optional header chrome above it. * * @remarks - * Re-emits every event produced by the state machine (or the active child machine, when one is - * nested) to the upstream `onEvent` callback, so the consuming flow component (e.g. `PayrollFlow`, - * `OnboardingFlow`) can forward them to partner code. The set of event types is defined by the - * machine itself rather than a fixed catalogue. + * Re-emits every event to the upstream `onEvent` callback, so the consuming flow component + * (e.g. `PayrollFlow`, `OnboardingFlow`) can forward them to partner code. The set of event + * types is defined by the machine itself rather than a fixed catalogue. * - * @typeParam M - The robot3 {@link Machine} type whose context extends {@link FlowContextInterface}. + * @typeParam M - The {@link Machine} type whose context extends {@link FlowContextInterface}. * @param props - Component props: the `machine` instance to run and an `onEvent` handler that * receives every event the machine emits. * @returns A React element rendering the machine's current `component` inside the flow context, @@ -55,21 +53,13 @@ export const Flow = >({ onEvent, machine, }: FlowProps) => { - const [current, send, service] = useMachine(machine, { + const [current, send] = useMachine(machine, { onEvent: handleEvent, component: null, }) function handleEvent(type: EventType, data: unknown): void { - const event = { type, payload: data } - const sendFn = send as SendFunction - //When dealing with nested state machine, correct machine needs to recieve an event - if (service.child) { - ;(service.child.send as SendFunction)(event) - } else { - sendFn(event) - } - // Pass event upstream - onEvent can be optional on Flow component + send({ type, payload: data }) onEvent(type, data) } diff --git a/src/components/InformationRequests/InformationRequests.tsx b/src/components/InformationRequests/InformationRequests.tsx index 852d95b6fd..35d620f9d1 100644 --- a/src/components/InformationRequests/InformationRequests.tsx +++ b/src/components/InformationRequests/InformationRequests.tsx @@ -1,10 +1,9 @@ -import { createMachine } from 'robot3' -import { useMachine } from 'react-robot' import { Suspense, useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { InformationRequestList } from './InformationRequestList' import { informationRequestsMachine } from './informationRequestsStateMachine' import { type InformationRequestsContextInterface } from './InformationRequestsComponents' +import { createMachine, useMachine } from '@/lib/state-machine' import { BaseBoundaries, type BaseComponentInterface } from '@/components/Base' import { Flex } from '@/components/Common' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' diff --git a/src/components/InformationRequests/informationRequestsStateMachine.tsx b/src/components/InformationRequests/informationRequestsStateMachine.tsx index b4d41b286f..b17aa32491 100644 --- a/src/components/InformationRequests/informationRequestsStateMachine.tsx +++ b/src/components/InformationRequests/informationRequestsStateMachine.tsx @@ -1,6 +1,6 @@ -import { state, transition, reduce } from 'robot3' import type { InformationRequestsContextInterface } from './InformationRequestsComponents' import { InformationRequestFormContextual } from './InformationRequestsComponents' +import { state, transition, reduce } from '@/lib/state-machine' import { informationRequestEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Payroll/ConfirmWireDetails/ConfirmWireDetails.tsx b/src/components/Payroll/ConfirmWireDetails/ConfirmWireDetails.tsx index 36dcfb1c81..79e371ea8f 100644 --- a/src/components/Payroll/ConfirmWireDetails/ConfirmWireDetails.tsx +++ b/src/components/Payroll/ConfirmWireDetails/ConfirmWireDetails.tsx @@ -1,5 +1,3 @@ -import { createMachine } from 'robot3' -import { useMachine } from 'react-robot' import { Suspense, useMemo, useRef, useState } from 'react' import { useWireInRequestsListSuspense } from '@gusto/embedded-api/react-query/wireInRequestsList' import { ConfirmWireDetailsBanner } from './ConfirmWireDetailsBanner' @@ -11,6 +9,7 @@ import styles from './ConfirmWireDetails.module.scss' import { BaseComponent, BaseBoundaries } from '@/components/Base' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' import { FlowContext } from '@/components/Flow/useFlow' +import { createMachine, useMachine } from '@/lib/state-machine' import { payrollWireEvents, type EventType } from '@/shared/constants' /** diff --git a/src/components/Payroll/ConfirmWireDetails/confirmWireDetailsStateMachine.tsx b/src/components/Payroll/ConfirmWireDetails/confirmWireDetailsStateMachine.tsx index e6fd3cd790..9e3bfb89e2 100644 --- a/src/components/Payroll/ConfirmWireDetails/confirmWireDetailsStateMachine.tsx +++ b/src/components/Payroll/ConfirmWireDetails/confirmWireDetailsStateMachine.tsx @@ -1,10 +1,10 @@ -import { state, transition, reduce } from 'robot3' import type { ConfirmationAlert } from './types' import type { ConfirmWireDetailsContextInterface } from './ConfirmWireDetailsComponents' import { WireInstructionsContextual, ConfirmWireDetailsFormContextual, } from './ConfirmWireDetailsComponents' +import { state, transition, reduce } from '@/lib/state-machine' import { payrollWireEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Payroll/Dismissal/DismissalFlow.tsx b/src/components/Payroll/Dismissal/DismissalFlow.tsx index 33eef4effd..b1408fccaa 100644 --- a/src/components/Payroll/Dismissal/DismissalFlow.tsx +++ b/src/components/Payroll/Dismissal/DismissalFlow.tsx @@ -1,5 +1,4 @@ import { useMemo } from 'react' -import { createMachine } from 'robot3' import { dismissalMachine, dismissalBreadcrumbsNodes } from './dismissalStateMachine' import { DismissalPayPeriodSelectionContextual, @@ -7,6 +6,7 @@ import { type DismissalFlowContextInterface, type DismissalFlowProps, } from './DismissalFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { BaseComponent } from '@/components/Base/Base' import { buildBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Payroll/Dismissal/dismissalStateMachine.test.ts b/src/components/Payroll/Dismissal/dismissalStateMachine.test.ts index 8e49a6c9ef..7b8cf7197b 100644 --- a/src/components/Payroll/Dismissal/dismissalStateMachine.test.ts +++ b/src/components/Payroll/Dismissal/dismissalStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { dismissalMachine, dismissalBreadcrumbsNodes } from './dismissalStateMachine' import type { DismissalFlowContextInterface } from './DismissalFlowComponents' import { componentEvents } from '@/shared/constants' diff --git a/src/components/Payroll/Dismissal/dismissalStateMachine.ts b/src/components/Payroll/Dismissal/dismissalStateMachine.ts index 1f601d9536..73f1c6c013 100644 --- a/src/components/Payroll/Dismissal/dismissalStateMachine.ts +++ b/src/components/Payroll/Dismissal/dismissalStateMachine.ts @@ -1,9 +1,9 @@ -import { state, transition, reduce, guard } from 'robot3' import { DismissalPayPeriodSelectionContextual, DismissalExecutionContextual, type DismissalFlowContextInterface, } from './DismissalFlowComponents' +import { state, transition, reduce, guard } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' import type { BreadcrumbNodes } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' diff --git a/src/components/Payroll/OffCycle/OffCycleExecution.test.tsx b/src/components/Payroll/OffCycle/OffCycleExecution.test.tsx index 5737635553..8eb4192a84 100644 --- a/src/components/Payroll/OffCycle/OffCycleExecution.test.tsx +++ b/src/components/Payroll/OffCycle/OffCycleExecution.test.tsx @@ -3,10 +3,10 @@ import { screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { http, HttpResponse } from 'msw' import { useMemo } from 'react' -import { createMachine } from 'robot3' import type { OffCycleFlowContextInterface } from './OffCycleFlowComponents' import { OffCycleExecutionContextual } from './OffCycleFlowComponents' import { offCycleMachine, offCycleBreadcrumbsNodes } from './offCycleStateMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { buildBreadcrumbs } from '@/helpers/breadcrumbHelpers' import { server } from '@/test/mocks/server' diff --git a/src/components/Payroll/OffCycle/OffCycleFlow.tsx b/src/components/Payroll/OffCycle/OffCycleFlow.tsx index 7c3991633b..c5206251d0 100644 --- a/src/components/Payroll/OffCycle/OffCycleFlow.tsx +++ b/src/components/Payroll/OffCycle/OffCycleFlow.tsx @@ -1,11 +1,11 @@ import { useMemo } from 'react' -import { createMachine } from 'robot3' import { offCycleMachine, offCycleBreadcrumbsNodes } from './offCycleStateMachine' import { OffCycleCreationContextual, type OffCycleFlowContextInterface, type OffCycleFlowProps, } from './OffCycleFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { buildBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Payroll/OffCycle/offCycleStateMachine.test.ts b/src/components/Payroll/OffCycle/offCycleStateMachine.test.ts index 2cb8fc0221..9c6aa46142 100644 --- a/src/components/Payroll/OffCycle/offCycleStateMachine.test.ts +++ b/src/components/Payroll/OffCycle/offCycleStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { offCycleMachine, offCycleBreadcrumbsNodes } from './offCycleStateMachine' import type { OffCycleFlowContextInterface } from './OffCycleFlowComponents' import { componentEvents } from '@/shared/constants' diff --git a/src/components/Payroll/OffCycle/offCycleStateMachine.ts b/src/components/Payroll/OffCycle/offCycleStateMachine.ts index 4c20fc52a3..6e76a901b7 100644 --- a/src/components/Payroll/OffCycle/offCycleStateMachine.ts +++ b/src/components/Payroll/OffCycle/offCycleStateMachine.ts @@ -1,9 +1,9 @@ -import { state, transition, reduce, guard } from 'robot3' import { OffCycleCreationContextual, OffCycleExecutionContextual, type OffCycleFlowContextInterface, } from './OffCycleFlowComponents' +import { state, transition, reduce, guard } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' import type { BreadcrumbNodes } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' diff --git a/src/components/Payroll/PayrollExecutionFlow/PayrollExecutionFlow.tsx b/src/components/Payroll/PayrollExecutionFlow/PayrollExecutionFlow.tsx index ee1dc59014..5784ba3a42 100644 --- a/src/components/Payroll/PayrollExecutionFlow/PayrollExecutionFlow.tsx +++ b/src/components/Payroll/PayrollExecutionFlow/PayrollExecutionFlow.tsx @@ -1,5 +1,4 @@ import { useMemo } from 'react' -import { createMachine } from 'robot3' import type { PayrollPayPeriodType } from '@gusto/embedded-api/models/components/payrollpayperiodtype' import type { ConfirmWireDetailsComponentType } from '../ConfirmWireDetails/ConfirmWireDetails' import { @@ -12,6 +11,7 @@ import { payrollExecutionMachine, getPayrollExecutionBreadcrumbsNodes, } from './payrollExecutionMachine' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { FlowBreadcrumb } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' import { buildBreadcrumbs, updateBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Payroll/PayrollExecutionFlow/payrollExecutionMachine.test.ts b/src/components/Payroll/PayrollExecutionFlow/payrollExecutionMachine.test.ts index 3e0fffd73f..4ebb4be9e5 100644 --- a/src/components/Payroll/PayrollExecutionFlow/payrollExecutionMachine.test.ts +++ b/src/components/Payroll/PayrollExecutionFlow/payrollExecutionMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { payrollExecutionMachine, getPayrollExecutionBreadcrumbsNodes, diff --git a/src/components/Payroll/PayrollExecutionFlow/payrollExecutionMachine.ts b/src/components/Payroll/PayrollExecutionFlow/payrollExecutionMachine.ts index b064e197a0..78abb03ee2 100644 --- a/src/components/Payroll/PayrollExecutionFlow/payrollExecutionMachine.ts +++ b/src/components/Payroll/PayrollExecutionFlow/payrollExecutionMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state, guard } from 'robot3' import type { PayrollPayPeriodType } from '@gusto/embedded-api/models/components/payrollpayperiodtype' import type { PayrollFlowAlert } from '../PayrollFlow/PayrollFlowComponents' import { @@ -9,6 +8,7 @@ import { PayrollBlockerContextual, type PayrollFlowContextInterface, } from '../PayrollFlow/PayrollFlowComponents' +import { transition, reduce, state, guard } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import { diff --git a/src/components/Payroll/PayrollFlow/PayrollFlow.tsx b/src/components/Payroll/PayrollFlow/PayrollFlow.tsx index 9fc9bddb2d..84267acaff 100644 --- a/src/components/Payroll/PayrollFlow/PayrollFlow.tsx +++ b/src/components/Payroll/PayrollFlow/PayrollFlow.tsx @@ -1,4 +1,3 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { payrollFlowBreadcrumbsNodes, payrollFlowMachine } from './payrollStateMachine' import type { PayrollFlowProps } from './PayrollFlowComponents' @@ -7,6 +6,7 @@ import { PayrollLandingContextual, type PayrollFlowContextInterface, } from './PayrollFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { buildBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Payroll/PayrollFlow/payrollStateMachine.test.ts b/src/components/Payroll/PayrollFlow/payrollStateMachine.test.ts index 4b50efbf28..be26ea1b3f 100644 --- a/src/components/Payroll/PayrollFlow/payrollStateMachine.test.ts +++ b/src/components/Payroll/PayrollFlow/payrollStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { payrollFlowMachine, payrollFlowBreadcrumbsNodes } from './payrollStateMachine' import type { PayrollFlowContextInterface } from './PayrollFlowComponents' import { componentEvents } from '@/shared/constants' diff --git a/src/components/Payroll/PayrollFlow/payrollStateMachine.ts b/src/components/Payroll/PayrollFlow/payrollStateMachine.ts index a076311a24..32dcd92deb 100644 --- a/src/components/Payroll/PayrollFlow/payrollStateMachine.ts +++ b/src/components/Payroll/PayrollFlow/payrollStateMachine.ts @@ -1,4 +1,3 @@ -import { state, transition, reduce, guard } from 'robot3' import type { PayrollPayPeriodType } from '@gusto/embedded-api/models/components/payrollpayperiodtype' import type { PayrollExecutionInitialState } from '../PayrollExecutionFlow' import { @@ -11,6 +10,7 @@ import { import { PayrollExecutionFlowContextual } from './PayrollExecutionFlowContextual' import { TransitionFlowContextual } from './TransitionFlowContextual' import { OffCycleFlowContextual } from './OffCycleFlowContextual' +import { state, transition, reduce, guard } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import { patchBreadcrumbsHeader, updateBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Payroll/PayrollLanding/PayrollLanding.tsx b/src/components/Payroll/PayrollLanding/PayrollLanding.tsx index 6e2164e554..2d6db1a303 100644 --- a/src/components/Payroll/PayrollLanding/PayrollLanding.tsx +++ b/src/components/Payroll/PayrollLanding/PayrollLanding.tsx @@ -1,5 +1,4 @@ import { useMemo } from 'react' -import { createMachine } from 'robot3' import type { ConfirmWireDetailsComponentType } from '../ConfirmWireDetails/ConfirmWireDetails' import { payrollLandingMachine, payrollLandingBreadcrumbNodes } from './payrollLandingStateMachine' import { @@ -7,6 +6,7 @@ import { type PayrollLandingFlowContextInterface, type PayrollLandingFlowProps, } from './PayrollLandingFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import type { BaseComponentInterface } from '@/components/Base/Base' import { BaseComponent } from '@/components/Base/Base' diff --git a/src/components/Payroll/PayrollLanding/payrollLandingStateMachine.ts b/src/components/Payroll/PayrollLanding/payrollLandingStateMachine.ts index bc73d2c38f..f1ee4d51ea 100644 --- a/src/components/Payroll/PayrollLanding/payrollLandingStateMachine.ts +++ b/src/components/Payroll/PayrollLanding/payrollLandingStateMachine.ts @@ -1,10 +1,10 @@ -import { transition, reduce, state, guard } from 'robot3' import { PayrollLandingTabsContextual, PayrollLandingReceiptsContextual, PayrollLandingOverviewContextual, type PayrollLandingFlowContextInterface, } from './PayrollLandingFlowComponents' +import { transition, reduce, state, guard } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' import type { BreadcrumbNodes } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' diff --git a/src/components/Payroll/PrintChecks/PrintChecks.tsx b/src/components/Payroll/PrintChecks/PrintChecks.tsx index ac39353d11..006e7cfdd4 100644 --- a/src/components/Payroll/PrintChecks/PrintChecks.tsx +++ b/src/components/Payroll/PrintChecks/PrintChecks.tsx @@ -1,10 +1,9 @@ -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 { createMachine, useMachine } from '@/lib/state-machine' import { BaseComponent } from '@/components/Base' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' import { FlowContext } from '@/components/Flow/useFlow' diff --git a/src/components/Payroll/PrintChecks/printChecksStateMachine.tsx b/src/components/Payroll/PrintChecks/printChecksStateMachine.tsx index 6124518352..b739f09de1 100644 --- a/src/components/Payroll/PrintChecks/printChecksStateMachine.tsx +++ b/src/components/Payroll/PrintChecks/printChecksStateMachine.tsx @@ -1,10 +1,10 @@ -import { state, transition, reduce } from 'robot3' import type { PrintChecksContextInterface } from './PrintChecksComponents' import { PrintChecksFormContextual, PrintChecksFailureContextual, PrintChecksSummaryContextual, } from './PrintChecksComponents' +import { state, transition, reduce } from '@/lib/state-machine' import { printChecksEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Payroll/RecoveryCases/RecoveryCases.tsx b/src/components/Payroll/RecoveryCases/RecoveryCases.tsx index ba30a13ed4..c1e36cf2ab 100644 --- a/src/components/Payroll/RecoveryCases/RecoveryCases.tsx +++ b/src/components/Payroll/RecoveryCases/RecoveryCases.tsx @@ -1,9 +1,8 @@ -import { createMachine } from 'robot3' -import { useMachine } from 'react-robot' import { useMemo, useState } from 'react' import { RecoveryCasesList } from './RecoveryCasesList' import { recoveryCasesMachine } from './recoveryCasesStateMachine' import { type RecoveryCasesContextInterface } from './RecoveryCasesComponents' +import { createMachine, useMachine } from '@/lib/state-machine' import { BaseComponent, type BaseComponentInterface } from '@/components/Base' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' import { FlowContext } from '@/components/Flow/useFlow' diff --git a/src/components/Payroll/RecoveryCases/recoveryCasesStateMachine.tsx b/src/components/Payroll/RecoveryCases/recoveryCasesStateMachine.tsx index 832a32c9de..b4e946ca94 100644 --- a/src/components/Payroll/RecoveryCases/recoveryCasesStateMachine.tsx +++ b/src/components/Payroll/RecoveryCases/recoveryCasesStateMachine.tsx @@ -1,6 +1,6 @@ -import { state, transition, reduce } from 'robot3' import type { RecoveryCasesContextInterface } from './RecoveryCasesComponents' import { RecoveryCasesResubmitContextual } from './RecoveryCasesComponents' +import { state, transition, reduce } from '@/lib/state-machine' import { recoveryCasesEvents } from '@/shared/constants' import type { MachineEventType, MachineTransition } from '@/types/Helpers' diff --git a/src/components/Payroll/Transition/TransitionFlow.tsx b/src/components/Payroll/Transition/TransitionFlow.tsx index 7fb0aa6d15..caa9ca3ba1 100644 --- a/src/components/Payroll/Transition/TransitionFlow.tsx +++ b/src/components/Payroll/Transition/TransitionFlow.tsx @@ -1,5 +1,4 @@ import { useMemo } from 'react' -import { createMachine } from 'robot3' import { transitionMachine, transitionBreadcrumbsNodes } from './transitionStateMachine' import { TransitionCreationContextual, @@ -7,6 +6,7 @@ import { type TransitionFlowContextInterface, type TransitionFlowProps, } from './TransitionFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' import { buildBreadcrumbs } from '@/helpers/breadcrumbHelpers' diff --git a/src/components/Payroll/Transition/transitionStateMachine.test.ts b/src/components/Payroll/Transition/transitionStateMachine.test.ts index eba09e7fba..85f5791767 100644 --- a/src/components/Payroll/Transition/transitionStateMachine.test.ts +++ b/src/components/Payroll/Transition/transitionStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { transitionMachine, transitionBreadcrumbsNodes } from './transitionStateMachine' import type { TransitionFlowContextInterface } from './TransitionFlowComponents' import { componentEvents } from '@/shared/constants' diff --git a/src/components/Payroll/Transition/transitionStateMachine.ts b/src/components/Payroll/Transition/transitionStateMachine.ts index 15413f058d..64bd46d4ae 100644 --- a/src/components/Payroll/Transition/transitionStateMachine.ts +++ b/src/components/Payroll/Transition/transitionStateMachine.ts @@ -1,9 +1,9 @@ -import { state, transition, reduce, guard } from 'robot3' import { TransitionCreationContextual, TransitionExecutionContextual, type TransitionFlowContextInterface, } from './TransitionFlowComponents' +import { state, transition, reduce, guard } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' import type { BreadcrumbNodes } from '@/components/Common/FlowBreadcrumbs/FlowBreadcrumbsTypes' diff --git a/src/components/TimeOff/TimeOffFlow/TimeOffFlow.tsx b/src/components/TimeOff/TimeOffFlow/TimeOffFlow.tsx index a64c72960b..7d15f3d7e9 100644 --- a/src/components/TimeOff/TimeOffFlow/TimeOffFlow.tsx +++ b/src/components/TimeOff/TimeOffFlow/TimeOffFlow.tsx @@ -1,8 +1,8 @@ -import { createMachine } from 'robot3' import { useMemo } from 'react' import { timeOffMachine } from './timeOffStateMachine' import type { TimeOffFlowProps, TimeOffFlowContextInterface } from './TimeOffFlowComponents' import { PolicyListContextual } from './TimeOffFlowComponents' +import { createMachine } from '@/lib/state-machine' import { Flow } from '@/components/Flow/Flow' /** diff --git a/src/components/TimeOff/TimeOffFlow/timeOffStateMachine.test.ts b/src/components/TimeOff/TimeOffFlow/timeOffStateMachine.test.ts index 94b962b480..f342a427c8 100644 --- a/src/components/TimeOff/TimeOffFlow/timeOffStateMachine.test.ts +++ b/src/components/TimeOff/TimeOffFlow/timeOffStateMachine.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { createMachine, interpret, type SendFunction } from 'robot3' +import { createMachine, interpret, type SendFunction } from '@/lib/state-machine' import { timeOffMachine } from './timeOffStateMachine' import type { TimeOffFlowContextInterface } from './TimeOffFlowComponents' import { componentEvents } from '@/shared/constants' diff --git a/src/components/TimeOff/TimeOffFlow/timeOffStateMachine.ts b/src/components/TimeOff/TimeOffFlow/timeOffStateMachine.ts index 137e5c16ee..db71e62a11 100644 --- a/src/components/TimeOff/TimeOffFlow/timeOffStateMachine.ts +++ b/src/components/TimeOff/TimeOffFlow/timeOffStateMachine.ts @@ -1,4 +1,3 @@ -import { transition, reduce, state, guard } from 'robot3' import { PolicyListContextual, SelectPolicyTypeContextual, @@ -17,6 +16,7 @@ import { type AddEmployeesSource, } from './TimeOffFlowComponents' import type { TimeOffPolicyType } from './timeOffPolicyTypes' +import { transition, reduce, state, guard } from '@/lib/state-machine' import { componentEvents } from '@/shared/constants' import type { MachineTransition } from '@/types/Helpers' diff --git a/src/lib/state-machine/__tests__/core.test.ts b/src/lib/state-machine/__tests__/core.test.ts new file mode 100644 index 0000000000..fa3e0e9ad8 --- /dev/null +++ b/src/lib/state-machine/__tests__/core.test.ts @@ -0,0 +1,246 @@ +import { describe, it, expect, vi } from 'vitest' +import { + guard, + reduce, + transition, + state, + createMachine, + interpret, + applyTransition, +} from '../core' + +describe('state machine core', () => { + describe('applyTransition', () => { + it('transitions to a new state and applies the reducer', () => { + const states = { + a: state( + transition( + 'GO', + 'b', + reduce((ctx: { count: number }) => ({ ...ctx, count: ctx.count + 1 })), + ), + ), + b: state(), + } + + const result = applyTransition(states, 'a', { count: 0 }, { type: 'GO' }) + + expect(result).toMatchObject({ current: 'b', context: { count: 1 } }) + }) + + it('returns null for unhandled events', () => { + const states = { + a: state(transition('GO', 'b')), + } + + const result = applyTransition(states, 'a', {}, { type: 'UNKNOWN' }) + + expect(result).toBeNull() + }) + + it('evaluates guards and picks the first matching transition', () => { + const states = { + a: state( + transition( + 'GO', + 'b', + guard((ctx: { val: string }) => ctx.val === 'yes'), + ), + transition('GO', 'c'), + ), + } + + expect(applyTransition(states, 'a', { val: 'no' }, { type: 'GO' })).toMatchObject({ + current: 'c', + }) + expect(applyTransition(states, 'a', { val: 'yes' }, { type: 'GO' })).toMatchObject({ + current: 'b', + }) + }) + + it('composes multiple guards with AND', () => { + const states = { + a: state( + transition( + 'GO', + 'b', + guard((_ctx: { x: number }) => true), + guard((ctx: { x: number }) => ctx.x > 5), + ), + ), + } + + expect(applyTransition(states, 'a', { x: 3 }, { type: 'GO' })).toBeNull() + expect(applyTransition(states, 'a', { x: 10 }, { type: 'GO' })).toMatchObject({ + current: 'b', + }) + }) + + it('pipes reducers in order', () => { + const states = { + a: state( + transition( + 'GO', + 'b', + reduce((ctx: { items: string[] }) => ({ ...ctx, items: [...ctx.items, 'first'] })), + reduce((ctx: { items: string[] }) => ({ ...ctx, items: [...ctx.items, 'second'] })), + ), + ), + b: state(), + } + + const result = applyTransition(states, 'a', { items: [] }, { type: 'GO' }) + + expect(result).toMatchObject({ + current: 'b', + context: { items: ['first', 'second'] }, + }) + }) + + it('passes the event to reducers', () => { + const states = { + a: state( + transition( + 'SET', + 'b', + reduce((_ctx: { value: string }, ev: { payload: string }) => ({ + value: ev.payload, + })), + ), + ), + b: state(), + } + + const result = applyTransition(states, 'a', { value: '' }, { type: 'SET', payload: 'hello' }) + + expect(result).toMatchObject({ + current: 'b', + context: { value: 'hello' }, + }) + }) + + it('passes the event to guards', () => { + const states = { + a: state( + transition( + 'GO', + 'b', + guard((_ctx: object, ev: { payload: { allowed: boolean } }) => ev.payload.allowed), + ), + ), + } + + expect( + applyTransition(states, 'a', {}, { type: 'GO', payload: { allowed: false } }), + ).toBeNull() + expect( + applyTransition(states, 'a', {}, { type: 'GO', payload: { allowed: true } }), + ).toMatchObject({ current: 'b' }) + }) + + it('warns in dev mode for unhandled events', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) + const states = { a: state() } + + applyTransition(states, 'a', {}, { type: 'NOPE' }) + + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('No transition for event "NOPE" in state "a"'), + ) + warnSpy.mockRestore() + }) + }) + + describe('createMachine', () => { + it('stores the initial state, states, and context factory', () => { + const factory = () => ({ value: 42 }) + const machine = createMachine('start', { start: state() }, factory) + + expect(machine.initial).toBe('start') + expect(machine.states.start).toBeDefined() + expect(machine.contextFactory()).toMatchObject({ value: 42 }) + }) + }) + + describe('interpret', () => { + it('creates a service with the initial state and context', () => { + const machine = createMachine('idle', { idle: state(), active: state() }, () => ({ + count: 0, + })) + + const service = interpret(machine, () => {}) + + expect(service.machine.current).toBe('idle') + expect(service.context).toMatchObject({ count: 0 }) + expect(service.child).toBeUndefined() + }) + + it('transitions on send and calls onChange', () => { + const machine = createMachine( + 'a', + { + a: state( + transition( + 'NEXT', + 'b', + reduce((ctx: { step: number }) => ({ step: ctx.step + 1 })), + ), + ), + b: state(), + }, + () => ({ step: 0 }), + ) + + const onChange = vi.fn() + const service = interpret(machine, onChange) + + service.send({ type: 'NEXT' }) + + expect(service.machine.current).toBe('b') + expect(service.context).toMatchObject({ step: 1 }) + expect(onChange).toHaveBeenCalledTimes(1) + }) + + it('does not call onChange when no transition matches', () => { + const machine = createMachine('a', { a: state() }, () => ({})) + + const onChange = vi.fn() + const service = interpret(machine, onChange) + + service.send({ type: 'UNKNOWN' }) + + expect(service.machine.current).toBe('a') + expect(onChange).not.toHaveBeenCalled() + }) + + it('passes initialContext through the context factory', () => { + const machine = createMachine('start', { start: state() }, (init: { id?: string } = {}) => ({ + id: init.id ?? 'default', + })) + + const service = interpret(machine, () => {}, { id: 'custom' }) + + expect(service.context).toMatchObject({ id: 'custom' }) + }) + + it('supports sequential transitions', () => { + const machine = createMachine( + 'a', + { + a: state(transition('NEXT', 'b')), + b: state(transition('NEXT', 'c')), + c: state(), + }, + () => ({}), + ) + + const service = interpret(machine, () => {}) + + service.send({ type: 'NEXT' }) + expect(service.machine.current).toBe('b') + + service.send({ type: 'NEXT' }) + expect(service.machine.current).toBe('c') + }) + }) +}) diff --git a/src/lib/state-machine/__tests__/useMachine.test.tsx b/src/lib/state-machine/__tests__/useMachine.test.tsx new file mode 100644 index 0000000000..f0d2064e95 --- /dev/null +++ b/src/lib/state-machine/__tests__/useMachine.test.tsx @@ -0,0 +1,161 @@ +import { describe, it, expect, vi } from 'vitest' +import { render, screen, act } from '@testing-library/react' +import { createMachine, useMachine, state, transition, reduce } from '..' + +type TestContext = { component: React.ComponentType | null; count: number } + +const First = () =>
First
+const Second = () =>
Second
+ +function buildMachine(initial = 'a') { + return createMachine( + initial, + { + a: state( + transition( + 'NEXT', + 'b', + reduce((ctx: TestContext): TestContext => ({ + ...ctx, + component: Second, + count: ctx.count + 1, + })), + ), + ), + b: state( + transition( + 'BACK', + 'a', + reduce((ctx: TestContext): TestContext => ({ + ...ctx, + component: First, + count: ctx.count + 1, + })), + ), + ), + }, + (): TestContext => ({ component: First, count: 0 }), + ) +} + +function TestHarness({ machine }: { machine: ReturnType }) { + const [current, send] = useMachine(machine) + const Component = current.context.component + return ( +
+
{current.name}
+
{current.context.count}
+ {Component && } + + +
+ ) +} + +describe('useMachine', () => { + it('renders the initial component from the machine context', () => { + render() + + expect(screen.getByTestId('first')).toBeInTheDocument() + expect(screen.getByTestId('state')).toHaveTextContent('a') + expect(screen.getByTestId('count')).toHaveTextContent('0') + }) + + it('transitions on dispatch and re-renders with the new component', () => { + render() + + act(() => { + screen.getByRole('button', { name: 'next' }).click() + }) + + expect(screen.getByTestId('second')).toBeInTheDocument() + expect(screen.getByTestId('state')).toHaveTextContent('b') + expect(screen.getByTestId('count')).toHaveTextContent('1') + }) + + it('supports round-trip transitions', () => { + render() + + act(() => { + screen.getByRole('button', { name: 'next' }).click() + }) + expect(screen.getByTestId('second')).toBeInTheDocument() + + act(() => { + screen.getByRole('button', { name: 'back' }).click() + }) + expect(screen.getByTestId('first')).toBeInTheDocument() + expect(screen.getByTestId('count')).toHaveTextContent('2') + }) + + it('provides a service object with machine.current and context', () => { + let lastService: ReturnType>[2] | undefined + + function ServiceInspector({ machine }: { machine: ReturnType }) { + const [, , service] = useMachine(machine) + lastService = service + return null + } + + render() + + expect(lastService?.machine.current).toBe('a') + expect(lastService?.context.count).toBe(0) + expect(lastService?.child).toBeUndefined() + }) + + it('re-initializes when the machine reference changes', () => { + const machine1 = buildMachine('a') + const machine2 = buildMachine('b') + + const { rerender } = render() + expect(screen.getByTestId('state')).toHaveTextContent('a') + + rerender() + expect(screen.getByTestId('state')).toHaveTextContent('b') + }) + + it('passes initialContext through the context factory', () => { + type Ctx = { label: string } + const machine = createMachine('start', { start: state() }, (init?: Partial): Ctx => ({ + label: init?.label ?? 'default', + })) + + function Inspector() { + const [current] = useMachine(machine, { label: 'custom' }) + return
{current.context.label}
+ } + + render() + expect(screen.getByTestId('label')).toHaveTextContent('custom') + }) + + it('ignores events with no matching transition', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) + + render() + + act(() => { + screen.getByRole('button', { name: 'back' }).click() + }) + + expect(screen.getByTestId('state')).toHaveTextContent('a') + expect(screen.getByTestId('count')).toHaveTextContent('0') + + warnSpy.mockRestore() + }) +}) diff --git a/src/lib/state-machine/core.ts b/src/lib/state-machine/core.ts new file mode 100644 index 0000000000..416ba92502 --- /dev/null +++ b/src/lib/state-machine/core.ts @@ -0,0 +1,140 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-parameters */ +import type { + Guard, + Reducer, + TransitionDefinition, + StateDefinition, + Machine, + ContextFunction, + SendEvent, + Service, +} from './types' + +/** @internal */ +export function guard(fn: (ctx: C, ev: any) => boolean): Guard { + return { _tag: 'guard', fn } +} + +/** @internal */ +export function reduce(fn: (ctx: C, ev: any) => C): Reducer { + return { _tag: 'reduce', fn } +} + +/** @internal */ +export function transition( + event: string, + target: string, + ...modifiers: (Guard | Reducer)[] +): TransitionDefinition { + const guards: Guard[] = [] + const reducers: Reducer[] = [] + for (const mod of modifiers) { + if (mod._tag === 'guard') guards.push(mod) + else reducers.push(mod) + } + return { _tag: 'transition', event, target, guards, reducers } +} + +/** @internal */ +export function state<_T = unknown>(...transitions: TransitionDefinition[]): StateDefinition { + const transitionMap = new Map() + for (const def of transitions) { + const existing = transitionMap.get(def.event) + if (existing) { + existing.push(def) + } else { + transitionMap.set(def.event, [def]) + } + } + return { _tag: 'state', transitions: transitionMap } +} + +/** @internal */ +export function createMachine( + initial: string, + states: Record, + contextFactory: ContextFunction, +): Machine { + return { initial, states, contextFactory } +} + +/** @internal */ +export type TransitionResult = { current: string; context: C } + +/** @internal */ +export function applyTransition( + states: Record, + currentState: string, + context: C, + event: SendEvent, +): TransitionResult | null { + const stateDef = states[currentState] + if (!stateDef) { + if (import.meta.env.DEV) { + // eslint-disable-next-line no-console + console.warn(`[state-machine] Unknown state "${currentState}"`) + } + return null + } + + const candidates = stateDef.transitions.get(event.type) + if (!candidates || candidates.length === 0) { + if (import.meta.env.DEV) { + // eslint-disable-next-line no-console + console.warn( + `[state-machine] No transition for event "${event.type}" in state "${currentState}"`, + ) + } + return null + } + + for (const candidate of candidates) { + const allGuardsPass = candidate.guards.every(g => g.fn(context, event)) + if (!allGuardsPass) continue + + let nextContext = context + for (const reducer of candidate.reducers) { + nextContext = reducer.fn(nextContext, event) as C + } + + return { current: candidate.target, context: nextContext } + } + + if (import.meta.env.DEV) { + // eslint-disable-next-line no-console + console.warn( + `[state-machine] All guards failed for event "${event.type}" in state "${currentState}"`, + ) + } + return null +} + +/** @internal */ +export function interpret( + machine: Machine, + onChange: (service: Service) => void, + initialContext?: any, +): Service { + const context = machine.contextFactory(initialContext) + + const service: Service = { + machine: { current: machine.initial }, + context, + send: (event: SendEvent) => { + const result = applyTransition( + machine.states, + service.machine.current, + service.context, + event, + ) + if (result) { + service.machine = { current: result.current } + service.context = result.context + onChange(service) + } + }, + child: undefined, + } + + return service +} diff --git a/src/lib/state-machine/index.ts b/src/lib/state-machine/index.ts new file mode 100644 index 0000000000..d9d711d204 --- /dev/null +++ b/src/lib/state-machine/index.ts @@ -0,0 +1,75 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { useReducer, useRef } from 'react' +import { applyTransition } from './core' +import type { Machine, MachineState, SendEvent, Service, StateDefinition } from './types' + +export { guard, reduce, transition, state, createMachine, interpret } from './core' +export type { + Guard, + Reducer, + TransitionDefinition, + StateDefinition, + Machine, + MachineState, + Service, + SendFunction, + SendEvent, + ContextFunction, + Transition, + Immediate, + GetMachineTransitions, +} from './types' + +type ReducerState = { current: string; context: C } + +type ReducerAction = SendEvent | { type: '__RESET__'; _initial: string; _context: C } + +function machineReducer( + machineStates: Record, + state: ReducerState, + action: ReducerAction, +): ReducerState { + if (action.type === '__RESET__' && '_initial' in action) { + return { current: action._initial, context: action._context } + } + return ( + applyTransition(machineStates, state.current, state.context, action as SendEvent) ?? state + ) +} + +/** @internal */ +export function useMachine( + machine: Machine, + initialContext?: any, +): [MachineState, (event: SendEvent) => void, Service] { + const machineRef = useRef(machine) + + const [{ current, context }, dispatch] = useReducer( + (s: ReducerState, a: ReducerAction) => machineReducer(machineRef.current.states, s, a), + undefined, + () => ({ + current: machine.initial, + context: machine.contextFactory(initialContext), + }), + ) + + if (machineRef.current !== machine) { + machineRef.current = machine + const resetContext = machine.contextFactory(initialContext) + dispatch({ type: '__RESET__', _initial: machine.initial, _context: resetContext }) + } + + const send = (event: SendEvent) => { + dispatch(event) + } + + const currentState: MachineState = { name: current, context } + const service: Service = { + machine: { current }, + context, + send, + child: undefined, + } + + return [currentState, send, service] +} diff --git a/src/lib/state-machine/types.ts b/src/lib/state-machine/types.ts new file mode 100644 index 0000000000..3e86cdb2df --- /dev/null +++ b/src/lib/state-machine/types.ts @@ -0,0 +1,66 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +/** @internal */ +export type SendEvent = { type: string; payload?: unknown } + +/** @internal */ +export type SendFunction = (event: SendEvent | { type: T }) => void + +/** @internal */ +export type Guard = { + _tag: 'guard' + fn: (ctx: C, ev: any) => boolean +} + +/** @internal */ +export type Reducer = { + _tag: 'reduce' + fn: (ctx: C, ev: any) => C +} + +/** @internal */ +export type TransitionDefinition = { + _tag: 'transition' + event: string + target: string + guards: Guard[] + reducers: Reducer[] +} + +/** @internal */ +export type Transition<_E extends string = string> = TransitionDefinition +/** @internal */ +export type Immediate<_E extends string = string> = TransitionDefinition + +/** @internal */ +export type StateDefinition = { + _tag: 'state' + transitions: Map[]> +} + +/** @internal */ +export type ContextFunction = (initialContext?: any) => C + +/** @internal */ +export type Machine = { + initial: string + states: Record + contextFactory: ContextFunction +} + +/** @internal */ +export type MachineState = { + name: string + context: C +} + +/** @internal */ +export type Service = { + machine: { current: string } + context: C + send: SendFunction + child: undefined +} + +/** @internal */ +export type GetMachineTransitions = TransitionDefinition diff --git a/src/shared/constants.ts b/src/shared/constants.ts index e8a0bcfb5b..f92b041b24 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -577,7 +577,7 @@ export const timeOffEvents = { * ``` */ export const componentEvents = { - ROBOT_MACHINE_DONE: 'done', //This is internal Robot event thrown when machine transitions to final state + ROBOT_MACHINE_DONE: 'done', ERROR: 'ERROR', CANCEL: 'CANCEL', BREADCRUMB_NAVIGATE: 'breadcrumb/navigate', diff --git a/src/types/Helpers.d.ts b/src/types/Helpers.d.ts index a173f363f1..98bb233832 100644 --- a/src/types/Helpers.d.ts +++ b/src/types/Helpers.d.ts @@ -36,11 +36,9 @@ export type MachineEventType< payload: TEventPayloads[TEventType] } -// Robot3 state machine helper types for consistent usage across the codebase -export type { Transition, Immediate } from 'robot3' +export type { Transition, Immediate } from '@/lib/state-machine' export type { EventType } from '@/shared/constants' -// Reusable type for robot3 state machine transitions that accept any EventType export type MachineTransition = Transition | Immediate //Makes specific property in the given type required