docs: added cart storefront guides (#7662)

* docs: added cart storefront guides

* add context guides

* small fixes to the context
This commit is contained in:
Shahed Nasser
2024-06-11 11:56:37 +03:00
committed by GitHub
parent 37426939da
commit f3bf8c73a3
11 changed files with 969 additions and 1 deletions
@@ -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()
// ...
}
```