docs: added re-order guide (#12363)
* docs: added re-order guide * reiteration to intro * adjustment to title * fix vale error * generate * fix vale
This commit is contained in:
@@ -0,0 +1,659 @@
|
||||
---
|
||||
sidebar_label: "Re-Order"
|
||||
tags:
|
||||
- name: order
|
||||
label: "Implement Re-Order"
|
||||
- server
|
||||
- tutorial
|
||||
---
|
||||
|
||||
import { Github, PlaySolid } from "@medusajs/icons"
|
||||
import { Prerequisites, WorkflowDiagram } from "docs-ui"
|
||||
|
||||
export const ogImage = "https://res.cloudinary.com/dza7lstvk/image/upload/v1742389227/Medusa%20Resources/product-reviews_zia79g.jpg"
|
||||
|
||||
export const metadata = {
|
||||
title: `Implement Quick Re-Order Functionality in Medusa`,
|
||||
openGraph: {
|
||||
images: [
|
||||
{
|
||||
url: ogImage,
|
||||
width: 1600,
|
||||
height: 836,
|
||||
type: "image/jpeg"
|
||||
}
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
images: [
|
||||
{
|
||||
url: ogImage,
|
||||
width: 1600,
|
||||
height: 836,
|
||||
type: "image/jpeg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this tutorial, you'll learn how to implement a re-order functionality in Medusa.
|
||||
|
||||
When you install a Medusa application, you get a fully-fledged commerce platform with a Framework for customization. The Medusa application's commerce features are built around [Commerce Modules](../../../commerce-modules/page.mdx) which are available out-of-the-box. The features include order-management features.
|
||||
|
||||
The Medusa Framework facilitates building custom features that are necessary for your business use case. In this tutorial, you'll learn how to implement a re-order functionality in Medusa. This feature is useful for businesses whose customers are likely to repeat their orders, such as B2B or food delivery businesses.
|
||||
|
||||
You can follow this guide whether you're new to Medusa or an advanced Medusa developer.
|
||||
|
||||
## Summary
|
||||
|
||||
By following this tutorial, you'll learn how to:
|
||||
|
||||
- Install and set up Medusa.
|
||||
- Define the logic to re-order an order.
|
||||
- Customize the Next.js Starter Storefront to add a re-order button.
|
||||
|
||||

|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "https://github.com/medusajs/examples/tree/main/re-order",
|
||||
title: "Re-Order Repository",
|
||||
text: "Find the full code for this guide in this repository.",
|
||||
icon: Github,
|
||||
},
|
||||
{
|
||||
// TODO update link
|
||||
href: "https://res.cloudinary.com/dza7lstvk/raw/upload/v1741941475/OpenApi/product-reviews_jh8ohj.yaml",
|
||||
title: "OpenApi Specs for Postman",
|
||||
text: "Import this OpenApi Specs file into tools like Postman.",
|
||||
icon: PlaySolid,
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Install a Medusa Application
|
||||
|
||||
<Prerequisites items={[
|
||||
{
|
||||
text: "Node.js v20+",
|
||||
link: "https://nodejs.org/en/download"
|
||||
},
|
||||
{
|
||||
text: "Git CLI tool",
|
||||
link: "https://git-scm.com/downloads"
|
||||
},
|
||||
{
|
||||
text: "PostgreSQL",
|
||||
link: "https://www.postgresql.org/download/"
|
||||
}
|
||||
]} />
|
||||
|
||||
Start by installing the Medusa application on your machine with the following command:
|
||||
|
||||
```bash
|
||||
npx create-medusa-app@latest
|
||||
```
|
||||
|
||||
You'll first be asked for the project's name. Then, when asked whether you want to install the [Next.js Starter Storefront](../../../nextjs-starter/page.mdx), choose Yes.
|
||||
|
||||
Afterwards, the installation process will start, which will install the Medusa application in a directory with your project's name, and the Next.js Starter Storefront in a separate directory with the `{project-name}-storefront` name.
|
||||
|
||||
<Note title="Why is the storefront installed separately?">
|
||||
|
||||
The Medusa application is composed of a headless Node.js server and an admin dashboard. The storefront is installed or custom-built separately and connects to the Medusa application through its REST endpoints, called [API routes](!docs!/learn/fundamentals/api-routes). Learn more in [Medusa's Architecture documentation](!docs!/learn/introduction/architecture).
|
||||
|
||||
</Note>
|
||||
|
||||
Once the installation finishes successfully, the Medusa Admin dashboard will open with a form to create a new user. Enter the user's credentials and submit the form. Afterwards, you can log in with the new user and explore the dashboard.
|
||||
|
||||
<Note title="Ran into Errors?">
|
||||
|
||||
Check out the [troubleshooting guides](../../../troubleshooting/create-medusa-app-errors/page.mdx) for help.
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Implement Re-Order Workflow
|
||||
|
||||
To build custom commerce features in Medusa, you create a [workflow](!docs!/learn/fundamentals/workflows). A workflow is a series of queries and actions, called steps, that complete a task.
|
||||
|
||||
By using workflows, you can track their executions' progress, define roll-back logic, and configure other advanced features. Then, you execute the workflow from other customizations, such as in an API Route.
|
||||
|
||||
In this section, you'll implement the re-order functionality in a workflow. Later, you'll execute the workflow in a custom API route.
|
||||
|
||||
<Note>
|
||||
|
||||
Refer to the [Workflows documentation](!docs!/learn/fundamentals/workflows) to learn more.
|
||||
|
||||
</Note>
|
||||
|
||||
The workflow will have the following steps:
|
||||
|
||||
<WorkflowDiagram
|
||||
workflow={{
|
||||
name: "reorderWorkflow",
|
||||
steps: [
|
||||
{
|
||||
name: "useQueryGraphStep",
|
||||
type: "step",
|
||||
description: "Retrieve the order's details.",
|
||||
link: "/references/helper-steps/useQueryGraphStep",
|
||||
depth: 1,
|
||||
},
|
||||
{
|
||||
name: "createCartWorkflow",
|
||||
type: "step",
|
||||
description: "Create a cart for the re-order.",
|
||||
link: "/references/medusa-workflows/createCartWorkflow",
|
||||
depth: 1,
|
||||
},
|
||||
{
|
||||
name: "addShippingMethodToCartWorkflow",
|
||||
type: "step",
|
||||
description: "Add the order's shipping method(s) to the cart.",
|
||||
link: "/references/medusa-workflows/addShippingMethodToCartWorkflow",
|
||||
depth: 1,
|
||||
},
|
||||
{
|
||||
name: "useQueryGraphStep",
|
||||
type: "step",
|
||||
description: "Retrieve the cart's details.",
|
||||
link: "/references/helper-steps/useQueryGraphStep",
|
||||
depth: 1,
|
||||
}
|
||||
]
|
||||
}}
|
||||
hideLegend
|
||||
/>
|
||||
|
||||
This workflow uses steps from Medusa's `@medusajs/medusa/core-flows` package. So, you can implement the workflow without implementing custom steps.
|
||||
|
||||
### a. Create the Workflow
|
||||
|
||||
To create the workflow, create the file `src/workflows/reorder.ts` with the following content:
|
||||
|
||||
export const workflowHighlights1 = [
|
||||
["20", "useQueryGraphStep", "Retrieve the order's details."],
|
||||
]
|
||||
|
||||
```ts title="src/workflows/reorder.ts" highlights={workflowHighlights1}
|
||||
import {
|
||||
createWorkflow,
|
||||
transform,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
addShippingMethodToCartWorkflow,
|
||||
createCartWorkflow,
|
||||
useQueryGraphStep,
|
||||
} from "@medusajs/medusa/core-flows"
|
||||
|
||||
type ReorderWorkflowInput = {
|
||||
order_id: string
|
||||
}
|
||||
|
||||
export const reorderWorkflow = createWorkflow(
|
||||
"reorder",
|
||||
({ order_id }: ReorderWorkflowInput) => {
|
||||
// @ts-ignore
|
||||
const { data: orders } = useQueryGraphStep({
|
||||
entity: "order",
|
||||
fields: [
|
||||
"*",
|
||||
"items.*",
|
||||
"shipping_address.*",
|
||||
"billing_address.*",
|
||||
"region.*",
|
||||
"sales_channel.*",
|
||||
"shipping_methods.*",
|
||||
"customer.*",
|
||||
],
|
||||
filters: {
|
||||
id: order_id,
|
||||
},
|
||||
})
|
||||
|
||||
// TODO create a cart with the order's items
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
You create a workflow using `createWorkflow` from the Workflows SDK. It accepts the workflow's unique name as a first parameter.
|
||||
|
||||
It accepts as a second parameter a constructor function, which is the workflow's implementation. The function can accept input, which in this case is an object holding the ID of the order to re-order.
|
||||
|
||||
In the workflow's constructor function, so far you use the `useQueryGraphStep` step to retrieve the order's details. This step uses [Query](!docs!/learn/fundamentals/module-links/query) under the hood, which allows you to query data across [modules](!docs!/learn/fundamentals/modules).
|
||||
|
||||
<Note>
|
||||
|
||||
Refer to the [Query documentation](!docs!/learn/fundamentals/module-links/query) to learn more about how to use it.
|
||||
|
||||
</Note>
|
||||
|
||||
### b. Create a Cart
|
||||
|
||||
Next, you need to create a cart using the old order's details. You can use the `createCartWorkflow` step to create a cart, but you first need to prepare its input data.
|
||||
|
||||
Replace the `TODO` in the workflow with the following:
|
||||
|
||||
export const workflowHighlights2 = [
|
||||
["1", "transform", "Prepare the input for cart creation."],
|
||||
["37", "createCartWorkflow", "Create the cart."],
|
||||
]
|
||||
|
||||
```ts title="src/workflows/reorder.ts" highlights={workflowHighlights2}
|
||||
const createInput = transform({
|
||||
orders,
|
||||
}, (data) => {
|
||||
return {
|
||||
region_id: data.orders[0].region_id!,
|
||||
sales_channel_id: data.orders[0].sales_channel_id!,
|
||||
customer_id: data.orders[0].customer_id!,
|
||||
email: data.orders[0].email!,
|
||||
billing_address: {
|
||||
first_name: data.orders[0].billing_address?.first_name!,
|
||||
last_name: data.orders[0].billing_address?.last_name!,
|
||||
address_1: data.orders[0].billing_address?.address_1!,
|
||||
city: data.orders[0].billing_address?.city!,
|
||||
country_code: data.orders[0].billing_address?.country_code!,
|
||||
province: data.orders[0].billing_address?.province!,
|
||||
postal_code: data.orders[0].billing_address?.postal_code!,
|
||||
phone: data.orders[0].billing_address?.phone!,
|
||||
},
|
||||
shipping_address: {
|
||||
first_name: data.orders[0].shipping_address?.first_name!,
|
||||
last_name: data.orders[0].shipping_address?.last_name!,
|
||||
address_1: data.orders[0].shipping_address?.address_1!,
|
||||
city: data.orders[0].shipping_address?.city!,
|
||||
country_code: data.orders[0].shipping_address?.country_code!,
|
||||
province: data.orders[0].shipping_address?.province!,
|
||||
postal_code: data.orders[0].shipping_address?.postal_code!,
|
||||
phone: data.orders[0].shipping_address?.phone!,
|
||||
},
|
||||
items: data.orders[0].items?.map((item) => ({
|
||||
variant_id: item?.variant_id!,
|
||||
quantity: item?.quantity!,
|
||||
unit_price: item?.unit_price!,
|
||||
})),
|
||||
}
|
||||
})
|
||||
|
||||
const { id: cart_id } = createCartWorkflow.runAsStep({
|
||||
input: createInput,
|
||||
})
|
||||
|
||||
// TODO add the shipping method to the cart
|
||||
```
|
||||
|
||||
Data manipulation is not allowed in a workflow, as Medusa stores its definition before executing it. Instead, you can use `transform` from the Workflows SDK to manipulate the data.
|
||||
|
||||
<Note>
|
||||
|
||||
Learn more about why you can't manipulate data in a workflow and the `transform` function in the [Data Manipulation in Workflows documentation](!docs!/learn/fundamentals/workflows/variable-manipulation).
|
||||
|
||||
</Note>
|
||||
|
||||
`transform` accepts the following parameters:
|
||||
|
||||
1. The data to use in the transformation function.
|
||||
2. A transformation function that accepts the data from the first parameter and returns the transformed data.
|
||||
|
||||
In the above code snippet, you use `transform` to create the input for the `createCartWorkflow` step. The input is an object that holds the cart's details, including its items, shipping and billing addresses, and more.
|
||||
|
||||
<Note>
|
||||
|
||||
Learn about other input parameters you can pass in the [createCartWorkflow reference](/references/medusa-workflows/createCartWorkflow).
|
||||
|
||||
</Note>
|
||||
|
||||
After that, you execute the `createCartWorkflow` passing it the transformed input. The workflow returns the cart's details, including its ID.
|
||||
|
||||
### c. Add Shipping Methods
|
||||
|
||||
Next, you need to add the order's shipping method(s) to the cart. This saves the customer from having to select a shipping method again.
|
||||
|
||||
You can use the `addShippingMethodToCartWorkflow` step to add the shipping method(s) to the cart.
|
||||
|
||||
Replace the `TODO` in the workflow with the following:
|
||||
|
||||
export const workflowHighlights3 = [
|
||||
["1", "transform", "Prepare the input for adding shipping methods to the cart."],
|
||||
["14", "addShippingMethodToCartWorkflow", "Add the shipping methods to the cart."],
|
||||
]
|
||||
|
||||
```ts title="src/workflows/reorder.ts" highlights={workflowHighlights3}
|
||||
const addShippingMethodToCartInput = transform({
|
||||
cart_id,
|
||||
orders,
|
||||
}, (data) => {
|
||||
return {
|
||||
cart_id: data.cart_id,
|
||||
options: data.orders[0].shipping_methods?.map((method) => ({
|
||||
id: method?.shipping_option_id!,
|
||||
data: method?.data!,
|
||||
})) ?? [],
|
||||
}
|
||||
})
|
||||
|
||||
addShippingMethodToCartWorkflow.runAsStep({
|
||||
input: addShippingMethodToCartInput,
|
||||
})
|
||||
|
||||
// TODO retrieve and return the cart's details
|
||||
```
|
||||
|
||||
Again, you use `transform` to prepare the input for the `addShippingMethodToCartWorkflow`. The input includes the cart's ID and the shipping method(s) to add to the cart.
|
||||
|
||||
Then, you execute the `addShippingMethodToCartWorkflow` to add the shipping method(s) to the cart.
|
||||
|
||||
### d. Retrieve and Return the Cart's Details
|
||||
|
||||
Finally, you need to retrieve the cart's details and return them as the workflow's output.
|
||||
|
||||
Replace the `TODO` in the workflow with the following:
|
||||
|
||||
export const workflowHighlights4 = [
|
||||
["2", "useQueryGraphStep", "Retrieve the cart's details."],
|
||||
["28", "WorkflowResponse", "Return the cart's details."],
|
||||
]
|
||||
|
||||
```ts title="src/workflows/reorder.ts" highlights={workflowHighlights4}
|
||||
// @ts-ignore
|
||||
const { data: carts } = useQueryGraphStep({
|
||||
entity: "cart",
|
||||
fields: [
|
||||
"*",
|
||||
"items.*",
|
||||
"shipping_methods.*",
|
||||
"shipping_address.*",
|
||||
"billing_address.*",
|
||||
"region.*",
|
||||
"sales_channel.*",
|
||||
"promotions.*",
|
||||
"currency_code",
|
||||
"subtotal",
|
||||
"item_total",
|
||||
"total",
|
||||
"item_subtotal",
|
||||
"shipping_subtotal",
|
||||
"customer.*",
|
||||
"payment_collection.*",
|
||||
|
||||
],
|
||||
filters: {
|
||||
id: cart_id,
|
||||
},
|
||||
}).config({ name: "retrieve-cart" })
|
||||
|
||||
return new WorkflowResponse(carts[0])
|
||||
```
|
||||
|
||||
You execute the `useQueryGraphStep` again to retrieve the cart's details. Since you're re-using a step, you have to rename it using the `config` method.
|
||||
|
||||
Finally, you return the cart's details. A workflow must return an instance of `WorkflowResponse`.
|
||||
|
||||
The `WorkflowResponse` constructor accepts the workflow's output as a parameter, which is the cart's details in this case.
|
||||
|
||||
In the next step, you'll create an API route that exposes the re-order functionality.
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Create Re-Order API Route
|
||||
|
||||
Now that you have the logic to re-order, you need to expose it so that frontend clients, such as a storefront, can use it. You do this by creating an [API route](!docs!/learn/fundamentals/api-routes).
|
||||
|
||||
An API Route is an endpoint that exposes commerce features to external applications and clients, such as storefronts. You'll create an API route at the path `/store/customers/me/orders/:id` that executes the workflow from the previous step.
|
||||
|
||||
<Note>
|
||||
|
||||
Refer to the [API Routes documentation](!docs!/learn/fundamentals/api-routes) to learn more.
|
||||
|
||||
</Note>
|
||||
|
||||
An API route is created in a `route.ts` file under a sub-directory of the `src/api` directory. The path of the API route is the file's path relative to `src/api`.
|
||||
|
||||
So, create the file `src/api/store/customers/me/orders/[id]/route.ts` with the following content:
|
||||
|
||||
```ts title="src/api/store/customers/me/orders/[id]/route.ts"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/framework/http"
|
||||
import { reorderWorkflow } from "../../../../../../workflows/reorder"
|
||||
|
||||
export async function POST(
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse
|
||||
) {
|
||||
const { id } = req.params
|
||||
|
||||
const { result } = await reorderWorkflow(req.scope).run({
|
||||
input: {
|
||||
order_id: id,
|
||||
},
|
||||
})
|
||||
|
||||
return res.json({
|
||||
cart: result,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Since you export a `POST` route handler function, you expose a `POST` API route at `/store/customers/me/orders/:id`.
|
||||
|
||||
<Note>
|
||||
|
||||
API routes that start with `/store/customers/me` are protected by default, meaning that only authenticated customers can access them. Learn more in the [Protected API Routes documentation](!docs!/learn/fundamentals/api-routes/protected-routes).
|
||||
|
||||
</Note>
|
||||
|
||||
The route handler function accepts two parameters:
|
||||
|
||||
1. A request object with details and context on the request, such as path parameters or authenticated customer details.
|
||||
2. A response object to manipulate and send the response.
|
||||
|
||||
In the route handler function, you execute the `reorderWorkflow`. To execute a workflow, you:
|
||||
|
||||
- Invoke it, passing it the [Medusa container](!docs!/learn/fundamentals/medusa-container) available in the `req.scope` property.
|
||||
- The Medusa container is a registry of Framework and commerce resources that you can resolve and use in your customizations.
|
||||
- Call the `run` method, passing it an object with the workflow's input.
|
||||
|
||||
You pass the order ID from the request's path parameters as the workflow's input. Finally, you return the created cart's details in the response.
|
||||
|
||||
You'll test out this API route after you customize the Next.js Starter Storefront.
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Customize the Next.js Starter Storefront
|
||||
|
||||
In this step, you'll customize the [Next.js Starter Storefront](../../../nextjs-starter/page.mdx) to add a re-order button. You installed the Next.js Starter Storefront in the first step with the Medusa application, but you can also install it separately as explained in the [Next.js Starter Storefront documentation](../../../nextjs-starter/page.mdx).
|
||||
|
||||
The Next.js Starter Storefront provides rich commerce features and a sleek design. You can use it as-is or build on top of it to tailor it for your business's unique use case, design, and customer experience.
|
||||
|
||||
<Note title="Reminder" forceMultiline>
|
||||
|
||||
The Next.js Starter Storefront was installed in a separate directory from Medusa. The directory's name is `{your-project}-storefront`.
|
||||
|
||||
So, if your Medusa application's directory is `medusa-reorder`, you can find the storefront by going back to the parent directory and changing to the `medusa-reorder-storefront` directory:
|
||||
|
||||
```bash
|
||||
cd ../medusa-reorder-storefront # change based on your project name
|
||||
```
|
||||
|
||||
</Note>
|
||||
|
||||
To add the re-order button, you will:
|
||||
|
||||
- Add a server function that re-orders an order using the API route from the previous step.
|
||||
- Add a button to the order details page that calls the server function.
|
||||
|
||||
### a. Add the Server Function
|
||||
|
||||
You'll add the server function for the re-order functionality in the `src/lib/data/orders.ts` file.
|
||||
|
||||
First, add the following import statement to the top of the file:
|
||||
|
||||
```ts title="src/lib/data/orders.ts" badgeLabel="Storefront" badgeColor="blue"
|
||||
import { setCartId } from "./cookies"
|
||||
```
|
||||
|
||||
Then, add the function at the end of the file:
|
||||
|
||||
```ts title="src/lib/data/orders.ts" badgeLabel="Storefront" badgeColor="blue"
|
||||
export const reorder = async (id: string) => {
|
||||
const headers = await getAuthHeaders()
|
||||
|
||||
const { cart } = await sdk.client.fetch<HttpTypes.StoreCartResponse>(
|
||||
`/store/customers/me/orders/${id}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers,
|
||||
}
|
||||
)
|
||||
|
||||
await setCartId(cart.id)
|
||||
|
||||
return cart
|
||||
}
|
||||
```
|
||||
|
||||
You add a function that accepts the order ID as a parameter.
|
||||
|
||||
The function uses the `client.fetch` method of the [JS SDK](../../../js-sdk/page.mdx) to send a request to the API route you created in the previous step.
|
||||
|
||||
<Note>
|
||||
|
||||
The JS SDK is already configured in the Next.js Starter Storefront. Refer to the [JS SDK documentation](../../../js-sdk/page.mdx) to learn more about it.
|
||||
|
||||
</Note>
|
||||
|
||||
Once the request succeeds, you use the `setCartId` function that's defined in the storefront to set the cart ID in a cookie. This ensures the cart is used across the storefront.
|
||||
|
||||
Finally, you return the cart's details.
|
||||
|
||||
### b. Add the Re-Order Button Component
|
||||
|
||||
Next, you'll add the component that shows the re-order button. You'll later add the component to the order details page.
|
||||
|
||||
To create the component, create the file `src/modules/order/components/reorder-action/index.tsx` with the following content:
|
||||
|
||||
export const componentHighlights = [
|
||||
["14", "handleReorder", "Re-order the order."],
|
||||
["21", "push", "Redirect to the checkout page."],
|
||||
["24", "toast.error", "Show the error message."],
|
||||
]
|
||||
|
||||
```tsx title="src/modules/order/components/reorder-action/index.tsx" badgeLabel="Storefront" badgeColor="blue" highlights={componentHighlights}
|
||||
import { Button, toast } from "@medusajs/ui"
|
||||
import { reorder } from "../../../../lib/data/orders"
|
||||
import { useState } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
|
||||
type ReorderActionProps = {
|
||||
orderId: string
|
||||
}
|
||||
|
||||
export default function ReorderAction({ orderId }: ReorderActionProps) {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const router = useRouter()
|
||||
|
||||
const handleReorder = async () => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const cart = await reorder(orderId)
|
||||
|
||||
setIsLoading(false)
|
||||
toast.success("Prepared cart to reorder. Proceeding to checkout...")
|
||||
router.push(`/${cart.shipping_address!.country_code}/checkout?step=payment`)
|
||||
} catch (error) {
|
||||
setIsLoading(false)
|
||||
toast.error(`Error reordering: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="primary"
|
||||
size="small"
|
||||
onClick={handleReorder}
|
||||
disabled={isLoading}
|
||||
>
|
||||
Reorder
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
You create a `ReorderAction` component that accepts the order ID as a prop.
|
||||
|
||||
In the component, you render a button that, when clicked, calls a `handleReorder` function. The function calls the `reorder` function you created in the previous step to re-order the order.
|
||||
|
||||
If the re-order succeeds, you redirect the user to the payment step of the checkout page. If it fails, you show an error message.
|
||||
|
||||
### c. Show Re-Order Button on Order Details Page
|
||||
|
||||
Finally, you'll show the `ReorderAction` component on the order details page.
|
||||
|
||||
In `src/modules/order/templates/order-details-template.tsx`, add the following import statement to the top of the file:
|
||||
|
||||
```tsx title="src/modules/order/templates/order-details-template.tsx" badgeLabel="Storefront" badgeColor="blue"
|
||||
import ReorderAction from "../components/reorder-action"
|
||||
```
|
||||
|
||||
Then, in the return statement of the `OrderDetailsTemplate` component, find the `OrderDetails` component and add the `ReorderAction` component below it:
|
||||
|
||||
```tsx title="src/modules/order/templates/order-details-template.tsx" badgeLabel="Storefront" badgeColor="blue"
|
||||
<ReorderAction orderId={order.id} />
|
||||
```
|
||||
|
||||
The re-order button will now be shown on the order details page.
|
||||
|
||||
### Test it Out
|
||||
|
||||
You'll now test out the re-order functionality.
|
||||
|
||||
First, to start the Medusa application, run the following command in the Medusa application's directory:
|
||||
|
||||
```bash npm2yarn badgeLabel="Medusa application" badgeColor="green"
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Then, in the Next.js Starter Storefront directory, run the following command to start the storefront:
|
||||
|
||||
```bash npm2yarn badgeLabel="Storefront" badgeColor="blue"
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The storefront will be running at `http://localhost:8000`. Open it in your browser.
|
||||
|
||||
To test out the re-order functionality:
|
||||
|
||||
- Create an account in the storefront.
|
||||
- Add a product to the cart and complete the checkout process to place an order.
|
||||
- Go to Account -> Orders, and click on the "See details" button.
|
||||
|
||||

|
||||
|
||||
On the order's details page, you'll find a "Reorder" button.
|
||||
|
||||

|
||||
|
||||
When you click on the button, a new cart will be created with the order's details, and you'll be redirected to the checkout page where you can complete the purchase.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
You now have a re-order functionality in your Medusa application and Next.js Starter Storefront. You can expand more on this feature based on your use case.
|
||||
|
||||
For example, you can add quick orders on the storefront's homepage, allowing customers to quickly re-order their last orders.
|
||||
|
||||
If you're new to Medusa, check out the [main documentation](!docs!/learn), where you'll get a more in-depth learning of all the concepts you've used in this guide and more.
|
||||
|
||||
To learn more about the commerce features that Medusa provides, check out Medusa's [Commerce Modules](../../../commerce-modules/page.mdx).
|
||||
Reference in New Issue
Block a user