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:
Shahed Nasser
2024-10-18 08:24:34 +00:00
committed by GitHub
parent 7a47f5211d
commit 0a37675f0e
223 changed files with 2549 additions and 696 deletions
@@ -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 files default export must be the UI routes 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.