docs: add routing page (#9550)
- Add a new homepage to `book` project for the routing page - Move all main doc pages to be under `/v2/learn` (and added redirects + fixed links across docs) - Other: add admin components to resources dropdown + fixes to search on mobile. Closes DX-955 Preview: https://docs-v2-git-docs-router-page-medusajs.vercel.app/v2
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Admin Development Constraints`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
This chapter lists some constraints of admin widgets and UI routes.
|
||||
|
||||
## Arrow Functions
|
||||
|
||||
Widget and UI route components must be created as arrow functions.
|
||||
|
||||
export const arrowHighlights = [
|
||||
["2", "function", "Don't declare the widget / UI route as a function."],
|
||||
["7", "() => ", "Use arrow functions when creating a widget / UI route."]
|
||||
]
|
||||
|
||||
```ts highlights={arrowHighlights}
|
||||
// Don't
|
||||
function ProductWidget() {
|
||||
// ...
|
||||
}
|
||||
|
||||
// Do
|
||||
const ProductWidget = () => {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Widget Zone
|
||||
|
||||
A widget zone's value must be wrapped in double or single quotes. It can't be a template literal or a variable.
|
||||
|
||||
export const zoneHighlights = [
|
||||
["3", "`product.details.before`", "Don't specify the value of `zone` as a template literal."],
|
||||
["9", "ZONE", "Don't specify a variable as the value of `zone`."],
|
||||
["14", `"product.details.before"`, "Wrap the value of `zone` in double or single quotes."]
|
||||
]
|
||||
|
||||
```ts highlights={zoneHighlights}
|
||||
// Don't
|
||||
export const config = defineWidgetConfig({
|
||||
zone: `product.details.before`,
|
||||
})
|
||||
|
||||
// Don't
|
||||
const ZONE = "product.details.after"
|
||||
export const config = defineWidgetConfig({
|
||||
zone: ZONE,
|
||||
})
|
||||
|
||||
// Do
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.before",
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,26 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Admin Development`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In the next chapters, you'll learn more about possible admin customizations.
|
||||
|
||||
You can customize the admin dashboard by:
|
||||
|
||||
- Adding new sections to existing pages using Widgets.
|
||||
- Adding new pages using UI Routes.
|
||||
|
||||
---
|
||||
|
||||
## Medusa UI Package
|
||||
|
||||
Medusa provides a Medusa UI package to facilitate your admin development through ready-made components and ensure a consistent design between your customizations and the dashboard’s design.
|
||||
|
||||
Refer to the [Medusa UI documentation](https://docs.medusajs.com/ui) to learn how to install it and use its components.
|
||||
|
||||
---
|
||||
|
||||
## Admin Components List
|
||||
|
||||
To build admin customizations that match the Medusa Admin's designs and layouts, refer to [this guide](!resources!/admin-component) to find common components.
|
||||
@@ -0,0 +1,101 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Admin Development Tips`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll find some tips for your admin development.
|
||||
|
||||
## Send Requests to API Routes
|
||||
|
||||
To send a request to an API route in the Medusa Application, use the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch).
|
||||
|
||||
For example:
|
||||
|
||||
export const fetchHighlights = [
|
||||
["14", "fetch", "Send a request to the `/admin/products` API route."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={fetchHighlights}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-sdk"
|
||||
import { Container } from "@medusajs/ui"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
const ProductWidget = () => {
|
||||
const [productsCount, setProductsCount] = useState(0)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
return
|
||||
}
|
||||
|
||||
fetch(`/admin/products`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(({ count }) => {
|
||||
setProductsCount(count)
|
||||
setLoading(false)
|
||||
})
|
||||
}, [loading])
|
||||
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
{loading && <span>Loading...</span>}
|
||||
{!loading && <span>You have {productsCount} Product(s).</span>}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.list.before",
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
In this example, you send a request to the [List Products API route](!api!/admin#products_getproducts) and show the count of products in a widget.
|
||||
|
||||
---
|
||||
|
||||
## Routing Functionalities
|
||||
|
||||
To navigate or link to other pages, or perform other routing functionalities, use the [react-router-dom](https://reactrouter.com/en/main) package. It's installed in your project through the Medusa Admin.
|
||||
|
||||
For example:
|
||||
|
||||
export const highlights = [
|
||||
["9", "Link", "Add a link to another page"],
|
||||
["9", '"/orders', "Add the path without the `/app` prefix."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={highlights}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-sdk"
|
||||
import { Container } from "@medusajs/ui"
|
||||
import { Link } from "react-router-dom"
|
||||
|
||||
// The widget
|
||||
const ProductWidget = () => {
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<Link to={"/orders"}>View Orders</Link>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
// The widget's configurations
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.before",
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
This adds a widget in a product's details page with a link to the Orders page. The link's path must be without the `/app` prefix.
|
||||
|
||||
<Note title="Learn more">
|
||||
|
||||
Refer to [react-router-dom’s documentation](https://reactrouter.com/en/main) for other available components and hooks.
|
||||
|
||||
</Note>
|
||||
@@ -0,0 +1,168 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Admin UI Routes`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn how to create a UI route in the admin dashboard.
|
||||
|
||||
## What is a UI Route?
|
||||
|
||||
A UI route is a React Component that adds a new page to your admin dashboard. The UI Route can be shown in the sidebar or added as a nested page.
|
||||
|
||||
For example, you may add a new page to manage product reviews.
|
||||
|
||||
---
|
||||
|
||||
## How to Create a UI Route?
|
||||
|
||||
A UI route is created in a file named `page.tsx` under the `src/admin/routes` directory. The file’s default export must be the UI route’s React component.
|
||||
|
||||
For example, create the file `src/admin/routes/custom/page.tsx` with the following content:
|
||||
|
||||
```tsx title="src/admin/routes/custom/page.tsx"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
const CustomPage = () => {
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h2">This is my custom route</Heading>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
The new page’s path is the file’s path relative to `src/admin/routes`. So, the above UI route is a new page added at the path `localhost:9000/app/custom`.
|
||||
|
||||
<Note title="Important" type="warning">
|
||||
|
||||
The UI route component must be created as an arrow function.
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Test the UI Route
|
||||
|
||||
To test the UI route, start the Medusa application:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Then, after logging into the admin dashboard, open the page `localhost:9000/app/custom` to see your custom page.
|
||||
|
||||
---
|
||||
|
||||
## Show UI Route in the Sidebar
|
||||
|
||||
A UI route file can export a configuration object that indicates a new item must be added in the sidebar linking to the new UI route.
|
||||
|
||||
For example:
|
||||
|
||||
export const highlights = [
|
||||
["16", "label", "The label of the UI route's sidebar item."],
|
||||
["17", "icon", "The icon of the UI route's sidebar item."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/routes/custom/page.tsx" highlights={highlights}
|
||||
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||
import { ChatBubbleLeftRight } from "@medusajs/icons"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
const CustomPage = () => {
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h2">This is my custom route</Heading>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config = defineRouteConfig({
|
||||
label: "Custom Route",
|
||||
icon: ChatBubbleLeftRight,
|
||||
})
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
The configuration object is created using the `defineRouteConfig` function imported from `@medusajs/admin-sdk`. It accepts the following properties:
|
||||
|
||||
- `label`: the sidebar item’s label.
|
||||
- `icon`: an optional React component used as an icon in the sidebar.
|
||||
|
||||
The above example adds a new sidebar item with the label `Custom Route` and an icon from the [Medusa UI Icons package](!ui!/icons/overview).
|
||||
|
||||
---
|
||||
|
||||
## Create Settings Page
|
||||
|
||||
To create a page under the settings section of the admin dashboard, create the UI route file under the path `src/admin/routes/settings`.
|
||||
|
||||
For example:
|
||||
|
||||
```tsx title="src/admin/routes/settings/custom/page.tsx"
|
||||
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
const CustomSettingPage = () => {
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h1">Custom Setting Page</Heading>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config = defineRouteConfig({
|
||||
label: "Custom",
|
||||
})
|
||||
|
||||
export default CustomSettingPage
|
||||
```
|
||||
|
||||
This adds a page under the path `/app/settings/custom`. An item is also added to the settings sidebar with the label `Custom`.
|
||||
|
||||
---
|
||||
|
||||
## Path Parameters
|
||||
|
||||
A UI route can accept path parameters if the name of any of the directories in its path is of the format `[param]`.
|
||||
|
||||
For example, create the file `src/admin/routes/custom/[id]/page.tsx` with the following content:
|
||||
|
||||
```tsx title="src/admin/routes/custom/[id]/page.tsx" highlights={[["5", "", "Retrieve the path parameter."], ["10", "{id}", "Show the path parameter."]]}
|
||||
import { useParams } from "react-router-dom"
|
||||
import { Container } from "@medusajs/ui"
|
||||
|
||||
const CustomPage = () => {
|
||||
const { id } = useParams()
|
||||
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h1">Passed ID: {id}</Heading>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
You access the passed parameter using `react-router-dom`'s [useParams hook](https://reactrouter.com/en/main/hooks/use-params).
|
||||
|
||||
If you run the Medusa application and go to `localhost:9000/app/custom/123`, you'll see `123` printed in the page.
|
||||
|
||||
---
|
||||
|
||||
## Admin Components List
|
||||
|
||||
To build admin customizations that match the Medusa Admin's designs and layouts, refer to [this guide](!resources!/admin-component) to find common components.
|
||||
@@ -0,0 +1,130 @@
|
||||
import { Table } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Admin Widgets`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn more about widgets and how to use them.
|
||||
|
||||
## What is an Admin Widget?
|
||||
|
||||
Admin widgets are React components you inject into predetermined injection zones in the Medusa Admin dashboard.
|
||||
|
||||
For example, you can add a widget on the order details page that shows payment details retrieved from Stripe.
|
||||
|
||||
---
|
||||
|
||||
## How to Create a Widget?
|
||||
|
||||
A widget is created in a file under the `src/admin/widgets` directory. The file’s default export must be the widget, which is the React component. The file must also export the widget’s configurations.
|
||||
|
||||
For example, create the file `src/admin/widgets/product-widget.tsx` with the following content:
|
||||
|
||||
export const widgetHighlights = [
|
||||
["5", "ProductWidget", "The React component of the product widget."],
|
||||
["17", "zone", "The zone to inject the widget to."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={widgetHighlights}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-sdk"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
// The widget
|
||||
const ProductWidget = () => {
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h2">Product Widget</Heading>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
// The widget's configurations
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.before",
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
The widget only shows the heading `Product Widget`.
|
||||
|
||||
Use the `defineWidgetConfig` function imported from `@medusajs/admin-sdk` to create and export the widget's configurations. It accepts as a parameter an object with the following property:
|
||||
|
||||
- `zone`: A string or an array of strings, each being the name of the zone to inject the widget into.
|
||||
|
||||
In the example above, the widget is injected at the top of a product’s details.
|
||||
|
||||
<Note title="Important" type="warning">
|
||||
|
||||
The widget component must be created as an arrow function.
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Test the Widget
|
||||
|
||||
To test out the widget, start the Medusa application:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Then, open a product’s details page. You’ll find your custom widget at the top of the page.
|
||||
|
||||
---
|
||||
|
||||
## Detail Widget Props
|
||||
|
||||
Widgets that are injected into a details page (for example, `product.details.before`) receive a `data` prop, which is the main data of the details page (for example, the product object).
|
||||
|
||||
For example:
|
||||
|
||||
export const detailHighlights = [
|
||||
["10", "data", "Receive the data as a prop."],
|
||||
["11", "AdminProduct", "Pass the expected type of `data` as a type argument."],
|
||||
["16", "data.title", "Show the product's title."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={detailHighlights}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-sdk"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
import {
|
||||
DetailWidgetProps,
|
||||
AdminProduct,
|
||||
} from "@medusajs/framework/types"
|
||||
|
||||
// The widget
|
||||
const ProductWidget = ({
|
||||
data,
|
||||
}: DetailWidgetProps<AdminProduct>) => {
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h2">
|
||||
Product Widget {data.title}
|
||||
</Heading>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
// The widget's configurations
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.before",
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
Notice that the type of the props is `DetailWidgetProps`, which accepts as a type argument the expected type of `data`.
|
||||
|
||||
---
|
||||
|
||||
## Injection Zone
|
||||
|
||||
Refer to [this reference](!resources!/admin-widget-injection-zones) for the full list of injection zones and their props.
|
||||
Reference in New Issue
Block a user