docs: revise admin customization pages (#10466)
* docs: revise admin customization pages * fix prerequisites link * apply lint
This commit is contained in:
1 parent
0a077d48e1
commit
21b0e0c26b
9 files changed
+549
-175
No files matched your search
@@ -1,64 +1,132 @@
|
||||
import { Prerequisites } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Show Brand of Product in Admin`,
|
||||
title: `${pageNumber} Guide: Add Product's Brand Widget in Admin`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
<Note title="Example Chapter">
|
||||
In this chapter, you'll customize the product details page of the Medusa Admin dashboard to show the product's [brand](../../custom-features/module/page.mdx). You'll create a widget that is injected into a pre-defined zone in the page, and in the widget you'll retrieve the product's brand from the server and display it.
|
||||
|
||||
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).
|
||||
<Prerequisites
|
||||
items={[
|
||||
{
|
||||
text: "Brands linked to products",
|
||||
link: "/learn/customization/extend-features/define-link"
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
## 1. Initialize JS SDK
|
||||
|
||||
In your custom widget, you'll retrieve the product's brand by sending a request to the Medusa server. Medusa has a [JS SDK](!resources!/js-sdk) that simplifies sending requests to the server's API routes.
|
||||
|
||||
So, you'll start by configuring the JS SDK. Create the file `src/admin/lib/sdk.ts` with the following content:
|
||||
|
||||

|
||||
|
||||
```ts title="src/admin/lib/sdk.ts"
|
||||
import Medusa from "@medusajs/js-sdk"
|
||||
|
||||
export const sdk = new Medusa({
|
||||
baseUrl: "http://localhost:9000",
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
auth: {
|
||||
type: "session",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
You initialize the SDK passing it the following options:
|
||||
|
||||
- `baseUrl`: The URL to the Medusa server.
|
||||
- `debug`: Whether to enable logging debug messages. This should only be enabled in development.
|
||||
- `auth.type`: The authentication method used in the client application, which is `session` in the Medusa Admin dashboard.
|
||||
|
||||
You can now use the SDK to send requests to the Medusa server.
|
||||
|
||||
<Note>
|
||||
|
||||
Learn more about the JS SDK and its options in [this reference](!resources!/js-sdk).
|
||||
|
||||
</Note>
|
||||
|
||||
## Widget to Show Brand in Product Details
|
||||
---
|
||||
|
||||
## 2. Add Widget to Product Details Page
|
||||
|
||||
You'll now add a widget to the product-details page. A widget is a React component that's injected into pre-defined zones in the Medusa Admin dashboard. It's created in a `.tsx` file under the `src/admin/widgets` directory.
|
||||
|
||||
<Note>
|
||||
|
||||
Learn more about widgets in [this documentation](../../../advanced-development/admin/widgets/page.mdx).
|
||||
|
||||
</Note>
|
||||
|
||||
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."]
|
||||
["14", "ProductBrandWidget", "Widget to inject into the page"],
|
||||
["15", "data", "Receive the product's details as a prop"],
|
||||
["17", "useQuery", "Use Tanstack Query to send the request to the server with the JS SDK."],
|
||||
["18", "sdk", "Send the request to retrieve the product with the JS SDK."],
|
||||
["19", "fields", "Specify the product's brand to be retrieved."],
|
||||
["23", "brandName", "Get brand name from the query request."],
|
||||
["53", "defineWidgetConfig", "Export the widget's configurations"],
|
||||
["54", "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"
|
||||
import { clx, Container, Heading, Text } from "@medusajs/ui"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { sdk } from "../lib/sdk"
|
||||
|
||||
type AdminProductBrand = AdminProduct & {
|
||||
brand?: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
const ProductBrandWidget = ({
|
||||
data,
|
||||
data: product,
|
||||
}: DetailWidgetProps<AdminProduct>) => {
|
||||
const [brand, setBrand] = useState<
|
||||
Record<string, string> | undefined
|
||||
>()
|
||||
const [loading, setLoading] = useState(true)
|
||||
const { data: queryResult } = useQuery({
|
||||
queryFn: () => sdk.admin.product.retrieve(product.id, {
|
||||
fields: "+brand.*",
|
||||
}),
|
||||
queryKey: [["product", product.id]],
|
||||
})
|
||||
const brandName = (queryResult?.product as AdminProductBrand)?.brand?.name
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
return
|
||||
}
|
||||
|
||||
fetch(`/admin/products/${data.id}?fields=+brand.*`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(({ product }) => {
|
||||
setBrand(product.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>
|
||||
<Heading level="h2">Brand</Heading>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={clx(
|
||||
`text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4`
|
||||
)}
|
||||
>
|
||||
<Text size="small" weight="plus" leading="compact">
|
||||
Name
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
size="small"
|
||||
leading="compact"
|
||||
className="whitespace-pre-line text-pretty"
|
||||
>
|
||||
{brandName || "-"}
|
||||
</Text>
|
||||
</div>
|
||||
{loading && <span>Loading...</span>}
|
||||
{brand && <span>Name: {brand.name}</span>}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -70,32 +138,41 @@ export const config = defineWidgetConfig({
|
||||
export default ProductBrandWidget
|
||||
```
|
||||
|
||||
This adds a widget at the top of the product's details page.
|
||||
A widget's file must export:
|
||||
|
||||
<Note>
|
||||
- A React component to be rendered in the specified injection zone. The component must be the file's default export.
|
||||
- A configuration object created with `defineWidgetConfig` from the Admin Extension SDK. The function receives an object as a parameter that has a `zone` property, whose value is the zone to inject the widget to.
|
||||
|
||||
Learn more about widgets [in this guide](../../../basics/admin-customizations/page.mdx).
|
||||
Since the widget is injected at the top of the product details page, the widget receives the product's details as a parameter.
|
||||
|
||||
</Note>
|
||||
In the widget, you use [Tanstack (React) Query](https://tanstack.com/query/latest) to query the Medusa server. Tanstack Query provides features like asynchronous state management and optimized caching. In the `queryFn` function that executes the query, you use the JS SDK to send a request to the [Get Product API Route](!api!/admin#products_getproductsid), passing `+brand.*` in the `fields` query parameter to retrieve the product's brand.
|
||||
|
||||
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 using the [Get Product API route](!api!/admin#products_getproductsid), passing it the query parameter `fields=+brand.*` to retrieve the product's brand.
|
||||
|
||||
<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>
|
||||
You then render a section that shows the brand's name. In admin customizations, use components from the [Medusa UI package](!ui!) to maintain a consistent user interface and design in the dashboard.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
To test out your widget, start the Medusa application:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Then, open the admin dashboard at `http://localhost:9000/app`. After you log in, open the page of a product that has a brand. You'll see a new section at the top showing the brand's name.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Next Chapter: Add List of Brands Page
|
||||
## Admin Components Guides
|
||||
|
||||
In the next chapter, you'll add a new page or UI route that displays the list of brands in your application.
|
||||
When building your widget, you may need more complicated components. For example, you may add a form to the above widget to set the product's brand.
|
||||
|
||||
The [Admin Components guides](!resources!/admin-components) show you how to build and use common components in the Medusa Admin, such as forms, tables, JSON data viewer, and more. The components in the guides also follow the Medusa Admin's design convention.
|
||||
|
||||
---
|
||||
|
||||
## Next Chapter: Add UI Route for Brands
|
||||
|
||||
In the next chapter, you'll add a UI route that displays the list of brands in your application and allows admin users.
|
||||
Reference in new issue
Block a user