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:
Shahed Nasser
2024-01-05 17:03:38 +02:00
committed by GitHub
parent 6fc6a9de6a
commit 7d650771d1
2811 changed files with 231856 additions and 455063 deletions
+143 -2
View File
@@ -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 carts 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 carts data will be gone on refresh.
* You would have to do that using the browsers [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"
+103 -7
View File
@@ -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 carts 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. Its 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) {