๐ง Important
Make sure to adjust the examples below accordingly to your project and store's platform.
Read more about platforms considerations here.
Creating a AddToCartButton
component
AddToCartButton.js
import React from 'react' import { useCartState, useCartActions } from 'frontend-checkout' import LoadingSpinner from 'Components/LoadingSpinner' import './styles.css' // Button states const IDLE = 'idle' const LOADING = 'loading' const SOLD_OUT = 'sold out' const ERROR = 'error' // Error message duration const THREE_SECONDS = 3 * 1000 const AddToCart = ({ id, children }) => { const [buttonState, setButtonState] = React.useState(IDLE) const { inventory } = useCartState() const { addItems, isProductAvailableForSale } = useCartActions() React.useEffect( function setSoldOutStateIfItemIsNotAvailable() { if (inventory.status === LOADING || inventory.status === ERROR) return const availableForSale = isProductAvailableForSale({ id: variantId, type: 'ProductVariant', }) if (!availableForSale) setButtonState(SOLD_OUT) }, [inventory.status], ) function clearError() { setButtonState(IDLE) } async function handleAddItemToCart() { setButtonState(LOADING) try { await addItems({ id, quantity: 1 }) setButtonState(IDLE) } catch (e) { setButtonState(ERROR) setTimeout(clearError, THREE_SECONDS) // Remove error message after 3 seconds. } } if (buttonState === LOADING) return ( <button className="AddToCart"> <LoadingSpinner /> </button> ) if (buttonState === SOLD_OUT) return ( <button className="AddToCart AddToCart--sold" disabled> Sold out </button> ) if (buttonState === ERROR) return ( <button className="AddToCart" onClick={clearError}> Adding failed </button> ) return ( <button className="AddToCart" onClick={handleAddItemToCart}> {children} </button> ) } export default AddToCart
Creating a CheckoutLink
component
JSX
import React from 'react' import { useCartState } from 'frontend-checkout' import './styles.css' const CheckoutLink = ({ children }) => { const { checkoutUrl } = useCartState() return ( <a className="CheckoutLink" href={checkoutUrl}> {children} </a> ) } export default CheckoutLink
Creating a ItemQuantityChange
component
ItemQuantity.js
import React from 'react'
import { useCartState, useCartActions } from 'frontend-checkout'
import LoadingSpinner from 'Components/LoadingSpinner'
import './styles.css'
// Button states
const IDLE = 'idle'
const LOADING = 'loading'
const SOLD_OUT = 'sold out'
const ERROR = 'error'
// Error message duration
const THREE_SECONDS = 3 * 1000
const AddToCart = ({ id, children }) => {
const [buttonState, setButtonState] = React.useState(IDLE)
const { inventory } = useCartState()
const { addItems, isProductAvailableForSale } = useCartActions()
React.useEffect(
function setSoldOutStateIfItemIsNotAvailable() {
if (inventory.status === LOADING || inventory.status === ERROR) return
const availableForSale = isProductAvailableForSale({
id: variantId,
type: 'ProductVariant',
})
if (!availableForSale) setButtonState(SOLD_OUT)
},
[inventory.status],
)
function clearError() {
setButtonState(IDLE)
}
async function handleAddItemToCart() {
setButtonState(LOADING)
try {
await addItems({ id, quantity: 1 })
setButtonState(IDLE)
} catch (e) {
setButtonState(ERROR)
setTimeout(clearError, THREE_SECONDS) // Remove error message after 3 seconds.
}
}
if (buttonState === LOADING)
return (
<button className="AddToCart">
<LoadingSpinner />
</button>
)
if (buttonState === SOLD_OUT)
return (
<button className="AddToCart AddToCart--sold" disabled>
Sold out
</button>
)
if (buttonState === ERROR)
return (
<button className="AddToCart" onClick={clearError}>
Adding failed
</button>
)
return (
<button className="AddToCart" onClick={handleAddItemToCart}>
{children}
</button>
)
}
export default AddToCart
Creating a change item variant component
CartPage.js
import React from 'react'
import { useCartState } from 'frontend-checkout'
import './styles.css'
const CartPage = () => {
const { items } = useCartState()
return (
<CartContainer>
{items.map((item) => (
<CartItem key={item.id} item={item} />
))}
</CartContainer>
)
}
export default CartPage
CartPage.js
import React, { useEffect, useState } from 'react'
import { useCartActions } from 'frontend-checkout'
import './styles.css'
const CartItem = ({ item }) => {
const { fetchProduct } = useCartActions()
const [variants, setVariants] = useState([])
// Shopify Storefront API (GraphQL)
const productId = item.variant.product.id // product id must be used in GraphQL API (Variant and CheckoutLineItem id will not work)
// Shopify AJAX API (REST)
const productId = item.handle // product handle must be used in REST API
useEffect(
async function getProductVariants() {
const product = await fetchProduct(productId)
if (product == null) return
const { variants } = product
setVariants(variants)
},
[productId, fetchProduct, setVariants],
)
return (
<CartItemContainer>
<CartItemTitle item={item} />
<ItemQuantity item={item} />
<VariantsDropdown itemId={item.id} quantity={item.quantity} variants={variants} />
</CartItemContainer>
)
}
export default CartItem
CartPage.js
import React, { useEffect, useState } from 'react'
import { useCartActions } from 'frontend-checkout'
import './styles.css'
const VariantsDropdown = ({ itemId, quantity, variants }) => {
const { addItems, removeItems } = useCartActions()
async function handleVariantChange(variant) {
// we can't update existing item in cart
// we need to remove and then add new variant
await removeItems(itemId)
await addItems({ id: variant.id, quantity })
}
return (
<VariantsDropdownContainer>
{variants.map((variant) => (
<VariantsDropdownItem variant={variant} onSelect={handleVariantChange} />
))}
</VariantsDropdownContainer>
)
}
export default VariantsDropdown
Updating cart attribute
CartPage.js
import React from 'react'
import { useCartState, useCartActions } from 'frontend-checkout'
import './styles.css'
const CartPage = () => {
const { updateCart } = useCartActions()
const { attributes } = useCartState()
async function addTestAttrToCart() {
// updateCart({ attributes: {}, note: '', items: [] })
// this method is able to add/update cart attributes, note as well
// as item quantities (all parameters are optional).
await updateCart({ attributes: { test: 'test' } })
}
return (
<CartContainer>
<button onClick={addTestAttrToCart}>Add Test Attr</button>
{Object.keys(attributes).map(attributesKey => {
return <p key={someRandomId}>{attributesKey}: {attributes[attributesKey]}</p>
})}
</CartContainer>
)
}
export default CartPage