docs: update storefront development snippets for next.js 15 compatibility (#10843)

This commit is contained in:
Shahed Nasser
2025-01-07 09:02:18 +02:00
committed by GitHub
parent 47594192b7
commit 4c0546a8e9
24 changed files with 179 additions and 252 deletions
@@ -25,13 +25,12 @@ export const highlights = [
["14", "setCart", "Allow the context provider's children to update the cart."],
["17", "refreshCart", "Allow the context provider's children to unset and reset the cart."],
["26", "CartProvider", "The provider component to use in your component tree."],
["32", "useRegion", "Use the `useRegion` hook defined in the Region Context guide."],
["37", "setItem", "Set the cart's ID in `localStorage` in case it changed."],
["45", "fetch", "If the customer doesn't have a cart, create a new one."],
["49", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to associate the correct sales channel(s)."],
["63", "fetch", "Retrieve the customer's cart."],
["76", "refreshCart", "This function unsets the cart, which triggers the `useEffect` callback to create a cart."],
["92", "useCart", "The hook that child components of the provider use to access the cart."]
["30", "useRegion", "Use the `useRegion` hook defined in the Region Context guide."],
["40", "fetch", "If the customer doesn't have a cart, create a new one."],
["44", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to associate the correct sales channel(s)."],
["58", "fetch", "Retrieve the customer's cart."],
["71", "refreshCart", "This function unsets the cart, which triggers the `useEffect` callback to create a cart."],
["87", "useCart", "The hook that child components of the provider use to access the cart."]
]
```tsx highlights={highlights}
@@ -55,7 +55,7 @@ export const fetchHighlights = [
export const highlights = [
["8", "region", "Assuming you previously retrieved the chosen region."],
["15", "cartId", "Retrieve the cart ID from `localStorage`, if exists."],
["21", "", "Send a request to create the cart."],
["22", "fetch", "Send a request to create the cart."],
["26", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to associate the correct sales channel(s)."],
["30", "region_id", "Associate the cart with the chosen region for accurate pricing."],
["35", "setItem", "Set the cart's ID in the `localStorage`."]
@@ -45,7 +45,7 @@ export const fetchHighlights = [
export const highlights = [
["16", "cartId", "Retrieve the cart ID from `localStorage`."],
["18", "TODO", "You can create the cart and set it here as explained in the Create Cart guide."],
["22"], ["23"], ["24"], ["25"], ["26"], ["27"], ["28"],
["22"], ["23"], ["24"], ["25"], ["26"], ["27"], ["28"], ["29"], ["30"], ["31"],
["34", "formatPrice", "This function was previously created to format product prices. You can re-use the same function."],
["37", "currency_code", "If you reuse the `formatPrice` function, pass the currency code as a parameter."],
]
@@ -76,7 +76,7 @@ fetch(`http://localhost:9000/store/carts/${cartId}/customer`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",
},
})
.then((res) => res.json())
@@ -64,7 +64,7 @@ export const highlights = [
["4", "useCart", "The `useCart` hook was defined in the Cart React Context documentation."],
["29", "address", "Assemble the address object to be used for both shipping and billing addresses."],
["41"], ["42"], ["43"], ["44"], ["45"], ["46"], ["47"], ["48"],
["49"], ["50"], ["51"], ["52"], ["53"], ["54"], ["55"], ["56"]
["49"], ["50"], ["51"], ["52"], ["53"], ["54"], ["55"], ["56"],
["103", "", "The address's country can only be within the cart's region."]
]
@@ -53,8 +53,8 @@ export const fetchHighlights = [
export const highlights = [
["20", "offset", "Calculate the number of addresses to skip based on the current page and limit."],
["27", "fetch", "Send a request to retrieve the addresses."],
["31", "searchParams.toString()", "Pass the pagination parameters in the query."],
["34", "count", "The total number of addresses in the Medusa application."],
["28", "searchParams.toString()", "Pass the pagination parameters in the query."],
["36", "count", "The total number of addresses in the Medusa application."],
["48", "setHasMorePages", "Set whether there are more pages based on the total count."],
["62", "", "Using only two address fields for simplicity."],
["68", "button", "Show a button to load more addresses if there are more pages."]
@@ -379,11 +379,10 @@ To edit an address, send a request to the [Update Customer Address API route](!a
export const editHighlights = [
["4", "useRegion", "Use the hook defined in the Region Context guide."],
["5", "useCustomer", "Use the hook defined in the Customer Context guide."],
["14", "{ params: { id }}", "This is based on Next.js which passes the path parameters as a prop."],
["19", "address", "Retrieve the address from the customer's `addresses` property."],
["60"], ["61"], ["62"], ["63"], ["64"], ["65"], ["66"], ["67"], ["68"], ["69"],
["70"], ["71"], ["72"], ["73"], ["74"], ["75"], ["76"], ["77"], ["78"], ["79"],
["80"], ["81"], ["82"]
["17", "address", "Retrieve the address from the customer's `addresses` property."],
["58"], ["59"], ["60"], ["61"], ["62"], ["63"], ["64"], ["65"], ["66"], ["67"],
["68"], ["69"], ["70"], ["71"], ["72"], ["73"], ["74"], ["75"], ["76"], ["77"],
["78"], ["79"], ["80"]
]
```tsx highlights={editHighlights} collapsibleLines="90-161" expandButtonLabel="Show form"
@@ -393,14 +392,12 @@ export const editHighlights = [
import { useRegion } from "../../../../../providers/region"
import { useCustomer } from "../../../../../providers/customer"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function EditAddress(
{ params: { id } }: Params
{ id }: Props
) {
const { customer, setCustomer } = useCustomer()
const { region } = useRegion()
@@ -8,7 +8,7 @@ tags:
import { CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `Retrieve Customer in Storefront`,
title: `Retrieve Logged-In Customer in Storefront`,
}
# {metadata.title}
@@ -392,7 +392,7 @@ export const validateReactHighlights = [
["2", "sendCallback", "Validate the callback in Medusa and retrieve the authentication token"],
["4", "shouldCreateCustomer", "Check if the decoded token has an `actor_id` property to decide whether a customer to be created."],
["7", "createCustomer", "Create a customer if the decoded token doesn't have `actor_id`."],
["9", "refetchToken", "Fetch a new token for the created customer."],
["9", "refreshToken", "Fetch a new token for the created customer."],
["13", "fetch", "Send an authenticated request using the token."]
]
@@ -58,12 +58,11 @@ export const fetchHighlights = [
<CodeTab label="React" value="react">
export const highlights = [
["12", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["24", `"category_children.id,category_children.name"`, "Select the fields of category children"],
["25", "parent_category_id", "Since each category will have its children, you only retrieve categories that don't have a parent."]
["22", `fields`, "Select the fields of category children"],
["23", "parent_category_id", "Since each category will have its children, you only retrieve categories that don't have a parent."],
["26"], ["27"], ["28"],
["29"], ["30"], ["31"], ["32"], ["33"], ["34"], ["35"], ["36"], ["37"], ["38"],
["54", "", "Show the nested categories."],
["52", "", "Show the nested categories."],
]
```tsx highlights={highlights}
@@ -72,13 +71,11 @@ export const highlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Category({ params: { id } }: Params) {
export default function Category({ id }: Props) {
const [loading, setLoading] = useState(true)
const [category, setCategory] = useState<
HttpTypes.StoreProductCategory | undefined
@@ -46,12 +46,11 @@ export const fetchHighlights = [
<CodeTab label="React" value="react">
export const highlights = [
["13", "params: { categoryId }", "This is based on Next.js which passes the path parameters as a prop."],
["33", "", "Pass the category ID as a query parameter."],
["36"], ["37"], ["38"],
["39", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve products of associated sales channel(s)."],
["40"], ["41"], ["42"], ["43"], ["44"], ["45"], ["46"], ["47"], ["48"], ["49"], ["50"], ["51"], ["52"], ["53"], ["54"],
["55"], ["56"]
["31", "", "Pass the category ID as a query parameter."],
["34"], ["35"], ["36"],
["37", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve products of associated sales channel(s)."],
["38"], ["39"], ["40"], ["41"], ["42"], ["43"], ["44"], ["45"], ["46"], ["47"], ["48"], ["49"], ["50"], ["51"], ["52"],
["53"], ["54"]
]
```tsx highlights={highlights}
@@ -60,15 +59,13 @@ export const highlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
categoryId: string
}
type Props = {
categoryId: string
}
export default function CategoryProducts({
params: { categoryId },
}: Params) {
categoryId,
}: Props) {
const [loading, setLoading] = useState(true)
const [products, setProducts] = useState<
HttpTypes.StoreProduct[]
@@ -49,9 +49,8 @@ export const fetchHighlights = [
<CodeTab label="React" value="react">
export const highlights = [
["12", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["23"], ["24"], ["25"], ["26"],
["27"], ["28"], ["29"], ["30"], ["31"], ["32"], ["33"]
["21"], ["22"], ["23"], ["24"],
["25"], ["26"], ["27"], ["28"], ["29"], ["30"], ["31"]
]
```tsx highlights={highlights}
@@ -60,13 +59,11 @@ export const highlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Category({ params: { id } }: Params) {
export default function Category({ id }: Props) {
const [loading, setLoading] = useState(true)
const [category, setCategory] = useState<
HttpTypes.StoreProductCategory | undefined
@@ -146,10 +143,9 @@ export const handleFetchHighlights = [
<CodeTab label="React" value="react">
export const handleHighlights = [
["12", "{ params: { handle } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["23"], ["24"], ["25"], ["26"],
["27"], ["28"], ["29"], ["30"],
["31"], ["32"], ["33"], ["34"], ["35"], ["36"], ["37"]
["21"], ["22"], ["23"], ["24"],
["25"], ["26"], ["27"], ["28"],
["29"], ["30"], ["31"], ["32"], ["33"], ["34"], ["35"]
]
```tsx highlights={handleHighlights}
@@ -158,13 +154,11 @@ export const handleHighlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
handle: string
}
type Props = {
handle: string
}
export default function Category({ params: { handle } }: Params) {
export default function Category({ handle }: Props) {
const [loading, setLoading] = useState(true)
const [category, setCategory] = useState<
HttpTypes.StoreProductCategory | undefined
@@ -46,12 +46,11 @@ export const fetchHighlights = [
<CodeTab label="React" value="react">
export const highlights = [
["13", "params: { collectionId }", "This is based on Next.js which passes the path parameters as a prop."],
["33", "", "Pass the collection ID as a query parameter."],
["36"], ["37"], ["38"],
["39", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve products of associated sales channel(s)."],
["40"], ["41"], ["42"], ["43"], ["44"], ["45"], ["46"], ["47"], ["48"], ["49"], ["50"], ["51"], ["52"], ["53"], ["54"],
["55"], ["56"], ["57"], ["58"]
["31", "collectionId", "Pass the collection ID as a query parameter."],
["34"], ["35"], ["36"],
["37", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve products of associated sales channel(s)."],
["38"], ["39"], ["40"], ["41"], ["42"], ["43"], ["44"], ["45"], ["46"], ["47"], ["48"], ["49"], ["50"], ["51"], ["52"],
["53"], ["54"], ["55"], ["56"]
]
```tsx highlights={highlights}
@@ -60,15 +59,13 @@ export const highlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
collectionId: string
}
type Props = {
collectionId: string
}
export default function CollectionProducts({
params: { collectionId },
}: Params) {
collectionId,
}: Props) {
const [loading, setLoading] = useState(true)
const [products, setProducts] = useState<
HttpTypes.StoreProduct[]
@@ -49,10 +49,9 @@ fetch(`http://localhost:9000/store/collections/${id}`, {
<CodeTab label="React" value="react">
export const highlights = [
["12", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["23"], ["24"], ["25"], ["26"],
["27"], ["28"], ["29"], ["30"],
["31"], ["32"], ["33"]
["21"], ["22"], ["23"], ["24"],
["25"], ["26"], ["27"], ["28"],
["29"], ["30"], ["31"],
]
```tsx highlights={highlights}
@@ -61,13 +60,11 @@ export const highlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Collection({ params: { id } }: Params) {
export default function Collection({ id }: Props) {
const [loading, setLoading] = useState(true)
const [collection, setCollection] = useState<
HttpTypes.StoreCollection | undefined
@@ -148,10 +145,9 @@ export const handleFetchHighlights = [
<CodeTab label="React" value="react">
export const handleHighlights = [
["13", "{ params: { handle } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["25"], ["26"], ["27"], ["28"],
["29"], ["30"], ["31"], ["32"], ["33"], ["34"], ["35"], ["36"],
["37"], ["38"], ["39"]
["23"], ["24"], ["25"], ["26"],
["27"], ["28"], ["29"], ["30"], ["31"], ["32"], ["33"], ["34"],
["35"], ["36"], ["37"]
]
```tsx highlights={handleHighlights}
@@ -160,14 +156,12 @@ export const handleHighlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
handle: string
}
type Props = {
handle: string
}
export default function Collection(
{ params: { handle } }: Params
{ handle }: Props
) {
const [loading, setLoading] = useState(true)
const [collection, setCollection] = useState<
@@ -66,11 +66,10 @@ A variant is in stock if:
## Full React Example
export const reactHighlights = [
["12", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["25", "fields", "Pass `+variants.inventory_quantity` in the fields to retrieve."],
["31", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve the inventory quantity based on the associated sales channels' stock locations."],
["55", "isInStock", "Consider the selected variant in stock either if its `manage_inventory` property is disabled, or the `inventory_quantity` is greater than `0`."],
["96", "isInStock", "Show whether the selected variant is in stock."]
["23", "fields", "Pass `+variants.inventory_quantity` in the fields to retrieve."],
["29", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve the inventory quantity based on the associated sales channels' stock locations."],
["53", "isInStock", "Consider the selected variant in stock either if its `manage_inventory` property is disabled, or the `inventory_quantity` is greater than `0`."],
["94", "isInStock", "Show whether the selected variant is in stock."]
]
```tsx title="React Storefront" highlights={reactHighlights}
@@ -79,13 +78,11 @@ export const reactHighlights = [
import { useEffect, useMemo, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Product({ params: { id } }: Params) {
export default function Product({ id }: Props) {
const [loading, setLoading] = useState(true)
const [product, setProduct] = useState<
HttpTypes.StoreProduct | undefined
@@ -31,6 +31,12 @@ Where `selectedVariantPrice` is either the variant the customer selected or the
If the price is a sale price, the original price is in the variant's `calculated_price.original_amount` field:
<Note title="Tip">
Find the implementation of the `formatPrice` function in [this guide](../show-price/page.mdx#price-formatting).
</Note>
```ts
const salePrice = formatPrice(selectedVariantPrice.calculated_price.calculated_amount)
const originalPrice = formatPrice(selectedVariantPrice.calculated_price.original_amount)
@@ -42,12 +48,6 @@ const discountedAmount = formatPrice(
You can use the original price either to display it or calculate and display the discounted amount.
<Note title="Tip">
Learn more about the `formatPrice` function in [this guide](../show-price/page.mdx#price-formatting)
</Note>
---
## Full React Example
@@ -62,11 +62,10 @@ The example only passes the `region_id` query parameter for pricing. Learn how t
export const saleHighlights = [
["5", "useRegion", "The `useRegion` hook is implemented in the Region React Context guide."],
["13", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["19", "region", "Access the region using the `useRegion` hook."],
["88", "isSale", "Determine whether the price is a sale price based on the value of the variant's `calculated_price.calculated_price.price_list_type` field."],
["97", "originalPrice", "Retrieve the original price from the variant's `calculated_price.original_amount` field if the price is a sale price."],
["143", "", "If the price is a sale price, show that to the customer along with the original price."]
["17", "region", "Access the region using the `useRegion` hook."],
["86", "isSale", "Determine whether the price is a sale price based on the value of the variant's `calculated_price.calculated_price.price_list_type` field."],
["95", "originalPrice", "Retrieve the original price from the variant's `calculated_price.original_amount` field if the price is a sale price."],
["141", "", "If the price is a sale price, show that to the customer along with the original price."]
]
```tsx highlights={saleHighlights}
@@ -76,13 +75,11 @@ import { useEffect, useMemo, useState } from "react"
import { HttpTypes } from "@medusajs/types"
import { useRegion } from "../providers/region"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Product({ params: { id } }: Params) {
export default function Product({ id }: Props) {
const [loading, setLoading] = useState(true)
const [product, setProduct] = useState<
HttpTypes.StoreProduct | undefined
@@ -15,20 +15,6 @@ export const metadata = {
In this document, you'll learn how to display a product variant's price with a full React example.
## Display Selected Variant Price
Once the customer selects a variant, use its `calculated_price.calculated_amount` property to display its price:
```ts
const price = formatPrice(
selectedVariantPrice.calculated_price.calculated_amount
)
```
You'll learn about the `formatPrice` function in the next section.
---
## Price Formatting
To format the price, use JavaScript's [NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) utility. You pass it the amount and the currency code (which you retrieve from the selected region):
@@ -45,6 +31,20 @@ const formatPrice = (amount: number): string => {
---
## Display Selected Variant Price
Once the customer selects a variant, use its `calculated_price.calculated_amount` property to display its price:
```ts
const price = formatPrice(
selectedVariantPrice.calculated_price.calculated_amount
)
```
You'll learn about the `formatPrice` function in the next section.
---
## Full React Example
The following React-based storefront example retrieves the product's price based on the selected variant:
@@ -57,17 +57,16 @@ The example only passes the `region_id` query parameter for pricing. Learn how t
export const priceHighlights = [
["5", "useRegion", "The `useRegion` hook is implemented in the Region React Context guide."],
["13", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["19", "region", "Access the region using the `useRegion` hook."],
["26", "queryParams", "Build the pricing query parameters."],
["58", "formatPrice", "A utility function to format an amount with its currency."],
["59", `"en-US"`, "If you use a different locale change it here."],
["66", "selectedVariantPrice", "Assign the variant to compute its price, which is either the selected or cheapest variant."],
["68", "selectedVariant", "Use the selected variant for pricing."],
["71", "", "If there isn't a selected variant, retrieve the variant with the cheapest price."],
["79", "price", "Compute the price of the selected or cheapest variant."],
["123", "", "If there's a computed price but no selected variant, show a `From` prefix to the price."],
["124", "price", "Display the computed price."]
["17", "region", "Access the region using the `useRegion` hook."],
["24", "queryParams", "Build the pricing query parameters."],
["56", "formatPrice", "A utility function to format an amount with its currency."],
["57", `"en-US"`, "If you use a different locale change it here."],
["64", "selectedVariantPrice", "Assign the variant to compute its price, which is either the selected or cheapest variant."],
["66", "selectedVariant", "Use the selected variant for pricing."],
["69", "", "If there isn't a selected variant, retrieve the variant with the cheapest price."],
["77", "price", "Compute the price of the selected or cheapest variant."],
["121", "", "If there's a computed price but no selected variant, show a `From` prefix to the price."],
["122", "price", "Display the computed price."]
]
```tsx highlights={priceHighlights}
@@ -77,13 +76,11 @@ import { useEffect, useMemo, useState } from "react"
import { HttpTypes } from "@medusajs/types"
import { useRegion } from "../providers/region"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Product({ params: { id } }: Params) {
export default function Product({ id }: Props) {
const [loading, setLoading] = useState(true)
const [product, setProduct] = useState<
HttpTypes.StoreProduct | undefined
@@ -60,18 +60,18 @@ You can instead allow the customer to choose their country.
After passing the `region_id` and `country_code` as query parameters when retrieving the product, each variant's price object will have a `calculated_amount_with_tax` property to indicate the price taxes applied:
<Note title="Tip">
Find the implementation of the `formatPrice` function in [this guide](../show-price/page.mdx#price-formatting).
</Note>
```ts
const price = formatPrice(selectedVariantPrice.calculated_price.calculated_amount_with_tax)
```
Where `selectedVariantPrice` is either the variant the customer selected or the cheapest variant.
<Note title="Tip">
Learn more about the `formatPrice` function in [this guide](../show-price/page.mdx#price-formatting)
</Note>
---
## Tax Price Properties
@@ -95,20 +95,19 @@ The example passes the `region_id` query parameter for pricing. Learn how to sto
export const taxHighlight = [
["5", "useRegion", "The `useRegion` hook is implemented in the Region React Context guide."],
["13", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["19", "region", "Access the region using the `useRegion` hook."],
["28", "region_id", "Pass the region ID as a query parameter."],
["29", "country_code", "Pass the ISO 2 country code as a parameter."],
["29", "region.countries[0].iso_2", "You can instead allow the customer to select a specific country."],
["59", "formatPrice", "A utility function to format an amount with its currency."],
["60", `"en-US"`, "If you use a different locale change it here."],
["67", "selectedVariantPrice", "Assign the variant to compute its price, which is either the selected or cheapest variant."],
["69", "selectedVariant", "Use the selected variant for pricing."],
["72", "", "If there isn't a selected variant, retrieve the variant with the cheapest price."],
["80", "price", "Compute the price of the selected or cheapest variant."],
["87", "calculated_amount_with_tax", "Use the variant price's `calculated_amount_with_tax` property to display the price."],
["126", "", "If there's a computed price but no selected variant, show a `From` prefix to the price."],
["127", "price", "Display the computed price."]
["17", "region", "Access the region using the `useRegion` hook."],
["26", "region_id", "Pass the region ID as a query parameter."],
["27", "country_code", "Pass the ISO 2 country code as a parameter."],
["27", "region.countries[0].iso_2", "You can instead allow the customer to select a specific country."],
["57", "formatPrice", "A utility function to format an amount with its currency."],
["58", `"en-US"`, "If you use a different locale change it here."],
["65", "selectedVariantPrice", "Assign the variant to compute its price, which is either the selected or cheapest variant."],
["67", "selectedVariant", "Use the selected variant for pricing."],
["70", "", "If there isn't a selected variant, retrieve the variant with the cheapest price."],
["78", "price", "Compute the price of the selected or cheapest variant."],
["85", "calculated_amount_with_tax", "Use the variant price's `calculated_amount_with_tax` property to display the price."],
["124", "", "If there's a computed price but no selected variant, show a `From` prefix to the price."],
["125", "price", "Display the computed price."]
]
```tsx highlights={taxHighlight}
@@ -118,13 +117,11 @@ import { useEffect, useMemo, useState } from "react"
import { HttpTypes } from "@medusajs/types"
import { useRegion } from "../providers/region"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Product({ params: { id } }: Params) {
export default function Product({ id }: Props) {
const [loading, setLoading] = useState(true)
const [product, setProduct] = useState<
HttpTypes.StoreProduct | undefined
@@ -49,10 +49,9 @@ export const fetchHighlights = [
<CodeTab label="React" value="react">
export const highlights = [
["12", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."]
["23"], ["24"], ["25"],
["26", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve products of associated sales channel(s)."],
["27"], ["28"], ["29"], ["30"], ["31"], ["32"], ["33"]
["21"], ["22"], ["23"],
["24", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve products of associated sales channel(s)."],
["25"], ["26"], ["27"], ["28"], ["29"], ["30"], ["31"]
]
```tsx highlights={highlights}
@@ -61,13 +60,11 @@ export const highlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Product({ params: { id } }: Params) {
export default function Product({ id }: Props) {
const [loading, setLoading] = useState(true)
const [product, setProduct] = useState<
HttpTypes.StoreProduct | undefined
@@ -164,10 +161,9 @@ export const handleFetchHighlights = [
<CodeTab label="React" value="react">
export const handleHighlights = [
["12", "{ params: { handle } }: Params", "This is based on Next.js which passes the path parameters as a prop."]
["23"], ["24"], ["25"],
["26", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve products of associated sales channel(s)."],
["27"], ["28"], ["29"], ["30"], ["31"], ["32"], ["33"], ["34"], ["35"]
["21"], ["22"], ["23"],
["24", "process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY", "Pass the Publishable API key to retrieve products of associated sales channel(s)."],
["25"], ["26"], ["27"], ["28"], ["29"], ["30"], ["31"], ["32"], ["33"]
]
```tsx highlights={handleHighlights}
@@ -176,13 +172,11 @@ export const handleHighlights = [
import { useEffect, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
handle: string
}
type Props = {
handle: string
}
export default function Product({ params: { handle } }: Params) {
export default function Product({ handle }: Props) {
const [loading, setLoading] = useState(true)
const [product, setProduct] = useState<
HttpTypes.StoreProduct | undefined
@@ -27,11 +27,10 @@ Since a variant is a combination of the product options' values (for example, si
For example, in a React-based storefront:
export const highlights = [
["12", "{ params: { id } }: Params", "This is based on Next.js which passes the path parameters as a prop."],
["17", "selectedOptions", "Store the options the customer selects."],
["37", "selectedVariant", "Compute the selected variant based on the chosen option values combinations."],
["66", "setSelectedOptions", "When an option's value is selected, add it to the selected options, which re-computes the selected variant."],
["81", "selectedVariant", "Show the selected variant's ID, if computed."]
["15", "selectedOptions", "Store the options the customer selects."],
["35", "selectedVariant", "Compute the selected variant based on the chosen option values combinations."],
["64", "setSelectedOptions", "When an option's value is selected, add it to the selected options, which re-computes the selected variant."],
["79", "selectedVariant", "Show the selected variant's ID, if computed."]
]
```tsx highlights={highlights}
@@ -40,13 +39,11 @@ export const highlights = [
import { useEffect, useMemo, useState } from "react"
import { HttpTypes } from "@medusajs/types"
type Params = {
params: {
id: string
}
type Props = {
id: string
}
export default function Product({ params: { id } }: Params) {
export default function Product({ id }: Props) {
const [loading, setLoading] = useState(true)
const [product, setProduct] = useState<
HttpTypes.StoreProduct | undefined
@@ -88,6 +88,4 @@ export const highlights = [
</CodeTab>
</CodeTabs>
{/* TODO add a link to regions object in API reference (once available). */}
The response has a `regions` field, which is an array of regions.
The response has a `regions` field, which is an array of [regions](!api!/store#regions_region_schema).
+20 -20
View File
@@ -136,46 +136,46 @@ export const generatedEditDates = {
"app/service-factory-reference/methods/update/page.mdx": "2024-07-31T17:01:33+03:00",
"app/service-factory-reference/tips/filtering/page.mdx": "2024-07-31T17:01:33+03:00",
"app/service-factory-reference/page.mdx": "2024-07-26T14:40:56+00:00",
"app/storefront-development/cart/context/page.mdx": "2024-12-19T16:27:53.821Z",
"app/storefront-development/cart/create/page.mdx": "2024-12-19T16:27:55.753Z",
"app/storefront-development/cart/context/page.mdx": "2025-01-06T16:00:34.296Z",
"app/storefront-development/cart/create/page.mdx": "2025-01-06T15:57:04.923Z",
"app/storefront-development/cart/manage-items/page.mdx": "2024-12-26T15:59:48.445Z",
"app/storefront-development/cart/retrieve/page.mdx": "2024-12-19T16:27:57.486Z",
"app/storefront-development/cart/update/page.mdx": "2024-12-19T16:28:05.574Z",
"app/storefront-development/cart/retrieve/page.mdx": "2025-01-06T15:58:13.885Z",
"app/storefront-development/cart/update/page.mdx": "2025-01-06T16:01:33.752Z",
"app/storefront-development/cart/page.mdx": "2024-06-11T11:56:37+03:00",
"app/storefront-development/checkout/address/page.mdx": "2024-12-19T16:30:41.978Z",
"app/storefront-development/checkout/address/page.mdx": "2025-01-06T16:02:20.872Z",
"app/storefront-development/checkout/complete-cart/page.mdx": "2024-12-19T16:30:41.019Z",
"app/storefront-development/checkout/email/page.mdx": "2024-12-19T16:30:40.122Z",
"app/storefront-development/checkout/payment/stripe/page.mdx": "2024-12-19T16:30:39.173Z",
"app/storefront-development/checkout/payment/page.mdx": "2025-01-02T08:47:20.531Z",
"app/storefront-development/checkout/shipping/page.mdx": "2024-12-26T15:34:51.431Z",
"app/storefront-development/checkout/page.mdx": "2024-06-12T19:46:06+02:00",
"app/storefront-development/customers/addresses/page.mdx": "2024-12-19T16:38:44.847Z",
"app/storefront-development/customers/addresses/page.mdx": "2025-01-06T16:59:53.878Z",
"app/storefront-development/customers/context/page.mdx": "2024-12-19T16:38:43.703Z",
"app/storefront-development/customers/log-out/page.mdx": "2024-12-19T16:31:28.347Z",
"app/storefront-development/customers/login/page.mdx": "2024-12-19T16:31:34.194Z",
"app/storefront-development/customers/profile/page.mdx": "2024-12-19T16:31:43.978Z",
"app/storefront-development/customers/register/page.mdx": "2024-12-19T16:31:49.314Z",
"app/storefront-development/customers/retrieve/page.mdx": "2024-12-19T16:32:34.302Z",
"app/storefront-development/customers/retrieve/page.mdx": "2025-01-06T16:07:12.542Z",
"app/storefront-development/customers/page.mdx": "2024-06-13T12:21:54+03:00",
"app/storefront-development/products/categories/list/page.mdx": "2024-12-19T16:33:06.547Z",
"app/storefront-development/products/categories/nested-categories/page.mdx": "2024-12-19T16:33:20.197Z",
"app/storefront-development/products/categories/products/page.mdx": "2024-12-19T16:33:23.566Z",
"app/storefront-development/products/categories/retrieve/page.mdx": "2024-12-19T16:33:31.498Z",
"app/storefront-development/products/categories/nested-categories/page.mdx": "2025-01-06T15:50:56.324Z",
"app/storefront-development/products/categories/products/page.mdx": "2025-01-06T15:46:26.562Z",
"app/storefront-development/products/categories/retrieve/page.mdx": "2025-01-06T15:44:45.608Z",
"app/storefront-development/products/categories/page.mdx": "2024-06-11T19:55:56+02:00",
"app/storefront-development/products/collections/list/page.mdx": "2024-12-19T16:33:43.902Z",
"app/storefront-development/products/collections/products/page.mdx": "2024-12-19T16:33:54.473Z",
"app/storefront-development/products/collections/retrieve/page.mdx": "2024-12-19T16:34:02.301Z",
"app/storefront-development/products/collections/products/page.mdx": "2025-01-06T15:55:34.444Z",
"app/storefront-development/products/collections/retrieve/page.mdx": "2025-01-06T15:53:54.960Z",
"app/storefront-development/products/collections/page.mdx": "2024-06-11T19:55:56+02:00",
"app/storefront-development/products/list/page.mdx": "2024-12-19T16:34:23.521Z",
"app/storefront-development/products/price/examples/sale-price/page.mdx": "2024-12-19T16:34:46.886Z",
"app/storefront-development/products/price/examples/show-price/page.mdx": "2024-12-19T16:34:56.493Z",
"app/storefront-development/products/price/examples/tax-price/page.mdx": "2024-12-19T16:35:05.493Z",
"app/storefront-development/products/price/examples/sale-price/page.mdx": "2025-01-06T15:39:33.475Z",
"app/storefront-development/products/price/examples/show-price/page.mdx": "2025-01-06T15:37:57.350Z",
"app/storefront-development/products/price/examples/tax-price/page.mdx": "2025-01-06T15:40:56.854Z",
"app/storefront-development/products/price/page.mdx": "2024-12-19T16:35:19.471Z",
"app/storefront-development/products/retrieve/page.mdx": "2024-12-26T15:58:41.305Z",
"app/storefront-development/products/variants/page.mdx": "2024-12-19T16:35:41.278Z",
"app/storefront-development/products/retrieve/page.mdx": "2025-01-06T15:35:38.192Z",
"app/storefront-development/products/variants/page.mdx": "2025-01-06T15:36:41.374Z",
"app/storefront-development/products/page.mdx": "2024-06-11T19:55:56+02:00",
"app/storefront-development/regions/context/page.mdx": "2024-12-19T16:36:07.406Z",
"app/storefront-development/regions/list/page.mdx": "2024-12-19T16:36:17.364Z",
"app/storefront-development/regions/list/page.mdx": "2025-01-06T15:23:05.744Z",
"app/storefront-development/regions/store-retrieve-region/page.mdx": "2024-12-19T16:36:22.800Z",
"app/storefront-development/regions/page.mdx": "2024-06-09T15:19:09+02:00",
"app/storefront-development/tips/page.mdx": "2024-12-19T16:36:32.938Z",
@@ -864,7 +864,7 @@ export const generatedEditDates = {
"references/types/interfaces/types.BaseClaim/page.mdx": "2024-12-23T12:30:28.267Z",
"app/commerce-modules/auth/auth-providers/github/page.mdx": "2024-10-08T07:37:27.882Z",
"app/commerce-modules/auth/auth-providers/google/page.mdx": "2024-10-08T07:37:06.517Z",
"app/storefront-development/customers/third-party-login/page.mdx": "2024-12-19T16:32:43.550Z",
"app/storefront-development/customers/third-party-login/page.mdx": "2025-01-06T16:05:41.159Z",
"references/types/HttpTypes/types/types.HttpTypes.AdminWorkflowRunResponse/page.mdx": "2024-12-09T13:21:34.761Z",
"references/types/HttpTypes/types/types.HttpTypes.BatchResponse/page.mdx": "2024-12-09T13:21:33.549Z",
"references/types/WorkflowsSdkTypes/types/types.WorkflowsSdkTypes.Acknowledgement/page.mdx": "2024-12-09T13:21:35.873Z",
@@ -910,7 +910,7 @@ export const generatedEditDates = {
"references/promotion/interfaces/promotion.IPromotionModuleService/page.mdx": "2024-11-25T17:49:58.612Z",
"references/types/EventBusTypes/interfaces/types.EventBusTypes.IEventBusService/page.mdx": "2024-12-09T13:21:33.073Z",
"references/types/TransactionBaseTypes/interfaces/types.TransactionBaseTypes.ITransactionBaseService/page.mdx": "2024-09-06T00:11:08.494Z",
"app/storefront-development/products/inventory/page.mdx": "2024-12-19T16:34:10.122Z",
"app/storefront-development/products/inventory/page.mdx": "2025-01-06T15:42:09.252Z",
"references/auth/IAuthModuleService/methods/auth.IAuthModuleService.updateAuthIdentities/page.mdx": "2024-12-09T13:21:36.269Z",
"references/auth/IAuthModuleService/methods/auth.IAuthModuleService.updateProvider/page.mdx": "2024-12-09T13:21:36.245Z",
"references/auth/IAuthModuleService/methods/auth.IAuthModuleService.updateProviderIdentities/page.mdx": "2024-12-09T13:21:36.289Z",
-16
View File
@@ -14764,14 +14764,6 @@ export const generatedSidebar = [
"type": "category",
"title": "Carts",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/storefront-development/cart",
"title": "Overview",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -14885,14 +14877,6 @@ export const generatedSidebar = [
"type": "category",
"title": "Customers",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/storefront-development/customers",
"title": "Overview",
"children": []
},
{
"loaded": true,
"isPathHref": true,
+2 -1
View File
@@ -1,4 +1,3 @@
import mdx from "@next/mdx"
import {
brokenLinkCheckerPlugin,
localLinksRehypePlugin,
@@ -6,7 +5,9 @@ import {
typeListLinkFixerPlugin,
workflowDiagramLinkFixerPlugin,
} from "remark-rehype-plugins"
import bundleAnalyzer from "@next/bundle-analyzer"
import mdx from "@next/mdx"
import mdxPluginOptions from "./mdx-options.mjs"
import path from "node:path"
@@ -125,11 +125,6 @@ export const storefrontGuidesSidebar = [
type: "category",
title: "Carts",
children: [
{
type: "link",
path: "/storefront-development/cart",
title: "Overview",
},
{
type: "link",
path: "/storefront-development/cart/create",
@@ -204,11 +199,6 @@ export const storefrontGuidesSidebar = [
type: "category",
title: "Customers",
children: [
{
type: "link",
path: "/storefront-development/customers",
title: "Overview",
},
{
type: "link",
path: "/storefront-development/customers/register",