Skip to main content

AddToCart

Description

A render props component that provides state and actions for adding products to the cart. Handles loading states, validation, and error management.

Import

import { AddToCart } from '@components/frontStore/cart/AddToCart';

Usage

import { AddToCart } from '@components/frontStore/cart/AddToCart';

function ProductButton({ product }) {
return (
<AddToCart product={product} qty={1}>
{(state, actions) => (
<button
onClick={actions.addToCart}
disabled={!state.canAddToCart || state.isLoading}
>
{state.isLoading ? 'Adding...' : 'Add to Cart'}
</button>
)}
</AddToCart>
);
}

Props

NameTypeRequiredDescription
productProductInfoYesProduct information (sku, isInStock)
qtynumberYesQuantity to add
onSuccess(qty: number) => voidNoCallback on successful add
onError(error: string) => voidNoCallback on error
childrenRenderFunctionYesRender function receiving state and actions

ProductInfo Interface

interface ProductInfo {
sku: string; // Product SKU
isInStock: boolean; // Stock availability
}

State Object

The render function receives a state object:

interface AddToCartState {
isLoading: boolean; // True when adding to cart
error: string | null; // Error message if any
canAddToCart: boolean; // True if product can be added
isInStock: boolean; // Stock availability
}

Actions Object

The render function receives an actions object:

interface AddToCartActions {
addToCart: () => Promise<void>; // Add product to cart
clearError: () => void; // Clear error state
}

Examples

Basic Button

import { AddToCart } from '@components/frontStore/cart/AddToCart';

function BuyButton({ product }) {
return (
<AddToCart product={product} qty={1}>
{(state, actions) => (
<button
onClick={actions.addToCart}
disabled={!state.canAddToCart || state.isLoading}
>
{state.isLoading ? 'Adding...' : 'Add to Cart'}
</button>
)}
</AddToCart>
);
}

With Error Display

import { AddToCart } from '@components/frontStore/cart/AddToCart';

function ProductAddToCart({ product }) {
return (
<AddToCart product={product} qty={1}>
{(state, actions) => (
<div>
<button
onClick={actions.addToCart}
disabled={!state.canAddToCart || state.isLoading}
>
{state.isLoading ? 'Adding...' : 'Add to Cart'}
</button>

{state.error && (
<div className="error">
{state.error}
<button onClick={actions.clearError}>×</button>
</div>
)}

{!state.isInStock && (
<p className="out-of-stock">Out of Stock</p>
)}
</div>
)}
</AddToCart>
);
}

With Quantity Selector

import { AddToCart } from '@components/frontStore/cart/AddToCart';
import { useState } from 'react';

function ProductQuantityAdd({ product }) {
const [qty, setQty] = useState(1);

return (
<div>
<input
type="number"
min="1"
value={qty}
onChange={(e) => setQty(parseInt(e.target.value))}
/>

<AddToCart product={product} qty={qty}>
{(state, actions) => (
<button
onClick={actions.addToCart}
disabled={!state.canAddToCart || state.isLoading}
>
{state.isLoading ? 'Adding...' : 'Add to Cart'}
</button>
)}
</AddToCart>
</div>
);
}

With Callbacks

import { AddToCart } from '@components/frontStore/cart/AddToCart';

function ProductCard({ product }) {
const handleSuccess = (qty) => {
console.log(`Added ${qty} items to cart`);
// Show toast notification
};

const handleError = (error) => {
console.error('Failed to add to cart:', error);
// Show error notification
};

return (
<AddToCart
product={product}
qty={1}
onSuccess={handleSuccess}
onError={handleError}
>
{(state, actions) => (
<button
onClick={actions.addToCart}
disabled={!state.canAddToCart || state.isLoading}
>
Add to Cart
</button>
)}
</AddToCart>
);
}

Complete Example

import { AddToCart } from '@components/frontStore/cart/AddToCart';
import { useState } from 'react';

function ProductDetail({ product }) {
const [qty, setQty] = useState(1);
const [showSuccess, setShowSuccess] = useState(false);

return (
<div className="product">
<h1>{product.name}</h1>
<p>{product.price}</p>

<div className="quantity-selector">
<button onClick={() => setQty(Math.max(1, qty - 1))}>-</button>
<input
type="number"
value={qty}
onChange={(e) => setQty(parseInt(e.target.value) || 1)}
min="1"
/>
<button onClick={() => setQty(qty + 1)}>+</button>
</div>

<AddToCart
product={{ sku: product.sku, isInStock: product.inStock }}
qty={qty}
onSuccess={(addedQty) => {
setShowSuccess(true);
setTimeout(() => setShowSuccess(false), 3000);
}}
>
{(state, actions) => (
<div>
<button
className="add-to-cart-btn"
onClick={actions.addToCart}
disabled={!state.canAddToCart || state.isLoading}
>
{state.isLoading && <span>Adding...</span>}
{!state.isLoading && state.isInStock && <span>Add to Cart</span>}
{!state.isInStock && <span>Out of Stock</span>}
</button>

{state.error && (
<div className="error-message">
{state.error}
<button onClick={actions.clearError}>Dismiss</button>
</div>
)}

{showSuccess && (
<div className="success-message">
Added to cart successfully!
</div>
)}
</div>
)}
</AddToCart>
</div>
);
}

Features

  • Render Props Pattern: Flexible UI implementation
  • Loading State: Automatic loading state management
  • Error Handling: Built-in error management
  • Validation: Checks stock and quantity
  • Callbacks: onSuccess and onError hooks
  • Type Safe: Full TypeScript support
  • Cart Integration: Uses cart context automatically