Skip to main content

Configure Dynamic Bundles

Learn how to implement dynamic bundle configuration in your storefront. For understanding the configuration structure and concepts, see Understanding Bundle Configuration.

Prerequisites

Before implementing bundle configuration, ensure you understand:

Configure Bundle with SDK

Use configureByContextProduct to generate a valid bundle configuration:

import { configureByContextProduct } from '@epcc-sdk/sdks-shopper';

async function configureDynamicBundle(
bundleId: string,
selectedOptions: BundleConfiguration["selected_options"]
) {
try {
const response = await configureByContextProduct({
path: { product_id: bundleId },
body: {
data: {
selected_options: selectedOptions
}
}
});

// Returns configured bundle with updated price
return {
success: true,
configuredBundle: response.data,
configuration: response.data?.meta?.bundle_configuration
};
} catch (error) {
return {
success: false,
error: error.message || 'Failed to configure bundle'
};
}
}

Example: Bundle Configurator

Simplified implementation with validation and price updates:

function BundleConfigurator({ bundle, componentProducts }) {
const [selectedOptions, setSelectedOptions] = useState({});
const [configuredBundle, setConfiguredBundle] = useState(null);
const [isConfiguring, setIsConfiguring] = useState(false);
const [validationErrors, setValidationErrors] = useState([]);

const components = bundle.attributes?.components || {};

// Validate and configure on selection change
useEffect(() => {
const validation = validateBundleSelection(components, selectedOptions);
setValidationErrors(validation.errors);

if (validation.isValid && Object.keys(selectedOptions).length > 0) {
configureBundle();
}
}, [selectedOptions]);

const configureBundle = async () => {
setIsConfiguring(true);
const result = await configureDynamicBundle(bundle.id, selectedOptions);
if (result.success) {
setConfiguredBundle(result.configuredBundle);
}
setIsConfiguring(false);
};

const handleAddToCart = async () => {
const configuration = configuredBundle?.data?.meta?.bundle_configuration;
if (!configuration) return;

const cartId = getCartId();
await manageCarts({
path: { cartID: cartId },
body: {
data: {
type: 'cart_item',
id: bundle.id,
quantity: 1,
bundle_configuration: configuration
}
}
});
};

const currentPrice = configuredBundle?.data?.meta?.display_price?.without_tax?.formatted
|| bundle.meta?.display_price?.without_tax?.formatted;

return (
<>
<h3>Price: {isConfiguring ? 'Updating...' : currentPrice}</h3>

{validationErrors.map((error, idx) => (
<p key={idx}>{error}</p>
))}

{/* Render component selection UI here */}

<button
onClick={handleAddToCart}
disabled={validationErrors.length > 0 || !configuredBundle}
>
Add to Cart
</button>
</>
);
}

Configuration Persistence

To improve user experience, you can persist bundle configurations across sessions. See Configuration Persistence for implementation details including:

  • Saving configurations to URL for sharing
  • Using localStorage for returning users
  • Handling stale configuration data

Example usage in your component:

// On mount, restore saved configuration
useEffect(() => {
const savedConfig = restoreConfigurationFromUrl();
if (savedConfig) {
setSelectedOptions(savedConfig);
}
}, []);

// Save configuration when it changes
useEffect(() => {
if (Object.keys(selectedOptions).length > 0) {
saveConfigurationToUrl(bundle.id, selectedOptions);
}
}, [selectedOptions]);

Error Handling

Common error scenarios to handle:

  • 422 Validation Error: Invalid bundle configuration
  • 404 Not Found: Bundle or component product not found
  • Stock Issues: Component out of stock
  • Generic Errors: Network or server issues

Implementation Tips

When building bundle configurators:

  • Validate before configuring: Check selections meet requirements before API calls
  • Debounce API calls: Wait for user to finish selecting (300-500ms)
  • Show loading states: Indicate when prices are updating
  • Handle errors gracefully: Provide clear feedback for validation errors
  • Cache component data: Component products rarely change

For understanding the configuration data structure and concepts, see Understanding Bundle Configuration.

Next Steps

With your bundle configurator implemented:

References