Skip to content

Hierarchical Checkout

Article →
PaymentproceedbackproceedbackproceedchangePaymentbackexitchild.exitbackchangePaymentsubmitOrderrestartCartShippingShippingPaidMethodEntryAuthorizingAuthChallengeAuthorizationErrorAuthorizedReviewConfirmation
1
Cart
2
Shipping
3
Payment
4
Review
5
Done

Wireless Headphones

$99.99 each

$99.99

Bluetooth Speaker

$49.99 each

$99.98
Total$199.97
import {
createMachine,
defineStates,
effect,
setup,
withReset,
matchina,
} from "matchina";
import { submachine, nestedHsmRoot } from "matchina/hsm";
// Hierarchical checkout: main flow contains a payment submachine
export const paymentStates = defineStates({
MethodEntry: undefined,
Authorizing: undefined,
AuthChallenge: undefined,
AuthorizationError: undefined,
Authorized: { final: true },
});
// Create payment machine factory
function createPayment() {
const m = matchina(
paymentStates,
{
MethodEntry: {
authorize: "Authorizing",
exit: "MethodEntry", // Exit resets to initial state
},
Authorizing: {
authRequired: "AuthChallenge",
authSucceeded: "Authorized",
authFailed: "AuthorizationError",
exit: "MethodEntry", // Exit from any payment state goes back to MethodEntry
},
AuthChallenge: {
authSucceeded: "Authorized",
authFailed: "AuthorizationError",
exit: "MethodEntry",
},
AuthorizationError: {
retry: "MethodEntry",
exit: "MethodEntry",
},
Authorized: {
exit: "MethodEntry",
},
},
paymentStates.MethodEntry()
);
return withReset(nestedHsmRoot(m), paymentStates.MethodEntry());
}
const paymentFactory = submachine(createPayment, { id: "payment" });
const checkoutStates = defineStates({
Cart: undefined,
Shipping: undefined,
ShippingPaid: undefined,
Payment: paymentFactory,
Review: undefined,
Confirmation: undefined,
});
export function createCheckoutMachine() {
const checkout = createMachine(
checkoutStates,
{
Cart: { proceed: "Shipping" },
Shipping: {
back: "Cart",
proceed: "Payment",
},
Payment: {
back: "Shipping",
exit: "Shipping",
"child.exit": "Review",
},
Review: {
back: "ShippingPaid",
changePayment: "Payment",
submitOrder: "Confirmation",
},
ShippingPaid: {
back: "Cart",
proceed: "Review",
changePayment: "Payment",
},
Confirmation: { restart: "Cart" },
},
"Cart"
);
const hierarchical = nestedHsmRoot(checkout);
// Get payment machine from state to wire up reset effect
const getPayment = () => {
const state = hierarchical.getState();
return state.is("Payment") ? state.data.machine : null;
};
setup(hierarchical)(
effect((ev) => {
if (ev.type === "restart") {
const payment = getPayment();
if (payment) {
payment.reset!();
}
return true;
}
})
);
return hierarchical;
}
// Type export for payment machine (used by CheckoutViewNested context)
export type PaymentMachine = ReturnType<typeof createPayment>;