import dynamic from 'next/dynamic'; import type { ComponentType } from 'react'; import type { CheckoutVariantId, CheckoutVariantProps } from './types'; type VariantLoader = () => Promise<{ default: ComponentType; }>; const variantLoaders: Record = { 'multi-step': () => import('./multi-step'), 'one-page': () => import('./one-page'), accordion: () => import('./one-page'), 'basket-and-checkout': () => import('./basket-and-checkout') }; /** * Variants that embed the basket inside the checkout page. In these modes the * basket page redirects to checkout, so checkout must never redirect back to * the basket page — that would create an infinite redirect loop. */ export const UNIFIED_VARIANTS: ReadonlySet = new Set([ 'basket-and-checkout' ]); export const getCheckoutVariant = (variant: CheckoutVariantId | undefined) => { // Own-key lookup only (see `isKnownVariant`): an inherited member would // resolve to a truthy non-loader and `dynamic()` would never render a flow. const loader = isKnownVariant(variant) ? variantLoaders[variant] : variantLoaders['multi-step']; return dynamic(loader, { ssr: false }); }; /** * `in` also answers true for inherited Object.prototype members ('toString', * 'constructor', '__proto__', …), which would let a saved setting name a * "known" variant with no loader — `getCheckoutVariant` would then hand * `dynamic()` a non-function and the flow would be lost. Own keys only. */ export const isKnownVariant = (value: unknown): value is CheckoutVariantId => typeof value === 'string' && Object.prototype.hasOwnProperty.call(variantLoaders, value);