docs: generate medusa-react reference (#6004)
* add new plugin for better organization * added handling in theme for mutations and query types * added tsdoc to hooks * added tsdocs to utility functions * added tsdoc to providers * generated reference * general fixes for generated reference * generated api reference specs + general fixes * add missing import react * split utilities into different directories * added overview page * added link to customer authentication section * fix lint errors * added changeset * fix readme * fixed build error * added expand fields + other sections to overview * updated what's new section * general refactoring * remove unnecessary query field * fix links * added ignoreApi option
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @packageDocumentation
|
||||
*
|
||||
* @customNamespace Providers.Cart
|
||||
*/
|
||||
|
||||
import React, { useState } from "react"
|
||||
import {
|
||||
useAddShippingMethodToCart,
|
||||
@@ -10,22 +16,113 @@ import {
|
||||
import { Cart } from "../types"
|
||||
|
||||
interface CartState {
|
||||
/**
|
||||
* The currently-used cart.
|
||||
*/
|
||||
cart?: Cart
|
||||
}
|
||||
|
||||
interface CartContext extends CartState {
|
||||
/**
|
||||
* The cart context available if the {@link CartProvider} is used previously in the React components tree.
|
||||
*/
|
||||
export interface CartContext extends CartState {
|
||||
/**
|
||||
* A state function used to set the cart object.
|
||||
*
|
||||
* @param {Cart} cart - The new value of the cart.
|
||||
*/
|
||||
setCart: (cart: Cart) => void
|
||||
/**
|
||||
* A mutation used to select a payment processor during checkout.
|
||||
* Using it is equivalent to using the {@link useSetPaymentSession} mutation.
|
||||
*/
|
||||
pay: ReturnType<typeof useSetPaymentSession>
|
||||
/**
|
||||
* A mutation used to create a cart.
|
||||
* Using it is equivalent to using the {@link useCreateCart} mutation.
|
||||
*/
|
||||
createCart: ReturnType<typeof useCreateCart>
|
||||
/**
|
||||
* A mutation used to initialize payment sessions during checkout.
|
||||
* Using it is equivalent to using the {@link useCreatePaymentSession} mutation.
|
||||
*/
|
||||
startCheckout: ReturnType<typeof useCreatePaymentSession>
|
||||
/**
|
||||
* A mutation used to complete the cart and place the order.
|
||||
* Using it is equivalent to using the {@link useCompleteCart} mutation.
|
||||
*/
|
||||
completeCheckout: ReturnType<typeof useCompleteCart>
|
||||
/**
|
||||
* A mutation used to update a cart’s details such as region, customer email, shipping address, and more.
|
||||
* Using it is equivalent to using the {@link useUpdateCart} mutation.
|
||||
*/
|
||||
updateCart: ReturnType<typeof useUpdateCart>
|
||||
/**
|
||||
* A mutation used to add a shipping method to the cart during checkout.
|
||||
* Using it is equivalent to using the {@link useAddShippingMethodToCart} mutation.
|
||||
*/
|
||||
addShippingMethod: ReturnType<typeof useAddShippingMethodToCart>
|
||||
/**
|
||||
* The number of items in the cart.
|
||||
*/
|
||||
totalItems: number
|
||||
}
|
||||
|
||||
const CartContext = React.createContext<CartContext | null>(null)
|
||||
|
||||
/**
|
||||
* This hook exposes the context of {@link CartProvider}.
|
||||
*
|
||||
* The context provides helper functions and mutations for managing the cart and checkout. You can refer to the following guides for examples on how to use them:
|
||||
*
|
||||
* - [How to Add Cart Functionality](https://docs.medusajs.com/modules/carts-and-checkout/storefront/implement-cart)
|
||||
* - [How to Implement Checkout Flow](https://docs.medusajs.com/modules/carts-and-checkout/storefront/implement-checkout-flow)
|
||||
*
|
||||
* @example
|
||||
* ```tsx title="src/Cart.ts"
|
||||
* import * as React from "react"
|
||||
*
|
||||
* import { useCart } from "medusa-react"
|
||||
*
|
||||
* const Cart = () => {
|
||||
* const handleClick = () => {
|
||||
* createCart.mutate({}) // create an empty cart
|
||||
* }
|
||||
*
|
||||
* const { cart, createCart } = useCart()
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {createCart.isLoading && <div>Loading...</div>}
|
||||
* {!cart?.id && (
|
||||
* <button onClick={handleClick}>
|
||||
* Create cart
|
||||
* </button>
|
||||
* )}
|
||||
* {cart?.id && (
|
||||
* <div>Cart ID: {cart.id}</div>
|
||||
* )}
|
||||
* </div>
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* export default Cart
|
||||
* ```
|
||||
*
|
||||
* In the example above, you retrieve the `createCart` mutation and `cart` state object using the `useCart` hook.
|
||||
* If the `cart` is not set, a button is shown. When the button is clicked, the `createCart` mutation is executed, which interacts with the backend and creates a new cart.
|
||||
*
|
||||
* After the cart is created, the `cart` state variable is set and its ID is shown instead of the button.
|
||||
*
|
||||
* :::note
|
||||
*
|
||||
* The example above does not store in the browser the ID of the cart created, so the cart’s data will be gone on refresh.
|
||||
* You would have to do that using the browser’s [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).
|
||||
*
|
||||
* :::
|
||||
*
|
||||
* @customNamespace Providers.Cart
|
||||
*/
|
||||
export const useCart = () => {
|
||||
const context = React.useContext(CartContext)
|
||||
if (!context) {
|
||||
@@ -34,8 +131,14 @@ export const useCart = () => {
|
||||
return context
|
||||
}
|
||||
|
||||
interface CartProps {
|
||||
export interface CartProps {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
children: React.ReactNode
|
||||
/**
|
||||
* An optional initial value to be used for the cart.
|
||||
*/
|
||||
initialState?: Cart
|
||||
}
|
||||
|
||||
@@ -44,6 +147,44 @@ const defaultInitialState = {
|
||||
items: [] as any,
|
||||
} as Cart
|
||||
|
||||
/**
|
||||
* `CartProvider` makes use of some of the hooks already exposed by `medusa-react` to perform cart operations on the Medusa backend.
|
||||
* You can use it to create a cart, start the checkout flow, authorize payment sessions, and so on.
|
||||
*
|
||||
* It also manages one single global piece of state which represents a cart, exactly like the one created on your Medusa backend.
|
||||
*
|
||||
* To use `CartProvider`, you first have to insert it somewhere in your component tree below the {@link Providers.Medusa.MedusaProvider | MedusaProvider}. Then, in any of the child components,
|
||||
* you can use the {@link useCart} hook exposed by `medusa-react` to get access to cart operations and data.
|
||||
*
|
||||
* @param {CartProps} param0 - Props of the provider.
|
||||
*
|
||||
* @example
|
||||
* ```tsx title="src/App.ts"
|
||||
* import { CartProvider, MedusaProvider } from "medusa-react"
|
||||
* import Storefront from "./Storefront"
|
||||
* import { QueryClient } from "@tanstack/react-query"
|
||||
* import React from "react"
|
||||
*
|
||||
* const queryClient = new QueryClient()
|
||||
*
|
||||
* function App() {
|
||||
* return (
|
||||
* <MedusaProvider
|
||||
* queryClientProviderProps={{ client: queryClient }}
|
||||
* baseUrl="http://localhost:9000"
|
||||
* >
|
||||
* <CartProvider>
|
||||
* <Storefront />
|
||||
* </CartProvider>
|
||||
* </MedusaProvider>
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* export default App
|
||||
* ```
|
||||
*
|
||||
* @customNamespace Providers.Cart
|
||||
*/
|
||||
export const CartProvider = ({
|
||||
children,
|
||||
initialState = defaultInitialState,
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/**
|
||||
* @packageDocumentation
|
||||
*
|
||||
* :::info
|
||||
*
|
||||
* This is an experimental feature.
|
||||
*
|
||||
* :::
|
||||
*
|
||||
* `medusa-react` exposes React Context Providers that facilitate building custom storefronts.
|
||||
*
|
||||
* @customNamespace Providers
|
||||
*/
|
||||
|
||||
export * from "./medusa"
|
||||
export * from "./session-cart"
|
||||
export * from "./cart"
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @packageDocumentation
|
||||
*
|
||||
* @customNamespace Providers.Medusa
|
||||
*/
|
||||
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
import {
|
||||
QueryClientProvider,
|
||||
@@ -5,12 +11,50 @@ import {
|
||||
} from "@tanstack/react-query"
|
||||
import React from "react"
|
||||
|
||||
interface MedusaContextState {
|
||||
export interface MedusaContextState {
|
||||
/**
|
||||
* The Medusa JS Client instance.
|
||||
*/
|
||||
client: Medusa
|
||||
}
|
||||
|
||||
const MedusaContext = React.createContext<MedusaContextState | null>(null)
|
||||
|
||||
/**
|
||||
* This hook gives you access to context of {@link MedusaProvider}. It's useful if you want access to the
|
||||
* [Medusa JS Client](https://docs.medusajs.com/js-client/overview).
|
||||
*
|
||||
* @example
|
||||
* import React from "react"
|
||||
* import { useMeCustomer, useMedusa } from "medusa-react"
|
||||
*
|
||||
* const CustomerLogin = () => {
|
||||
* const { client } = useMedusa()
|
||||
* const { refetch: refetchCustomer } = useMeCustomer()
|
||||
* // ...
|
||||
*
|
||||
* const handleLogin = (
|
||||
* email: string,
|
||||
* password: string
|
||||
* ) => {
|
||||
* client.auth.authenticate({
|
||||
* email,
|
||||
* password
|
||||
* })
|
||||
* .then(() => {
|
||||
* // customer is logged-in successfully
|
||||
* refetchCustomer()
|
||||
* })
|
||||
* .catch(() => {
|
||||
* // an error occurred.
|
||||
* })
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* @customNamespace Providers.Medusa
|
||||
*/
|
||||
export const useMedusa = () => {
|
||||
const context = React.useContext(MedusaContext)
|
||||
if (!context) {
|
||||
@@ -19,27 +63,79 @@ export const useMedusa = () => {
|
||||
return context
|
||||
}
|
||||
|
||||
interface MedusaProviderProps {
|
||||
export interface MedusaProviderProps {
|
||||
/**
|
||||
* The URL to your Medusa backend.
|
||||
*/
|
||||
baseUrl: string
|
||||
/**
|
||||
* An object used to set the Tanstack Query client. The object requires a `client` property,
|
||||
* which should be an instance of [QueryClient](https://tanstack.com/query/v4/docs/react/reference/QueryClient).
|
||||
*/
|
||||
queryClientProviderProps: QueryClientProviderProps
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
children: React.ReactNode
|
||||
/**
|
||||
* Authentication token
|
||||
* API key used for authenticating admin requests. Follow [this guide](https://docs.medusajs.com/api/admin#authentication) to learn how to create an API key for an admin user.
|
||||
*/
|
||||
apiKey?: string
|
||||
/**
|
||||
* PublishableApiKey identifier that defines the scope of resources
|
||||
* available within the request
|
||||
* Publishable API key used for storefront requests. You can create a publishable API key either using the
|
||||
* [admin APIs](https://docs.medusajs.com/development/publishable-api-keys/admin/manage-publishable-api-keys) or the
|
||||
* [Medusa admin](https://docs.medusajs.com/user-guide/settings/publishable-api-keys#create-publishable-api-key).
|
||||
*/
|
||||
publishableApiKey?: string
|
||||
/**
|
||||
* Number of times to retry a request if it fails
|
||||
* @default 3
|
||||
* Number of times to retry a request if it fails.
|
||||
*
|
||||
* @defaultValue 3
|
||||
*/
|
||||
maxRetries?: number
|
||||
/**
|
||||
* An object of custom headers to pass with every request. Each key of the object is the name of the header, and its value is the header's value.
|
||||
*
|
||||
* @defaultValue `{}`
|
||||
*/
|
||||
customHeaders?: Record<string, any>
|
||||
}
|
||||
|
||||
/**
|
||||
* The `MedusaProvider` must be used at the highest possible point in the React component tree. Using any of `medusa-react`'s hooks or providers requires having `MedusaProvider`
|
||||
* higher in the component tree.
|
||||
*
|
||||
* @param {MedusaProviderProps} param0 - Props of the provider.
|
||||
*
|
||||
* @example
|
||||
* ```tsx title="src/App.ts"
|
||||
* import { MedusaProvider } from "medusa-react"
|
||||
* import Storefront from "./Storefront"
|
||||
* import { QueryClient } from "@tanstack/react-query"
|
||||
* import React from "react"
|
||||
*
|
||||
* const queryClient = new QueryClient()
|
||||
*
|
||||
* const App = () => {
|
||||
* return (
|
||||
* <MedusaProvider
|
||||
* queryClientProviderProps={{ client: queryClient }}
|
||||
* baseUrl="http://localhost:9000"
|
||||
* >
|
||||
* <Storefront />
|
||||
* </MedusaProvider>
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* export default App
|
||||
* ```
|
||||
*
|
||||
* In the example above, you wrap the `Storefront` component with the `MedusaProvider`. `Storefront` is assumed to be the top-level component of your storefront, but you can place `MedusaProvider` at any point in your tree. Only children of `MedusaProvider` can benefit from its hooks.
|
||||
*
|
||||
* The `Storefront` component and its child components can now use hooks exposed by Medusa React.
|
||||
*
|
||||
* @customNamespace Providers.Medusa
|
||||
*/
|
||||
export const MedusaProvider = ({
|
||||
queryClientProviderProps,
|
||||
baseUrl,
|
||||
|
||||
@@ -1,32 +1,113 @@
|
||||
/**
|
||||
* @packageDocumentation
|
||||
*
|
||||
* @customNamespace Providers.Session Cart
|
||||
*/
|
||||
|
||||
import React, { useContext, useEffect } from "react"
|
||||
import { getVariantPrice } from "../helpers"
|
||||
import { useLocalStorage } from "../hooks/utils"
|
||||
import { ProductVariant, RegionInfo } from "../types"
|
||||
import { isArray, isEmpty, isObject } from "../utils"
|
||||
|
||||
interface Item {
|
||||
/**
|
||||
* A session cart's item.
|
||||
*/
|
||||
export interface Item {
|
||||
/**
|
||||
* The product variant represented by this item in the cart.
|
||||
*/
|
||||
variant: ProductVariant
|
||||
/**
|
||||
* The quantity added in the cart.
|
||||
*/
|
||||
quantity: number
|
||||
/**
|
||||
* The total amount of the item in the cart.
|
||||
*/
|
||||
readonly total?: number
|
||||
}
|
||||
|
||||
export interface SessionCartState {
|
||||
/**
|
||||
* The region of the cart.
|
||||
*/
|
||||
region: RegionInfo
|
||||
/**
|
||||
* The items in the cart.
|
||||
*/
|
||||
items: Item[]
|
||||
/**
|
||||
* The total items in the cart.
|
||||
*/
|
||||
totalItems: number
|
||||
/**
|
||||
* The total amount of the cart.
|
||||
*/
|
||||
total: number
|
||||
}
|
||||
|
||||
interface SessionCartContextState extends SessionCartState {
|
||||
export interface SessionCartContextState extends SessionCartState {
|
||||
/**
|
||||
* A state function used to set the region.
|
||||
*
|
||||
* @param region - The new value of the region.
|
||||
*/
|
||||
setRegion: (region: RegionInfo) => void
|
||||
/**
|
||||
* This function adds an item to the session cart.
|
||||
*
|
||||
* @param {Item} item - The item to add.
|
||||
*/
|
||||
addItem: (item: Item) => void
|
||||
/**
|
||||
* This function removes an item from the session cart.
|
||||
*
|
||||
* @param {string} id - The ID of the item.
|
||||
*/
|
||||
removeItem: (id: string) => void
|
||||
/**
|
||||
* This function updates an item in the session cart.
|
||||
*
|
||||
* @param {string} id - The ID of the item.
|
||||
* @param {Partial<Item>} item - The item's data to update.
|
||||
*/
|
||||
updateItem: (id: string, item: Partial<Item>) => void
|
||||
/**
|
||||
* A state function used to set the items in the cart.
|
||||
*
|
||||
* @param {Item[]} items - The items to set in the cart.
|
||||
*/
|
||||
setItems: (items: Item[]) => void
|
||||
/**
|
||||
* This function updates an item's quantity in the cart.
|
||||
*
|
||||
* @param {string} id - The ID of the item.
|
||||
* @param {number} quantity - The new quantity of the item.
|
||||
*/
|
||||
updateItemQuantity: (id: string, quantity: number) => void
|
||||
/**
|
||||
* This function increments the item's quantity in the cart.
|
||||
*
|
||||
* @param {string} id - The ID of the item.
|
||||
*/
|
||||
incrementItemQuantity: (id: string) => void
|
||||
/**
|
||||
* This function decrements the item's quantity in the cart.
|
||||
*
|
||||
* @param {string} id - The ID of the item.
|
||||
*/
|
||||
decrementItemQuantity: (id: string) => void
|
||||
/**
|
||||
* This function retrieves an item's details by its ID.
|
||||
*
|
||||
* @param {string} id - The ID of the item.
|
||||
* @returns {Item | undefined} The item in the cart, if found.
|
||||
*/
|
||||
getItem: (id: string) => Item | undefined
|
||||
/**
|
||||
* Removes all items in the cart.
|
||||
*/
|
||||
clearItems: () => void
|
||||
}
|
||||
|
||||
@@ -111,6 +192,9 @@ const reducer = (state: SessionCartState, action: Action) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
export const generateCartState = (state: SessionCartState, items: Item[]) => {
|
||||
const newItems = generateItems(state.region, items)
|
||||
return {
|
||||
@@ -135,8 +219,14 @@ const calculateSessionCartTotal = (items: Item[]) => {
|
||||
)
|
||||
}
|
||||
|
||||
interface SessionCartProviderProps {
|
||||
export interface SessionCartProviderProps {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
children: React.ReactNode
|
||||
/**
|
||||
* An optional initial value to be used for the session cart.
|
||||
*/
|
||||
initialState?: SessionCartState
|
||||
}
|
||||
|
||||
@@ -147,6 +237,44 @@ const defaultInitialState: SessionCartState = {
|
||||
totalItems: 0,
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike the {@link Providers.Cart.CartProvider | CartProvider}, `SessionProvider` never interacts with the Medusa backend. It can be used to implement the user experience related to managing a cart’s items.
|
||||
* Its state variables are JavaScript objects living in the browser, but are in no way communicated with the backend.
|
||||
*
|
||||
* You can use the `SessionProvider` as a lightweight client-side cart functionality. It’s not stored in any database or on the Medusa backend.
|
||||
*
|
||||
* To use `SessionProvider`, you first have to insert it somewhere in your component tree below the {@link Providers.Medusa.MedusaProvider | MedusaProvider}. Then, in any of the child components,
|
||||
* you can use the {@link useSessionCart} hook to get access to client-side cart item functionalities.
|
||||
*
|
||||
* @param {SessionCartProviderProps} param0 - Props of the provider.
|
||||
*
|
||||
* @example
|
||||
* ```tsx title="src/App.ts"
|
||||
* import { SessionProvider, MedusaProvider } from "medusa-react"
|
||||
* import Storefront from "./Storefront"
|
||||
* import { QueryClient } from "@tanstack/react-query"
|
||||
* import React from "react"
|
||||
*
|
||||
* const queryClient = new QueryClient()
|
||||
*
|
||||
* const App = () => {
|
||||
* return (
|
||||
* <MedusaProvider
|
||||
* queryClientProviderProps={{ client: queryClient }}
|
||||
* baseUrl="http://localhost:9000"
|
||||
* >
|
||||
* <SessionProvider>
|
||||
* <Storefront />
|
||||
* </SessionProvider>
|
||||
* </MedusaProvider>
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* export default App
|
||||
* ```
|
||||
*
|
||||
* @customNamespace Providers.Session Cart
|
||||
*/
|
||||
export const SessionCartProvider = ({
|
||||
initialState = defaultInitialState,
|
||||
children,
|
||||
@@ -278,6 +406,28 @@ export const SessionCartProvider = ({
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This hook exposes the context of {@link SessionCartProvider}.
|
||||
*
|
||||
* @example
|
||||
* The following example assumes that you've added `SessionCartProvider` previously in the React components tree:
|
||||
*
|
||||
* ```tsx title="src/Products.ts"
|
||||
* const Products = () => {
|
||||
* const { addItem } = useSessionCart()
|
||||
* // ...
|
||||
*
|
||||
* function addToCart(variant: ProductVariant) {
|
||||
* addItem({
|
||||
* variant: variant,
|
||||
* quantity: 1,
|
||||
* })
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @customNamespace Providers.Session Cart
|
||||
*/
|
||||
export const useSessionCart = () => {
|
||||
const context = useContext(SessionCartContext)
|
||||
if (!context) {
|
||||
|
||||
Reference in New Issue
Block a user