docs: added cart storefront guides (#7662)
* docs: added cart storefront guides * add context guides * small fixes to the context
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
import { CodeTabs, CodeTab } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Create Cart Context in Storefront`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
Throughout your storefront, you'll need to access the customer's cart to perform different actions.
|
||||
|
||||
So, if your storefront is React-based, create a cart context and add it at the top of your components tree. Then, you can access the customer's cart anywhere in your storefront.
|
||||
|
||||
## Create Cart Context Provider
|
||||
|
||||
For example, create the following file that exports a `CartProvider` component and a `useCart` hook:
|
||||
|
||||
export const highlights = [
|
||||
["13", "cart", "Expose cart to children of the context provider."],
|
||||
["14", "setCart", "Allow the context provider's children to update the cart."],
|
||||
["25", "CartProvider", "The provider component to use in your component tree."],
|
||||
["31", "useRegion", "Use the `useRegion` hook defined in the Region Context guide."],
|
||||
["36", "setItem", "Set the cart's ID in `localStorage` in case it changed."],
|
||||
["44", "fetch", "If the customer doesn't have a cart, create a new one."],
|
||||
["48", "process.env.NEXT_PUBLIC_PAK", "Pass the Publishable API key to associate the correct sales channel(s)."],
|
||||
["62", "fetch", "Retrieve the customer's cart."],
|
||||
["82", "useCart", "The hook that child components of the provider use to access the cart."]
|
||||
]
|
||||
|
||||
```tsx highlights={highlights}
|
||||
"use client" // include with Next.js 13+
|
||||
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState
|
||||
} from "react"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { useRegion } from "./region"
|
||||
|
||||
type CartContextType = {
|
||||
cart?: HttpTypes.StoreCart
|
||||
setCart: React.Dispatch<
|
||||
React.SetStateAction<HttpTypes.StoreCart | undefined>
|
||||
>
|
||||
}
|
||||
|
||||
const CartContext = createContext<CartContextType | null>(null)
|
||||
|
||||
type CartProviderProps = {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export const CartProvider = ({ children }: CartProviderProps) => {
|
||||
const [cart, setCart] = useState<
|
||||
HttpTypes.StoreCart
|
||||
>()
|
||||
const { region } = useRegion()
|
||||
|
||||
useEffect(() => {
|
||||
if (cart || !region) {
|
||||
return
|
||||
}
|
||||
|
||||
const cartId = localStorage.getItem("cart_id")
|
||||
if (!cartId) {
|
||||
// create a cart
|
||||
fetch(`http://localhost:9000/store/carts`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"x-publishable-api-key": process.env.NEXT_PUBLIC_PAK || "temp",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
region_id: region.id,
|
||||
})
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(({ cart: dataCart }) => {
|
||||
localStorage.setItem("cart_id", dataCart.id)
|
||||
setCart(dataCart)
|
||||
})
|
||||
} else {
|
||||
// retrieve cart
|
||||
fetch(`http://localhost:9000/store/carts/${cartId}`, {
|
||||
credentials: "include"
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(({ cart: dataCart }) => {
|
||||
setCart(dataCart)
|
||||
})
|
||||
}
|
||||
}, [cart, region])
|
||||
|
||||
return (
|
||||
<CartContext.Provider value={{
|
||||
cart,
|
||||
setCart
|
||||
}}>
|
||||
{children}
|
||||
</CartContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useCart = () => {
|
||||
const context = useContext(CartContext)
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useCart must be used within a CartProvider")
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
```
|
||||
|
||||
The `CartProvider` handles retrieving or creating the customer's cart. It uses the `useRegion` hook defined in the [Region Context guide](../../regions/context/page.mdx).
|
||||
|
||||
The `useCart` hook returns the value of the `CartContext`. Child components of `CartProvider` use this hook to access `cart` or `setCart`.
|
||||
|
||||
---
|
||||
|
||||
## Use CartProvider in Component Tree
|
||||
|
||||
To use the cart context's value, add the `CartProvider` high in your component tree.
|
||||
|
||||
For example, if you're using Next.js, add it to the `app/layout.tsx` or `src/app/layout.tsx` file:
|
||||
|
||||
```tsx title="app/layout.tsx" collapsibleLines="1-14" highlights={[["23"]]}
|
||||
import type { Metadata } from "next"
|
||||
import { Inter } from "next/font/google"
|
||||
import "./globals.css"
|
||||
import { CartProvider } from "../providers/cart"
|
||||
import { RegionProvider } from "../providers/region"
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>
|
||||
<RegionProvider>
|
||||
<CartProvider>
|
||||
{/* Other providers... */}
|
||||
{children}
|
||||
</CartProvider>
|
||||
</RegionProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Use useCart Hook
|
||||
|
||||
Now, you can use the `useCart` hook in child components of `CartProvider`.
|
||||
|
||||
For example:
|
||||
|
||||
```tsx
|
||||
"use client" // include with Next.js 13+
|
||||
// ...
|
||||
import { useCart } from "../providers/cart"
|
||||
|
||||
export default function Products() {
|
||||
const { cart } = useCart()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user