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,10 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Customize Admin to Add Brands`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In the next chapters, you'll continue with the brands example to learn how to customize the Medusa Admin to:
|
||||
|
||||
- Show a product's brand on its details page using a widget.
|
||||
- Add a page showing the list of brands in your application using a UI route.
|
||||
@@ -0,0 +1,196 @@
|
||||
import { Prerequisites } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Create Brands List UI Route in Admin`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
<Note title="Example Chapter">
|
||||
|
||||
This chapter covers how to create a UI route (or page) that shows your brands as a step of the ["Customize Admin" chapter](../page.mdx).
|
||||
|
||||
</Note>
|
||||
|
||||
## 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.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisite: Add Retrieve Brand API Route
|
||||
|
||||
<Prerequisites
|
||||
items={[
|
||||
{
|
||||
text: "Brand Module",
|
||||
link: "/customization/custom-features/module"
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
Before adding the UI route, you need an API route that retrieves all brands.
|
||||
|
||||
Create the file `src/api/admin/brands/route.ts` with the following content:
|
||||
|
||||
```ts title="src/api/admin/brands/route.ts" collapsibleLines="1-7" expandMoreButton="Show Imports"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/framework/http"
|
||||
import { BRAND_MODULE } from "../../../modules/brand"
|
||||
import BrandModuleService from "../../../modules/brand/service"
|
||||
|
||||
export const GET = async (
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const brandModuleService: BrandModuleService = req.scope.resolve(
|
||||
BRAND_MODULE
|
||||
)
|
||||
|
||||
const limit = req.query.limit || 15
|
||||
const offset = req.query.offset || 0
|
||||
|
||||
const [brands, count] = await brandModuleService.listAndCountBrands({}, {
|
||||
skip: offset as number,
|
||||
take: limit as number,
|
||||
})
|
||||
|
||||
res.json({
|
||||
brands,
|
||||
count,
|
||||
limit,
|
||||
offset,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
This adds a `GET` API route at `/admin/brands`.
|
||||
|
||||
In the API route, you resolve the Brand Module's main service and use its `listAndCountBrands` method to retrieve the list of brands with their total count.
|
||||
|
||||
This method accepts as a first parameter filters to apply on the retrieved data, and as a second parameter configurations for pagination.
|
||||
|
||||
<Note>
|
||||
|
||||
Learn more about the `listAndCount` method and its parameters in [this reference](!resources!service-factory-reference/methods/listAndCount).
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Add a UI Route to Show Brands
|
||||
|
||||
A UI route is created in a file named `page.tsx` under subdirectories of the `src/admin/routes` directory. The file’s default export must be the UI route’s React component.
|
||||
|
||||
To create a UI route that shows the list of brands, create the file `src/admin/routes/brands/page.tsx` with the following content:
|
||||
|
||||
export const uiRouteHighlights = [
|
||||
["7", "brands", "State variable to store the brands."],
|
||||
["12", "fetch", "Retrieve the brands from the custom API route."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/routes/brands/page.tsx" highlights={uiRouteHighlights}
|
||||
import { Table, Container, Heading } from "@medusajs/ui"
|
||||
import { useEffect, useState } from "react"
|
||||
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||
import { TagSolid } from "@medusajs/icons"
|
||||
|
||||
const BrandsPage = () => {
|
||||
const [brands, setBrands] = useState<
|
||||
Record<string, string>[]
|
||||
>([])
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`/admin/brands`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(({ brands: brandsData }) => {
|
||||
setBrands(brandsData)
|
||||
})
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h2">Brands</Heading>
|
||||
</div>
|
||||
<div className="flex h-full flex-col overflow-hidden !border-t-0">
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>ID</Table.HeaderCell>
|
||||
<Table.HeaderCell>Name</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{brands.map((brand) => (
|
||||
<Table.Row key={brand.id}>
|
||||
<Table.Cell>{brand.id}</Table.Cell>
|
||||
<Table.Cell>{brand.name}</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default BrandsPage
|
||||
|
||||
// TODO export configuration
|
||||
```
|
||||
|
||||
This adds a new page in the admin at `http://localhost:9000/app/brands`.
|
||||
|
||||
In the UI route's component, you retrieve the brands from the `/admin/brands` API route. You show the brands in a table.
|
||||
|
||||
<Note>
|
||||
|
||||
Admin customizations can use the [Medusa UI package](!ui!) to align your customizations with the admin's design. Also, [this guide](!resources!/admin-components) includes examples of common components in the Medusa Admin.
|
||||
|
||||
</Note>
|
||||
|
||||
### Add UI Route to the Sidebar
|
||||
|
||||
To add the UI route to the sidebar, replace the `TODO` at the end of the file with the following:
|
||||
|
||||
```ts title="src/admin/routes/brands/page.tsx"
|
||||
export const config = defineRouteConfig({
|
||||
label: "Brands",
|
||||
icon: TagSolid,
|
||||
})
|
||||
```
|
||||
|
||||
You export a `config` variable defined using the `defineRouteConfig` utility.
|
||||
|
||||
This indicates that a new item should be added to the sidebar with the title `Brands` and an icon from the [Medusa Icons package](!ui!/icons/overview).
|
||||
|
||||
---
|
||||
|
||||
## Test it Out
|
||||
|
||||
To test it out, start the Medusa application and login into the Medusa Admin.
|
||||
|
||||
You'll find a new "Brands" sidebar item. If you click on it, a new page opens showing the list of brands in your store.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
By following the examples of the previous chapters, you:
|
||||
|
||||
- Created a widget that showed the brand of a product in the Medusa Admin.
|
||||
- Created a UI route that showed the list of brands in the Medusa Admin.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
In the next chapters, you'll learn how to integrate third-party systems into your Medusa application to sync brands.
|
||||
@@ -0,0 +1,110 @@
|
||||
import { Prerequisites } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Show Brand of Product in Admin`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
<Note title="Example Chapter">
|
||||
|
||||
This chapter covers how to show the brand of a product in the Medusa Admin using a widget as a step of the ["Customize Admin" chapter](../page.mdx).
|
||||
|
||||
</Note>
|
||||
|
||||
## Widget to Show Brand in Product Details
|
||||
|
||||
<Prerequisites
|
||||
items={[
|
||||
{
|
||||
text: "Retrieve Brand of Product API Route",
|
||||
link: "/customization/extend-models/query-linked-records"
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
To create a widget that shows a product's brand in its details page, create the file `src/admin/widgets/product-brand.tsx` with the following content:
|
||||
|
||||
export const highlights = [
|
||||
["7", "data", "Receive the product's details as a prop"],
|
||||
["9", "brand", "A state variable to store the brand"],
|
||||
["19", "fetch", "Retrieve the brand of a product using the custom API route"],
|
||||
["41", "zone", "Show the widget at the top of the product details page."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/widgets/product-brand.tsx" highlights={highlights}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-sdk"
|
||||
import { DetailWidgetProps, AdminProduct } from "@medusajs/framework/types"
|
||||
import { useEffect, useState } from "react"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
const ProductBrandWidget = ({
|
||||
data,
|
||||
}: DetailWidgetProps<AdminProduct>) => {
|
||||
const [brand, setBrand] = useState<
|
||||
Record<string, string> | undefined
|
||||
>()
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
return
|
||||
}
|
||||
|
||||
fetch(`/admin/products/${data.id}/brand`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(({ brand }) => {
|
||||
setBrand(brand)
|
||||
setLoading(false)
|
||||
})
|
||||
}, [loading])
|
||||
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h2">Brand</Heading>
|
||||
</div>
|
||||
{loading && <span>Loading...</span>}
|
||||
{brand && <span>Name: {brand.name}</span>}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.before",
|
||||
})
|
||||
|
||||
export default ProductBrandWidget
|
||||
```
|
||||
|
||||
This adds a widget at the top of the product's details page.
|
||||
|
||||
<Note>
|
||||
|
||||
Learn more about widgets [in this guide](../../../basics/admin-customizations/page.mdx).
|
||||
|
||||
</Note>
|
||||
|
||||
Widgets created in a details page receive the targetted item in a `data` prop. So, the `ProductBrandWidget` receives the product's details in the `data` prop.
|
||||
|
||||
In the widget, you fetch the product's brand from the `/admin/products/:id/brand` API route and display it.
|
||||
|
||||
<Note>
|
||||
|
||||
Admin customizations can use the [Medusa UI package](!ui!) to align your customizations with the admin's design. Also, [this guide](!resources!/admin-components) includes examples of common components in the Medusa Admin.
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Test it Out
|
||||
|
||||
Start your Medusa application and go to a product's details page in the Medusa Admin, you'll find a new block at the top of the page showing the product's brand.
|
||||
|
||||
---
|
||||
|
||||
## Next Chapter: Add List of Brands Page
|
||||
|
||||
In the next chapter, you'll add a new page or UI route that displays the list of brands in your application.
|
||||
Reference in New Issue
Block a user