docs: prepare configuration (#7877)

* update configuration

* resolve todos + remove events guides

* disable v2 docs in v1 navbar

* remove v2 from v1 mobile sidebar

* resolve build errors

* fix build errors

* fix lint errors

* fix lint
This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-07-03 19:27:13 +03:00
1 parent 012a624ee4
commit 6713d76db3
57 files changed
+678 -958

No files matched your search

@@ -41,6 +41,7 @@ const Navbar = () => {
}} }}
additionalActionsBefore={<VersionSwitcher />} additionalActionsBefore={<VersionSwitcher />}
additionalActionsAfter={<FeedbackModal />} additionalActionsAfter={<FeedbackModal />}
showSearchOpener
isLoading={isLoading} isLoading={isLoading}
/> />
) )
+1
View File
@@ -12,6 +12,7 @@ const nextConfig = {
destination: `${ destination: `${
process.env.NEXT_PUBLIC_DOCS_URL || "https://localhost:3001" process.env.NEXT_PUBLIC_DOCS_URL || "https://localhost:3001"
}/:path*`, }/:path*`,
basePath: false,
}, },
], ],
} }
@@ -53,7 +53,7 @@ import { model } from "@medusajs/utils"
const MyCustom = model.define("my_custom", { const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(), id: model.id().primaryKey(),
name: model.text(), name: model.text(),
age: model.number() age: model.number(),
}).indexes([ }).indexes([
{ {
on: ["name", "age"], on: ["name", "age"],
@@ -82,13 +82,13 @@ import { model } from "@medusajs/utils"
const MyCustom = model.define("my_custom", { const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(), id: model.id().primaryKey(),
name: model.text(), name: model.text(),
age: model.number() age: model.number(),
}).indexes([ }).indexes([
{ {
on: ["name", "age"], on: ["name", "age"],
where: { where: {
age: 30 age: 30,
} },
}, },
]) ])
@@ -111,15 +111,15 @@ import { model } from "@medusajs/utils"
const MyCustom = model.define("my_custom", { const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(), id: model.id().primaryKey(),
name: model.text(), name: model.text(),
age: model.number().nullable() age: model.number().nullable(),
}).indexes([ }).indexes([
{ {
on: ["name", "age"], on: ["name", "age"],
where: { where: {
age: { age: {
$ne: null $ne: null,
} },
} },
}, },
]) ])
@@ -146,11 +146,11 @@ import { model } from "@medusajs/utils"
const MyCustom = model.define("my_custom", { const MyCustom = model.define("my_custom", {
id: model.id().primaryKey(), id: model.id().primaryKey(),
name: model.text(), name: model.text(),
age: model.number() age: model.number(),
}).indexes([ }).indexes([
{ {
on: ["name", "age"], on: ["name", "age"],
unique: true unique: true,
}, },
]) ])
@@ -41,25 +41,6 @@ A subscriber file must export:
The above subscriber listens to the `product.created` event. Whenever the event is emitted, it logs in the terminal `A product is created`. The above subscriber listens to the `product.created` event. Whenever the event is emitted, it logs in the terminal `A product is created`.
{/* TODO add when we have the admin dashboard to use with V2 for easy testing. */}
{/\* ### Test Subscriber
To test the subscriber, start the Medusa application:
```bash npm2yarn
npm run dev
```
Then, create a product using the Medusa Admin dashboard. Afterward, you’ll see the following messages logged in the terminal:
```bash
info: Processing product.created which has 1 subscribers
A product is created
```
The first message indicates that the `product.created` event was emitted, and the second one is the message logged from the subscriber. \*/}
--- ---
## When to Use Subscribers ## When to Use Subscribers
@@ -31,6 +31,7 @@ const Navbar = () => {
mobileSidebarOpen, mobileSidebarOpen,
}} }}
isLoading={false} isLoading={false}
showSearchOpener
/> />
) )
} }
+8 -1
View File
@@ -108,6 +108,13 @@ const nextConfig = {
}/v2/resources/:path*`, }/v2/resources/:path*`,
basePath: false, basePath: false,
}, },
{
source: "/v2/api/:path*",
destination: `${
process.env.NEXT_PUBLIC_API_URL || "https://localhost:3001"
}/v2/api/:path*`,
basePath: false,
},
// TODO comment out once we have the user guide published // TODO comment out once we have the user guide published
// { // {
// source: "/user-guide", // source: "/user-guide",
@@ -122,7 +129,7 @@ const nextConfig = {
{ {
source: "/:path*", source: "/:path*",
destination: `${ destination: `${
process.env.NEXT_PUBLIC_DOCS_V1_URL || "https://localhost:3000" process.env.NEXT_PUBLIC_API_V1_URL || "https://localhost:3001"
}/:path*`, }/:path*`,
basePath: false, basePath: false,
}, },
@@ -91,6 +91,4 @@ The `create` method accepts an object or an array of objects having the followin
sectionTitle="Use the Create Method" sectionTitle="Use the Create Method"
/> />
{/* TODO add once reference for type once generated */} For a full list of properties accepted, refer to [this guide](/references/notification-provider-module#create).
{/* For a full list of properties accepted, refer to [this guide](/references/notification-provider-module#create). */}
+115 -130
View File
@@ -36,8 +36,7 @@ You can create a sales channel through the Medusa Admin or Admin REST APIs.
{/* TODO add links */} {/* TODO add links */}
<CardList <CardList items={[
items={[
{ {
href: "#", href: "#",
title: "Option 1: Use Medusa Admin", title: "Option 1: Use Medusa Admin",
@@ -46,18 +45,17 @@ You can create a sales channel through the Medusa Admin or Admin REST APIs.
showLinkIcon: false, showLinkIcon: false,
badge: { badge: {
variant: "blue", variant: "blue",
children: "Guide Soon", children: "Guide Soon"
}, }
}, },
{ {
href: "!api!/api/admin#sales-channels_postsaleschannels", href: "!api!/api/admin#sales-channels_postsaleschannels",
title: "Option 2: Using the REST APIs", title: "Option 2: Using the REST APIs",
text: "Create the sales channel using the REST APIs.", text: "Create the sales channel using the REST APIs.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
--- ---
@@ -76,8 +74,7 @@ You can create a publishable API key through the Medusa Admin or the Admin REST
### Create Key ### Create Key
<CardList <CardList items={[
items={[
{ {
href: "#", href: "#",
title: "Option 1: Use Medusa Admin", title: "Option 1: Use Medusa Admin",
@@ -86,25 +83,23 @@ You can create a publishable API key through the Medusa Admin or the Admin REST
showLinkIcon: false, showLinkIcon: false,
badge: { badge: {
variant: "blue", variant: "blue",
children: "Guide Soon", children: "Guide Soon"
}, }
}, },
{ {
href: "!api!/api/admin#api-keys_postapikeys", href: "!api!/api/admin#api-keys_postapikeys",
title: "Option 2: Using the REST APIs", title: "Option 2: Using the REST APIs",
text: "Create the publishable API key using the REST APIs.", text: "Create the publishable API key using the REST APIs.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
### Associate Key with Sales Channel ### Associate Key with Sales Channel
{/* TODO add links */} {/* TODO add links */}
<CardList <CardList items={[
items={[
{ {
href: "#", href: "#",
title: "Option 1: Use Medusa Admin", title: "Option 1: Use Medusa Admin",
@@ -113,18 +108,17 @@ You can create a publishable API key through the Medusa Admin or the Admin REST
showLinkIcon: false, showLinkIcon: false,
badge: { badge: {
variant: "blue", variant: "blue",
children: "Guide Soon", children: "Guide Soon"
}, }
}, },
{ {
href: "#", href: "#",
title: "Option 2: Using the REST APIs", title: "Option 2: Using the REST APIs",
text: "Associate the publishable API key with the B2B sales channel using the REST APIs.", text: "Associate the publishable API key with the B2B sales channel using the REST APIs.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
--- ---
@@ -136,8 +130,7 @@ You can create new products or add existing ones to the B2B sales channel using
{/* TODO add links */} {/* TODO add links */}
<CardList <CardList items={[
items={[
{ {
href: "#", href: "#",
title: "Using Medusa Admin", title: "Using Medusa Admin",
@@ -146,25 +139,23 @@ You can create new products or add existing ones to the B2B sales channel using
showLinkIcon: false, showLinkIcon: false,
badge: { badge: {
variant: "blue", variant: "blue",
children: "Guide Soon", children: "Guide Soon"
}, }
}, },
{ {
href: "!api!/api/admin#products_postproducts", href: "!api!/api/admin#products_postproducts",
title: "Using REST APIs", title: "Using REST APIs",
text: "Create products using the REST APIs.", text: "Create products using the REST APIs.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
### Add Products to Sales Channel ### Add Products to Sales Channel
{/* TODO add links */} {/* TODO add links */}
<CardList <CardList items={[
items={[
{ {
href: "#", href: "#",
title: "Using Medusa Admin", title: "Using Medusa Admin",
@@ -173,18 +164,17 @@ You can create new products or add existing ones to the B2B sales channel using
showLinkIcon: false, showLinkIcon: false,
badge: { badge: {
variant: "blue", variant: "blue",
children: "Guide Soon", children: "Guide Soon"
}, }
}, },
{ {
href: "!api!/api/admin#sales-channels_postsaleschannelsidproductsbatchadd", href: "!api!/api/admin#sales-channels_postsaleschannelsidproductsbatchadd",
title: "Using REST APIs", title: "Using REST APIs",
text: "Add the products to the B2B sales channel using the REST APIs.", text: "Add the products to the B2B sales channel using the REST APIs.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
--- ---
@@ -202,35 +192,33 @@ Module Relationships is coming soon.
</Note> </Note>
<CardList <CardList items={[
items={[
{ {
href: "!docs!/basics/modules-and-services", href: "!docs!/basics/modules-and-services",
title: "Create Module", title: "Create Module",
text: "Learn how to create a module in Medusa.", text: "Learn how to create a module in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/basics/data-models", href: "!docs!/basics/data-models",
title: "Create Data Models", title: "Create Data Models",
text: "Learn how to create data models.", text: "Learn how to create data models.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
{/_ <Card {/* <Card
href="!docs!/advanced-development/modules/module-relationships" href="!docs!/advanced-development/modules/module-relationships"
title="Create Module Relationships" title="Create Module Relationships"
text="Learn how to create a relationship between modules." text="Learn how to create a relationship between modules."
startIcon={<AcademicCapSolid />} startIcon={<AcademicCapSolid />}
showLinkIcon={false} showLinkIcon={false}
className="mt-1" className="mt-1"
/> _/} /> */}
{/\* <Details summaryContent="Example"> {/* <Details summaryContent="Example">
In this section, you'll create a B2B module that has a `Company` data model. The `Company` data model has a relationship to the `CustomerGroup` data model of the Customer Module. In this section, you'll create a B2B module that has a `Company` data model. The `Company` data model has a relationship to the `CustomerGroup` data model of the Customer Module.
Start by creating the `src/modules/b2b` directory. Start by creating the `src/modules/b2b` directory.
@@ -259,14 +247,13 @@ Next, create the migration in the file `src/modules/b2b/migrations/Migration2024
import { Migration } from "@mikro-orm/migrations" import { Migration } from "@mikro-orm/migrations"
export class Migration20240516081502 extends Migration { export class Migration20240516081502 extends Migration {
async up(): Promise<void> { async up(): Promise<void> {
this.addSql( this.addSql("create table if not exists \"company\" (\"id\" text not null, \"name\" text not null, \"city\" text not null, \"country_code\" text not null, \"customer_group_id\" text not null, constraint \"company_pkey\" primary key (\"id\"));")
'create table if not exists "company" ("id" text not null, "name" text not null, "city" text not null, "country_code" text not null, "customer_group_id" text not null, constraint "company_pkey" primary key ("id"));'
)
} }
async down(): Promise<void> { async down(): Promise<void> {
this.addSql('drop table if exists "company" cascade;') this.addSql("drop table if exists \"company\" cascade;")
} }
} }
``` ```
@@ -294,10 +281,11 @@ Next, create the module definition at `src/modules/b2b/index.ts` with the follow
```ts title="src/modules/b2b/index.ts" ```ts title="src/modules/b2b/index.ts"
import B2bModuleService from "./service" import B2bModuleService from "./service"
import { Module } from "@medusajs/utils"
export default { export default Module("b2b", {
service: B2bModuleService, service: B2bModuleService,
} })
``` ```
Finally, add the module to the `modules` object in `medusa-config.js`: Finally, add the module to the `modules` object in `medusa-config.js`:
@@ -346,26 +334,15 @@ export type CreateCompanyDTO = {
country_code: string country_code: string
customer_group_id?: string customer_group_id?: string
} }
``` ```
Then, create the file `src/workflows/create-company.ts` with the following content: Then, create the file `src/workflows/create-company.ts` with the following content:
export const workflowHighlights = [ export const workflowHighlights = [
[ ["23", "tryToCreateCustomerGroupStep", "This step creates the customer group if its data is passed in the `customer_group` property."],
"23", ["36", "createCustomerGroupsWorkflow", "Use the `createCustomerGroupsWorkflow` defined by Medusa to create the customer group."],
"tryToCreateCustomerGroupStep", ["44", "", "Set the ID of the new customer group in the `customer_group_id` property so that it's added to the created company."],
"This step creates the customer group if its data is passed in the `customer_group` property.",
],
[
"36",
"createCustomerGroupsWorkflow",
"Use the `createCustomerGroupsWorkflow` defined by Medusa to create the customer group.",
],
[
"44",
"",
"Set the ID of the new customer group in the `customer_group_id` property so that it's added to the created company.",
],
["54", "createCompanyStep", "This step creates the company."], ["54", "createCompanyStep", "This step creates the company."],
] ]
@@ -375,7 +352,9 @@ import {
createStep, createStep,
createWorkflow, createWorkflow,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { createCustomerGroupsWorkflow } from "@medusajs/core-flows" import {
createCustomerGroupsWorkflow,
} from "@medusajs/core-flows"
import { CreateCustomerGroupDTO } from "@medusajs/types" import { CreateCustomerGroupDTO } from "@medusajs/types"
import { CompanyDTO, CreateCompanyDTO } from "../types/b2b" import { CompanyDTO, CreateCompanyDTO } from "../types/b2b"
import B2bModuleService from "../modules/b2b/service" import B2bModuleService from "../modules/b2b/service"
@@ -393,15 +372,19 @@ type CreateCustomerGroupStepInput = CreateCompanyWorkflowInput
const tryToCreateCustomerGroupStep = createStep( const tryToCreateCustomerGroupStep = createStep(
"try-to-create-customer-group-step", "try-to-create-customer-group-step",
async ( async (
{ customer_group, ...company }: CreateCustomerGroupStepInput, {
{ container } customer_group,
) => { ...company
}: CreateCustomerGroupStepInput,
{ container }) => {
if (!customer_group) { if (!customer_group) {
return new StepResponse({ company }) return new StepResponse({ company })
} }
// create customer group // create customer group
const { result } = await createCustomerGroupsWorkflow(container).run({ const { result } = await createCustomerGroupsWorkflow(
container
).run({
input: { input: {
customersData: [customer_group], customersData: [customer_group],
}, },
@@ -419,11 +402,17 @@ export type CreateCompanyStep = {
const createCompanyStep = createStep( const createCompanyStep = createStep(
"create-company-step", "create-company-step",
async ({ companyData }: CreateCompanyStep, { container }) => { async (
const b2bModuleService: B2bModuleService = { companyData }: CreateCompanyStep,
container.resolve("b2bModuleService") { container }) => {
const b2bModuleService: B2bModuleService = container
.resolve(
"b2bModuleService"
)
const company = await b2bModuleService.createCompany(companyData) const company = await b2bModuleService.createCompany(
companyData
)
return new StepResponse({ company }) return new StepResponse({ company })
} }
@@ -432,13 +421,18 @@ const createCompanyStep = createStep(
export const createCompanyWorkflow = createWorkflow< export const createCompanyWorkflow = createWorkflow<
CreateCompanyWorkflowInput, CreateCompanyWorkflowInput,
CreateCompanyWorkflowOutput CreateCompanyWorkflowOutput
>("create-company", function (input) { >(
const { company: companyData } = tryToCreateCustomerGroupStep(input) "create-company",
function (input) {
const {
company: companyData,
} = tryToCreateCustomerGroupStep(input)
const company = createCompanyStep({ companyData }) const company = createCompanyStep({ companyData })
return company return company
}) }
)
``` ```
You create a workflow with two steps: You create a workflow with two steps:
@@ -449,7 +443,10 @@ You create a workflow with two steps:
Finally, create the file `src/api/admin/b2b/company/route.ts` with the following content: Finally, create the file `src/api/admin/b2b/company/route.ts` with the following content:
```ts title="src/api/admin/b2b/company/route.ts" collapsibleLines="1-9" expandButtonLabel="Show Imports" ```ts title="src/api/admin/b2b/company/route.ts" collapsibleLines="1-9" expandButtonLabel="Show Imports"
import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa" import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { import {
CreateCompanyWorkflowInput, CreateCompanyWorkflowInput,
createCompanyWorkflow, createCompanyWorkflow,
@@ -461,7 +458,8 @@ export async function POST(
req: MedusaRequest<CreateCompanyReq>, req: MedusaRequest<CreateCompanyReq>,
res: MedusaResponse res: MedusaResponse
) { ) {
const { result } = await createCompanyWorkflow(req.scope).run({ const { result } = await createCompanyWorkflow(req.scope)
.run({
input: req.body, input: req.body,
}) })
@@ -519,8 +517,7 @@ You can do that through the Medusa Admin or Admin REST APIs.
{/* TODO add links */} {/* TODO add links */}
<CardList <CardList items={[
items={[
{ {
href: "#", href: "#",
title: "Option 1: Use Medusa Admin", title: "Option 1: Use Medusa Admin",
@@ -529,25 +526,23 @@ You can do that through the Medusa Admin or Admin REST APIs.
showLinkIcon: false, showLinkIcon: false,
badge: { badge: {
variant: "blue", variant: "blue",
children: "Guide Soon", children: "Guide Soon"
}, }
}, },
{ {
href: "!api!/api/admin#customers_postcustomers", href: "!api!/api/admin#customers_postcustomers",
title: "Option 2: Using the REST APIs", title: "Option 2: Using the REST APIs",
text: "Create the customers using the REST APIs.", text: "Create the customers using the REST APIs.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
### Assign Customers to Groups ### Assign Customers to Groups
{/* TODO add links */} {/* TODO add links */}
<CardList <CardList items={[
items={[
{ {
href: "#", href: "#",
title: "Option 1: Use Medusa Admin", title: "Option 1: Use Medusa Admin",
@@ -556,18 +551,17 @@ You can do that through the Medusa Admin or Admin REST APIs.
showLinkIcon: false, showLinkIcon: false,
badge: { badge: {
variant: "blue", variant: "blue",
children: "Guide Soon", children: "Guide Soon"
}, }
}, },
{ {
href: "!api!/api/admin#customer-groups_postcustomergroupsidcustomersbatch", href: "!api!/api/admin#customer-groups_postcustomergroupsidcustomersbatch",
title: "Option 2: Using the REST APIs", title: "Option 2: Using the REST APIs",
text: "Assign the customers to the B2B customer group using the REST APIs.", text: "Assign the customers to the B2B customer group using the REST APIs.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
--- ---
@@ -579,8 +573,7 @@ You can create a price list using the Medusa Admin or the Admin REST APIs. Make
{/* TODO add links */} {/* TODO add links */}
<CardList <CardList items={[
items={[
{ {
href: "#", href: "#",
title: "Using Medusa Admin", title: "Using Medusa Admin",
@@ -589,18 +582,17 @@ You can create a price list using the Medusa Admin or the Admin REST APIs. Make
showLinkIcon: false, showLinkIcon: false,
badge: { badge: {
variant: "blue", variant: "blue",
children: "Guide Soon", children: "Guide Soon"
}, }
}, },
{ {
href: "!api!/api/admin#price-lists_postpricelists", href: "!api!/api/admin#price-lists_postpricelists",
title: "Using REST APIs", title: "Using REST APIs",
text: "Create the price list using the REST APIs.", text: "Create the price list using the REST APIs.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
--- ---
@@ -634,22 +626,14 @@ The API route can check if the customer has any group with an associated company
showLinkIcon={false} showLinkIcon={false}
/> />
{/\* <Details summaryContent="Example"> {/* <Details summaryContent="Example">
For example, create the API route `src/api/store/b2b/check-customer/route.ts` with the following content: For example, create the API route `src/api/store/b2b/check-customer/route.ts` with the following content:
export const checkCustomerHighlights = [ export const checkCustomerHighlights = [
["19", "retrieveCustomer", "Retrieve the customer along with its groups."], ["19", "retrieveCustomer", "Retrieve the customer along with its groups."],
[ ["26", "listCompanies", "List the companies that have a customer group ID matching any of the customer's group IDs."],
"26", ["31", "", "Return whether there are any companies associated with the customer's groups."]
"listCompanies",
"List the companies that have a customer group ID matching any of the customer's group IDs.",
],
[
"31",
"",
"Return whether there are any companies associated with the customer's groups.",
],
] ]
```ts title="src/api/store/b2b/check-customer/route.ts" highlights={checkCustomerHighlights} collapsibleLines="1-5" expandButtonLabel="Show Imports" ```ts title="src/api/store/b2b/check-customer/route.ts" highlights={checkCustomerHighlights} collapsibleLines="1-5" expandButtonLabel="Show Imports"
@@ -665,11 +649,11 @@ export async function GET(
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
res: MedusaResponse res: MedusaResponse
) { ) {
const customerModuleService: ICustomerModuleService = req.scope.resolve( const customerModuleService: ICustomerModuleService = req
ModuleRegistrationName.CUSTOMER .scope.resolve(ModuleRegistrationName.CUSTOMER)
const b2bModuleService: B2bModuleService = req.scope.resolve(
"b2bModuleService"
) )
const b2bModuleService: B2bModuleService =
req.scope.resolve("b2bModuleService")
const customer = await customerModuleService.retrieveCustomer( const customer = await customerModuleService.retrieveCustomer(
req.auth_context.actor_id, req.auth_context.actor_id,
@@ -697,13 +681,18 @@ This creates a `GET` API Route at `/store/b2b/check-customer` that:
Before using the API route, create the file `src/api/middlewares.ts` with the following content: Before using the API route, create the file `src/api/middlewares.ts` with the following content:
```ts title="src/api/middlewares.ts" ```ts title="src/api/middlewares.ts"
import { MiddlewaresConfig, authenticate } from "@medusajs/medusa" import {
MiddlewaresConfig,
authenticate,
} from "@medusajs/medusa"
export const config: MiddlewaresConfig = { export const config: MiddlewaresConfig = {
routes: [ routes: [
{ {
matcher: "/store/b2b*", matcher: "/store/b2b*",
middlewares: [authenticate("store", ["bearer", "session"])], middlewares: [
authenticate("store", ["bearer", "session"]),
],
}, },
], ],
} }
@@ -765,31 +754,29 @@ Based on your use case, you may need to customize the Medusa Admin to add new wi
The Medusa Admin plugin can be extended to add widgets, new pages, and setting pages. The Medusa Admin plugin can be extended to add widgets, new pages, and setting pages.
<CardList <CardList items={[
items={[
{ {
href: "!docs!/advanced-development/admin/widgets", href: "!docs!/advanced-development/admin/widgets",
title: "Create Admin Widget", title: "Create Admin Widget",
text: "Learn how to add widgets into existing admin pages.", text: "Learn how to add widgets into existing admin pages.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/advanced-development/admin/ui-routes", href: "!docs!/advanced-development/admin/ui-routes",
title: "Create Admin UI Routes", title: "Create Admin UI Routes",
text: "Learn how to add new pages to your Medusa Admin.", text: "Learn how to add new pages to your Medusa Admin.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/advanced-development/admin/setting-pages", href: "!docs!/advanced-development/admin/setting-pages",
title: "Create Admin Setting Page", title: "Create Admin Setting Page",
text: "Learn how to add new page to the Medusa Admin settings.", text: "Learn how to add new page to the Medusa Admin settings.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
--- ---
@@ -799,24 +786,22 @@ Medusa provides a Next.js storefront to use with your application. You can eithe
Use the publishable API key you associated with your B2B sales channel in the storefront to ensure only B2B products are retrieved. Use the publishable API key you associated with your B2B sales channel in the storefront to ensure only B2B products are retrieved.
<CardList <CardList items={[
items={[
{ {
href: "/nextjs-starter", href: "/nextjs-starter",
title: "Next.js Storefront", title: "Next.js Storefront",
text: "Learn how to install and customize the Next.js storefront.", text: "Learn how to install and customize the Next.js storefront.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "/storefront-development", href: "/storefront-development",
title: "Storefront Development", title: "Storefront Development",
text: "Find guides for your storefront development.", text: "Find guides for your storefront development.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
<Card <Card
href="!api!/api/store#publishable-api-key" href="!api!/api/store#publishable-api-key"
@@ -40,44 +40,39 @@ The `inventory-item.updated` event is currently not emitted.
</Note> </Note>
<CardList <CardList items={[
items={[
{ {
href: "!docs!/basics/modules-and-services", href: "!docs!/basics/modules-and-services",
title: "Create a Module", title: "Create a Module",
text: "Learn how to create a module in Medusa.", text: "Learn how to create a module in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/basics/data-models", href: "!docs!/basics/data-models",
title: "Create a Data Model", title: "Create a Data Model",
text: "Learn how to create a data model.", text: "Learn how to create a data model.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
<CardList <CardList items={[
items={[
{ {
href: "!docs!/basics/api-routes", href: "!docs!/basics/api-routes",
title: "Create an API Route", title: "Create an API Route",
text: "Learn how to create an API route in Medusa.", text: "Learn how to create an API route in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/basics/events-and-subscribers", href: "!docs!/basics/events-and-subscribers",
title: "Create a Subscriber", title: "Create a Subscriber",
text: "Learn how to create a subscriber in Medusa.", text: "Learn how to create a subscriber in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} className="mt-1" />
className="mt-1"
/>
<Details summaryContent="Example"> <Details summaryContent="Example">
@@ -90,17 +85,9 @@ Start by creating the `src/modules/restock-notification` directory.
Then, create the file `src/modules/restock-notification/models/restock-notification.ts` with the following content: Then, create the file `src/modules/restock-notification/models/restock-notification.ts` with the following content:
export const restockModelHighlights = [ export const restockModelHighlights = [
[ ["5", "email", "The email of the customer to send the notification to when the item is restocked."],
"5",
"email",
"The email of the customer to send the notification to when the item is restocked.",
],
["6", "variant_id", "The ID of the variant the customer is subscribed to."], ["6", "variant_id", "The ID of the variant the customer is subscribed to."],
[ ["7", "sales_channel_id", "The ID of the sales channel the customer is viewing the product variant from."]
"7",
"sales_channel_id",
"The ID of the sales channel the customer is viewing the product variant from.",
],
] ]
```ts title="src/modules/restock-notification/models/restock-notification.ts" highlights={restockModelHighlights} ```ts title="src/modules/restock-notification/models/restock-notification.ts" highlights={restockModelHighlights}
@@ -131,15 +118,15 @@ Next, create the file `src/modules/restock-notification/migrations/Migration2024
import { Migration } from "@mikro-orm/migrations" import { Migration } from "@mikro-orm/migrations"
export class Migration20240516140616 extends Migration { export class Migration20240516140616 extends Migration {
async up(): Promise<void> { async up(): Promise<void> {
this.addSql( this.addSql("create table if not exists \"restock_notification\" (\"id\" text not null, \"email\" text not null, \"variant_id\" text not null, \"sales_channel_id\" text not null, constraint \"restock_notification_pkey\" primary key (\"id\"));")
'create table if not exists "restock_notification" ("id" text not null, "email" text not null, "variant_id" text not null, "sales_channel_id" text not null, constraint "restock_notification_pkey" primary key ("id"));'
)
} }
async down(): Promise<void> { async down(): Promise<void> {
this.addSql('drop table if exists "restock_notification" cascade;') this.addSql("drop table if exists \"restock_notification\" cascade;")
} }
} }
``` ```
@@ -166,10 +153,11 @@ Next, create the module's definition file `src/modules/restock-notification/inde
```ts title="src/modules/restock-notification/index.ts" ```ts title="src/modules/restock-notification/index.ts"
import RestockNotificationModuleService from "./service" import RestockNotificationModuleService from "./service"
import { Module } from "@medusajs/utils"
export default { export default Module("restock-notification", {
service: RestockNotificationModuleService, service: RestockNotificationModuleService,
} })
``` ```
Finally, add the module to the `modules` object in `medusa-config.js`: Finally, add the module to the `modules` object in `medusa-config.js`:
@@ -178,7 +166,7 @@ Finally, add the module to the `modules` object in `medusa-config.js`:
module.exports = defineConfig({ module.exports = defineConfig({
// ... // ...
modules: { modules: {
restockNotificationModuleService: { "restockNotificationModuleService": {
resolve: "./modules/restock-notification", resolve: "./modules/restock-notification",
definition: { definition: {
isQueryable: true, isQueryable: true,
@@ -199,8 +187,12 @@ npx medusa migrations run
Create the file `src/api/store/restock-notification/route.ts` with the following content: Create the file `src/api/store/restock-notification/route.ts` with the following content:
```ts title="src/api/store/restock-notification/route.ts" collapsibleLines="1-13" expandButtonLabel="Show Imports" ```ts title="src/api/store/restock-notification/route.ts" collapsibleLines="1-13" expandButtonLabel="Show Imports"
import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa" import type {
import RestockNotificationModuleService from "../../../modules/restock-notification/service" MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import RestockNotificationModuleService
from "../../../modules/restock-notification/service"
type RestockNotificationReq = { type RestockNotificationReq = {
email: string email: string
@@ -212,10 +204,14 @@ export async function POST(
req: MedusaRequest<RestockNotificationReq>, req: MedusaRequest<RestockNotificationReq>,
res: MedusaResponse res: MedusaResponse
) { ) {
const restockNotificationModuleService: RestockNotificationModuleService = const restockNotificationModuleService:
req.scope.resolve("restockNotificationModuleService") RestockNotificationModuleService = req.scope.resolve(
"restockNotificationModuleService"
)
await restockNotificationModuleService.createRestockNotifications(req.body) await restockNotificationModuleService.createRestockNotifications(
req.body
)
res.json({ res.json({
success: true, success: true,
@@ -238,69 +234,21 @@ The `inventory-item.updated` event is currently not emitted.
{/* To handle the sending of the restock notifications, create the file `src/subscribers/inventory-item-update.ts` with the following content: */} {/* To handle the sending of the restock notifications, create the file `src/subscribers/inventory-item-update.ts` with the following content: */}
export const subscriberHighlights = [ export const subscriberHighlights = [
[ ["48", "inventoryVariantLinkService", "Retrieve an instance of the link service for the product-variant-inventory-item link module."],
"48", ["55", "inventoryVariantItems", "Retrieve the variants linked to the updated inventory item."],
"inventoryVariantLinkService", ["68", "restockQuery", "Assemble the query to retrieve the restock notifications with their associated variants."],
"Retrieve an instance of the link service for the product-variant-inventory-item link module.", ["81", "restockNotifications", "Retrieve the restock notifications using the query."],
], ["84", "salesChannelLocationService", "Retrieve an instance of the link service for the sales-channel-stock-location link module."],
[ ["93", "salesChannelLocations", "Retrieve the stock locations linked to the restock notification's sales channel."],
"55", ["107", "availableQuantity", "Retrieve the available quantity of the variant in the retrieved stock locations."],
"inventoryVariantItems", ["116", "continue", "Only send the notification if the available quantity is greater than `0`"],
"Retrieve the variants linked to the updated inventory item.", ["119", "createNotifications", "Send the notification to the customer using the Notification Module."],
], ["122", '"test_template"', "Replace with the actual template used for sending the email."],
[ ["123", "data", "The data to send along to the third-party service sending the notification."],
"68", ["131", "deleteRestockNotifications", "Delete the restock notification to not send the notification again."]
"restockQuery",
"Assemble the query to retrieve the restock notifications with their associated variants.",
],
[
"81",
"restockNotifications",
"Retrieve the restock notifications using the query.",
],
[
"84",
"salesChannelLocationService",
"Retrieve an instance of the link service for the sales-channel-stock-location link module.",
],
[
"93",
"salesChannelLocations",
"Retrieve the stock locations linked to the restock notification's sales channel.",
],
[
"107",
"availableQuantity",
"Retrieve the available quantity of the variant in the retrieved stock locations.",
],
[
"116",
"continue",
"Only send the notification if the available quantity is greater than `0`",
],
[
"119",
"createNotifications",
"Send the notification to the customer using the Notification Module.",
],
[
"122",
'"test_template"',
"Replace with the actual template used for sending the email.",
],
[
"123",
"data",
"The data to send along to the third-party service sending the notification.",
],
[
"131",
"deleteRestockNotifications",
"Delete the restock notification to not send the notification again.",
],
] ]
{/\* ```ts title="src/subscribers/inventory-item-update.ts" highlights={subscriberHighlights} collapsibleLines="1-20" expandButtonLabel="Show Imports" {/* ```ts title="src/subscribers/inventory-item-update.ts" highlights={subscriberHighlights} collapsibleLines="1-20" expandButtonLabel="Show Imports"
import type { import type {
SubscriberArgs, SubscriberArgs,
SubscriberConfig, SubscriberConfig,
@@ -431,15 +379,13 @@ Modules.NOTIFICATION
await restockNotificationModuleService await restockNotificationModuleService
.deleteRestockNotifications(restockNotification.id) .deleteRestockNotifications(restockNotification.id)
} }
} }
// subscriber config // subscriber config
export const config: SubscriberConfig = { export const config: SubscriberConfig = {
event: "inventory-item.updated", event: "inventory-item.updated",
} }
```
````
This adds a subscriber to the `inventory-item.updated` event. In the subscriber handler function, you: This adds a subscriber to the `inventory-item.updated` event. In the subscriber handler function, you:
@@ -673,7 +619,7 @@ export const syncProductsWorkflow = createWorkflow<
}) })
} }
) )
```` ```
This creates a workflow with the following steps: This creates a workflow with the following steps:
@@ -686,10 +632,15 @@ Then, create a scheduled job at `src/jobs/sync-products.ts` that executes the wo
```ts ```ts
import { MedusaContainer } from "@medusajs/types" import { MedusaContainer } from "@medusajs/types"
import { syncProductsWorkflow } from "../workflows/sync-products" import {
syncProductsWorkflow,
} from "../workflows/sync-products"
export default async function syncProductsJob(container: MedusaContainer) { export default async function syncProductsJob(
await syncProductsWorkflow(container).run({ container: MedusaContainer
) {
await syncProductsWorkflow(container)
.run({
input: { input: {
name: "John", name: "John",
}, },
@@ -728,7 +679,7 @@ The `order.placed` event is currently not emitted.
showLinkIcon={false} showLinkIcon={false}
/> />
{/_ <CardList items={[ {/* <CardList items={[
{ {
href: "!docs!/basics/events-and-subscribers", href: "!docs!/basics/events-and-subscribers",
title: "Create a Subscriber", title: "Create a Subscriber",
@@ -743,7 +694,7 @@ text: "Check out triggered events by each commerce module.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false showLinkIcon: false
}, },
]} /> _/} ]} /> */}
--- ---
@@ -757,24 +708,22 @@ Medusa's commerce features are geared towards automating RMA flows and ensuring
- Merchants can make order changes and request the customer's approval for them. The customer can also send any additional payment if necessary. - Merchants can make order changes and request the customer's approval for them. The customer can also send any additional payment if necessary.
- Every order-related action triggers an event, which you can listen to with a subscriber. This allows you to handle order events to automate actions. - Every order-related action triggers an event, which you can listen to with a subscriber. This allows you to handle order events to automate actions.
<CardList <CardList items={[
items={[
{ {
href: "/commerce-modules/orders", href: "/commerce-modules/orders",
title: "Order Module", title: "Order Module",
text: "Learn about the Order Module and its features.", text: "Learn about the Order Module and its features.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/basics/events-and-subscribers", href: "!docs!/basics/events-and-subscribers",
title: "Create a Subscriber", title: "Create a Subscriber",
text: "Learn how to create a subscriber in Medusa.", text: "Learn how to create a subscriber in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
--- ---
@@ -798,31 +747,29 @@ The `order.placed` event is currently not emitted.
</Note> </Note>
<CardList <CardList items={[
items={[
{ {
href: "/commerce-modules/customer", href: "/commerce-modules/customer",
title: "Customer Module", title: "Customer Module",
text: "Learn about the Customer Module and its features.", text: "Learn about the Customer Module and its features.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "/commerce-modules/pricing", href: "/commerce-modules/pricing",
title: "Pricing Module", title: "Pricing Module",
text: "Learn about the Pricing Module and its features.", text: "Learn about the Pricing Module and its features.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/basics/events-and-subscribers", href: "!docs!/basics/events-and-subscribers",
title: "Create a Subscriber", title: "Create a Subscriber",
text: "Learn how to create a subscriber in Medusa.", text: "Learn how to create a subscriber in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
<Details summaryContent="Example: Add customer to VIP group"> <Details summaryContent="Example: Add customer to VIP group">
@@ -835,9 +782,17 @@ The `order.placed` event is currently not emitted.
</Note> </Note>
```ts title="src/subscribers/add-custom-to-vip.ts" collapsibleLines="1-12" expandButtonLabel="Show Imports" ```ts title="src/subscribers/add-custom-to-vip.ts" collapsibleLines="1-12" expandButtonLabel="Show Imports"
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/medusa" import type {
import { ModuleRegistrationName } from "@medusajs/utils" SubscriberArgs,
import { ICustomerModuleService, IOrderModuleService } from "@medusajs/types" SubscriberConfig,
} from "@medusajs/medusa"
import {
ModuleRegistrationName,
} from "@medusajs/modules-sdk"
import {
ICustomerModuleService,
IOrderModuleService,
} from "@medusajs/types"
export default async function orderCreatedHandler({ export default async function orderCreatedHandler({
data, data,
@@ -845,23 +800,21 @@ export default async function orderCreatedHandler({
}: SubscriberArgs<{ id: string }>) { }: SubscriberArgs<{ id: string }>) {
const orderId = "data" in data ? data.data.id : data.id const orderId = "data" in data ? data.data.id : data.id
const orderModuleService: IOrderModuleService = container.resolve( const orderModuleService: IOrderModuleService = container
ModuleRegistrationName.ORDER .resolve(ModuleRegistrationName.ORDER)
)
const customerModuleService: ICustomerModuleService = container.resolve( const customerModuleService:
ICustomerModuleService = container.resolve(
ModuleRegistrationName.CUSTOMER ModuleRegistrationName.CUSTOMER
) )
// check if VIP group exists // check if VIP group exists
const vipGroup = await customerModuleService.listCustomerGroups( const vipGroup = await customerModuleService
{ .listCustomerGroups({
name: "VIP", name: "VIP",
}, }, {
{
relations: ["customers"], relations: ["customers"],
} })
)
if (!vipGroup.length) { if (!vipGroup.length) {
return return
@@ -870,13 +823,11 @@ export default async function orderCreatedHandler({
// retrieve the order // retrieve the order
const order = await orderModuleService.retrieveOrder(orderId) const order = await orderModuleService.retrieveOrder(orderId)
if ( if (!order ||
!order ||
!order.customer_id || !order.customer_id ||
vipGroup[0].customers.find( vipGroup[0].customers.find(
(customer) => customer.id === order.customer_id (customer) => customer.id === order.customer_id
) !== undefined ) !== undefined) {
) {
return return
} }
@@ -913,24 +864,22 @@ To do that, create a subscriber that listens to the `product.created`, and send
You can also create a scheduled job that checks whether the number of new products has exceeded a set threshold, then sends out the newsletter. You can also create a scheduled job that checks whether the number of new products has exceeded a set threshold, then sends out the newsletter.
<CardList <CardList items={[
items={[
{ {
href: "!docs!/basics/events-and-subscribers", href: "!docs!/basics/events-and-subscribers",
title: "Create a Subscriber", title: "Create a Subscriber",
text: "Learn how to create a subscriber in Medusa.", text: "Learn how to create a subscriber in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/basics/scheduled-jobs", href: "!docs!/basics/scheduled-jobs",
title: "Scheduled Jobs", title: "Scheduled Jobs",
text: "Learn how to create a scheduled job in Medusa.", text: "Learn how to create a scheduled job in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
<Details summaryContent="Example: Sending a newsletter email after adding ten products"> <Details summaryContent="Example: Sending a newsletter email after adding ten products">
@@ -938,43 +887,24 @@ For example, create the file `src/subscribers/send-products-newsletter.ts` with
export const newsletterHighlights = [ export const newsletterHighlights = [
["33", "store", "Retrieve the first store in the application."], ["33", "store", "Retrieve the first store in the application."],
[ ["35", "products", "Retrieve the products created since the last newsletter send date."],
"35", ["41", "", "Check whether more than 10 products have been created before proceeding."],
"products", ["45", "customers", "Retrieve all customers, assuming they're considered subscribed."],
"Retrieve the products created since the last newsletter send date.", ["47", "createNotifications", "Send a notification (newsletter) to each customer using the Notification Module."],
],
[
"41",
"",
"Check whether more than 10 products have been created before proceeding.",
],
[
"45",
"customers",
"Retrieve all customers, assuming they're considered subscribed.",
],
[
"47",
"createNotifications",
"Send a notification (newsletter) to each customer using the Notification Module.",
],
["50", '"email"', "Send the notification through the email channel."], ["50", '"email"', "Send the notification through the email channel."],
[ ["51", '"newsletter_template"', "Specify the template name in the third-party service (for example, SendGrid)."],
"51",
'"newsletter_template"',
"Specify the template name in the third-party service (for example, SendGrid).",
],
["53", "products", "Pass the created products to the template."], ["53", "products", "Pass the created products to the template."],
[ ["58", "updateStores", "Update the store's `last_newsletter_send_date` property with the current date."]
"58",
"updateStores",
"Update the store's `last_newsletter_send_date` property with the current date.",
],
] ]
```ts title="src/subscribers/send-products-newsletter.ts" highlights={newsletterHighlights} collapsibleLines="1-14" expandButtonLabel="Show Imports" ```ts title="src/subscribers/send-products-newsletter.ts" highlights={newsletterHighlights} collapsibleLines="1-14" expandButtonLabel="Show Imports"
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/medusa" import type {
import { ModuleRegistrationName } from "@medusajs/modules-sdk" SubscriberArgs,
SubscriberConfig,
} from "@medusajs/medusa"
import {
ModuleRegistrationName,
} from "@medusajs/modules-sdk"
import { import {
ICustomerModuleService, ICustomerModuleService,
IProductModuleService, IProductModuleService,
@@ -986,20 +916,19 @@ export default async function productCreateHandler({
data, data,
container, container,
}: SubscriberArgs<{ id: string }>) { }: SubscriberArgs<{ id: string }>) {
const productModuleService: IProductModuleService = container.resolve( const productModuleService: IProductModuleService =
ModuleRegistrationName.PRODUCT container.resolve(ModuleRegistrationName.PRODUCT)
)
const storeModuleService: IStoreModuleService = container.resolve( const storeModuleService: IStoreModuleService =
ModuleRegistrationName.STORE container.resolve(ModuleRegistrationName.STORE)
)
const customerModuleService: ICustomerModuleService = container.resolve( const customerModuleService: ICustomerModuleService =
ModuleRegistrationName.CUSTOMER container.resolve(ModuleRegistrationName.CUSTOMER)
)
const notificationModuleService: INotificationModuleService = const notificationModuleService:
container.resolve(ModuleRegistrationName.NOTIFICATION) INotificationModuleService = container.resolve(
ModuleRegistrationName.NOTIFICATION
)
const store = (await storeModuleService.listStores())[0] const store = (await storeModuleService.listStores())[0]
@@ -1028,7 +957,7 @@ export default async function productCreateHandler({
await storeModuleService.updateStores(store.id, { await storeModuleService.updateStores(store.id, {
metadata: { metadata: {
last_newsletter_send_date: new Date().toString(), last_newsletter_send_date: (new Date()).toString(),
}, },
}) })
} }
@@ -33,24 +33,22 @@ Use a file module provider to manage your stored digital products.
During development, you can use the Local File Module Provider, which is installed by default in your store. For production, check out available file module providers or create your own. During development, you can use the Local File Module Provider, which is installed by default in your store. For production, check out available file module providers or create your own.
<CardList <CardList items={[
items={[
{ {
href: "/architectural-modules/file", href: "/architectural-modules/file",
title: "File Module Providers", title: "File Module Providers",
text: "Check out available file module providers.", text: "Check out available file module providers.",
startIcon: <PuzzleSolid />, startIcon: <PuzzleSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "/references/file-provider-module", href: "/references/file-provider-module",
title: "Create a File Module Provider", title: "Create a File Module Provider",
text: "Learn how to create a file module provider.", text: "Learn how to create a file module provider.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
--- ---
@@ -64,14 +62,13 @@ You can use one of Medusa’s notification module providers or create your own.
{/* TODO add links */} {/* TODO add links */}
<CardList <CardList items={[
items={[
{ {
href: "/architectural-modules/notification", href: "/architectural-modules/notification",
title: "Notification Module Providers", title: "Notification Module Providers",
text: "Check out available official notification module providers.", text: "Check out available official notification module providers.",
startIcon: <PuzzleSolid />, startIcon: <PuzzleSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "/references/notification-provider-module", href: "/references/notification-provider-module",
@@ -80,8 +77,7 @@ You can use one of Medusa’s notification module providers or create your own.
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false,
}, },
]} ]} />
/>
--- ---
@@ -121,10 +117,11 @@ Next, create the file `src/modules/digital-product/index.ts` with the following
```ts title="src/modules/digital-product/index.ts" ```ts title="src/modules/digital-product/index.ts"
import DigitalProductModuleService from "./service" import DigitalProductModuleService from "./service"
import { Module } from "@medusajs/utils"
export default { export default Module("digital-product", {
service: DigitalProductModuleService, service: DigitalProductModuleService,
} })
``` ```
This file holds the definition of the module. This file holds the definition of the module.
@@ -166,7 +163,7 @@ Module Relationships is coming soon.
showLinkIcon={false} showLinkIcon={false}
/> />
{/\* <Details summaryContent="Example: Create ProductMedia Data Model"> {/* <Details summaryContent="Example: Create ProductMedia Data Model">
In this section, you’ll create a `ProductMedia` data model that represents your digital products. In this section, you’ll create a `ProductMedia` data model that represents your digital products.
@@ -175,7 +172,7 @@ Before creating the data model, create the file `src/types/digital-product/produ
```ts title="src/types/digital-product/product-media.ts" ```ts title="src/types/digital-product/product-media.ts"
export enum MediaType { export enum MediaType {
MAIN = "main", MAIN = "main",
PREVIEW = "preview", PREVIEW = "preview"
} }
``` ```
@@ -250,7 +247,7 @@ Medusa facilitates implementing data-management features by providing a service
showLinkIcon={false} showLinkIcon={false}
/> />
{/\* <Details summaryContent="Example: Add Implementation of DigitalProductModuleService"> {/* <Details summaryContent="Example: Add Implementation of DigitalProductModuleService">
In this section, you’ll modify the `DigitalProductModuleService` you created earlier to provide data-management functionalities of the `ProductMedia` data model. In this section, you’ll modify the `DigitalProductModuleService` you created earlier to provide data-management functionalities of the `ProductMedia` data model.
@@ -275,7 +272,7 @@ The `DigitalProductModuleService` now extends the service factory which generate
{/* --- */} {/* --- */}
{/\* ## Add Relationship to Product Variants {/* ## Add Relationship to Product Variants
As mentioned in a previous section, the product media has a `variant_id` that points to the saleable product variant. As mentioned in a previous section, the product media has a `variant_id` that points to the saleable product variant.
@@ -382,27 +379,24 @@ Fetching data across modules using the remote query is coming soon.
</Note> </Note>
<CardList <CardList itemsPerRow={2} items={[
itemsPerRow={2}
items={[
{ {
href: "!docs!/basics/api-routes", href: "!docs!/basics/api-routes",
title: "API Routes", title: "API Routes",
text: "Learn how to create an API route.", text: "Learn how to create an API route.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/advanced-development/modules/remote-query", href: "!docs!/advanced-development/modules/remote-query",
title: "Remote Query", title: "Remote Query",
text: "Learn about what the remote query is and how to use it.", text: "Learn about what the remote query is and how to use it.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
{/\* <Details summaryContent="Example: Custom API Routes for Digital Products"> {/* <Details summaryContent="Example: Custom API Routes for Digital Products">
In this section, you’ll create a List and Create API routes to retrieve and create digital products. In this section, you’ll create a List and Create API routes to retrieve and create digital products.
@@ -422,7 +416,7 @@ import {
export enum MediaType { export enum MediaType {
MAIN = "main", MAIN = "main",
PREVIEW = "preview", PREVIEW = "preview"
} }
export type ProductMediaDTO = { export type ProductMediaDTO = {
@@ -443,9 +437,11 @@ export type CreateProductMediaDTO = {
variant_id?: string variant_id?: string
} }
export type CreateProductMediaWorkflowInput = CreateProductMediaDTO & { export type CreateProductMediaWorkflowInput =
CreateProductMediaDTO & {
product?: CreateProductWorkflowInputDTO product?: CreateProductWorkflowInputDTO
} }
``` ```
Then, create the file `src/workflows/digital-product/create.ts` with the following content: Then, create the file `src/workflows/digital-product/create.ts` with the following content:
@@ -463,7 +459,8 @@ import {
CreateProductMediaWorkflowInput, CreateProductMediaWorkflowInput,
ProductMediaDTO, ProductMediaDTO,
} from "../../types/digital-product/product-media" } from "../../types/digital-product/product-media"
import DigitalProductModuleService from "../../modules/digital-product/service" import DigitalProductModuleService from
"../../modules/digital-product/service"
import { RemoteQueryFunction } from "@medusajs/modules-sdk" import { RemoteQueryFunction } from "@medusajs/modules-sdk"
import { import {
ContainerRegistrationKeys, ContainerRegistrationKeys,
@@ -474,7 +471,8 @@ const tryToCreateProductVariantStep = createStep(
"try-to-create-product-variant-step", "try-to-create-product-variant-step",
async (input: CreateProductMediaWorkflowInput, { container }) => { async (input: CreateProductMediaWorkflowInput, { container }) => {
if (input.product && !input.variant_id) { if (input.product && !input.variant_id) {
const { result, errors } = await createProductsWorkflow(container).run({ const { result, errors } = await createProductsWorkflow(container)
.run({
input: { input: {
products: [input.product], products: [input.product],
}, },
@@ -497,10 +495,13 @@ const tryToCreateProductVariantStep = createStep(
const createProductMediaStep = createStep( const createProductMediaStep = createStep(
"create-product-media-step", "create-product-media-step",
async (input: CreateProductMediaDTO, { container }) => { async (input: CreateProductMediaDTO, { container }) => {
const digitalProductModuleService: DigitalProductModuleService = const digitalProductModuleService:
container.resolve("digitalProductModuleService") DigitalProductModuleService = container.resolve(
"digitalProductModuleService"
)
const productMedia = await digitalProductModuleService.createProductMedias( const productMedia = await digitalProductModuleService
.createProductMedias(
input input
) )
@@ -517,7 +518,14 @@ const retrieveProductMediaWithVariant = createStep(
const query = remoteQueryObjectFromString({ const query = remoteQueryObjectFromString({
entryPoint: "product_media", entryPoint: "product_media",
fields: ["id", "name", "type", "file_key", "mime_type", "variant.*"], fields: [
"id",
"name",
"type",
"file_key",
"mime_type",
"variant.*",
],
variables: { variables: {
filters: { filters: {
id: input.id, id: input.id,
@@ -558,10 +566,17 @@ This workflow has three steps:
Finally, create the `src/api/admin/digital-products/route.ts` file with the following content: Finally, create the `src/api/admin/digital-products/route.ts` file with the following content:
```ts title="src/api/admin/digital-products/route.ts" collapsibleLines="1-12" expandButtonLabel="Show Imports" ```ts title="src/api/admin/digital-products/route.ts" collapsibleLines="1-12" expandButtonLabel="Show Imports"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" import {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { MedusaError } from "@medusajs/utils" import { MedusaError } from "@medusajs/utils"
import { CreateProductMediaWorkflowInput } from "../../../types/digital-product/product-media" import {
import { createProductMediaWorkflow } from "../../../workflows/digital-product/create" CreateProductMediaWorkflowInput,
} from "../../../types/digital-product/product-media"
import {
createProductMediaWorkflow,
} from "../../../workflows/digital-product/create"
type CreateProductMediaReq = CreateProductMediaWorkflowInput type CreateProductMediaReq = CreateProductMediaWorkflowInput
@@ -570,7 +585,11 @@ export async function POST(
res: MedusaResponse res: MedusaResponse
) { ) {
// validation omitted for simplicity // validation omitted for simplicity
const { result, errors } = await createProductMediaWorkflow(req.scope).run({ const {
result,
errors,
} = await createProductMediaWorkflow(req.scope)
.run({
input: { input: {
data: { data: {
...req.body, ...req.body,
@@ -580,7 +599,10 @@ export async function POST(
}) })
if (errors.length) { if (errors.length) {
throw new MedusaError(MedusaError.Types.DB_ERROR, errors[0].error) throw new MedusaError(
MedusaError.Types.DB_ERROR,
errors[0].error
)
} }
res.json({ res.json({
@@ -646,7 +668,7 @@ You’ll receive a response similar to the following:
"variant_id": "variant_01HXEFRMR3B09EZJX23P1DMYFQ", "variant_id": "variant_01HXEFRMR3B09EZJX23P1DMYFQ",
"variant": { "variant": {
"id": "variant_01HXEFRMR3B09EZJX23P1DMYFQ", "id": "variant_01HXEFRMR3B09EZJX23P1DMYFQ",
"title": "Harry Potter 1" "title": "Harry Potter 1",
// ... // ...
} }
} }
@@ -669,7 +691,10 @@ import {
// ... // ...
export async function GET(req: MedusaRequest, res: MedusaResponse) { export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const remoteQuery: RemoteQueryFunction = req.scope.resolve( const remoteQuery: RemoteQueryFunction = req.scope.resolve(
ContainerRegistrationKeys.REMOTE_QUERY ContainerRegistrationKeys.REMOTE_QUERY
) )
@@ -717,26 +742,24 @@ You can extend the Medusa Admin to provide merchants with an interface to manage
In your customizations, you send requests to the API routes you created to create and list digital products. In your customizations, you send requests to the API routes you created to create and list digital products.
<CardList <CardList items={[
items={[
{ {
href: "!docs!/advanced-development/admin/widgets", href: "!docs!/advanced-development/admin/widgets",
title: "Create a Widget", title: "Create a Widget",
text: "Learn how to create a widget in the Medusa Admin.", text: "Learn how to create a widget in the Medusa Admin.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/advanced-development/admin/ui-routes", href: "!docs!/advanced-development/admin/ui-routes",
title: "Create UI Route", title: "Create UI Route",
text: "Learn how to create a UI route in the Medusa Admin.", text: "Learn how to create a UI route in the Medusa Admin.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
{/\* <Details summaryContent="Example: Digital Products Page in Admin"> {/* <Details summaryContent="Example: Digital Products Page in Admin">
In this example, you’ll add a single page that lists the digital products and allows you to create a new one. The implementation will be minimal for the purpose of simplicity, so you can elaborate on it based on your use case. In this example, you’ll add a single page that lists the digital products and allows you to create a new one. The implementation will be minimal for the purpose of simplicity, so you can elaborate on it based on your use case.
@@ -745,11 +768,16 @@ To create the UI route, create the file `src/admin/routes/product-media/page.tsx
```tsx title="src/admin/routes/product-media/page.tsx" badgeLabel="Medusa Application" collapsibleLines="1-13" expandButtonLabel="Show Imports" ```tsx title="src/admin/routes/product-media/page.tsx" badgeLabel="Medusa Application" collapsibleLines="1-13" expandButtonLabel="Show Imports"
import { defineRouteConfig } from "@medusajs/admin-shared" import { defineRouteConfig } from "@medusajs/admin-shared"
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
import { Container, Heading, Table } from "@medusajs/ui" import {
Container,
Heading,
Table,
} from "@medusajs/ui"
import { PhotoSolid } from "@medusajs/icons" import { PhotoSolid } from "@medusajs/icons"
import { ProductMediaDTO } from "../../../types/digital-product/product-media" import { ProductMediaDTO } from "../../../types/digital-product/product-media"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
import ProductMediaCreateForm from "../../components/product-media/CreateForm" import ProductMediaCreateForm
from "../../components/product-media/CreateForm"
const ProductMediaListPage = () => { const ProductMediaListPage = () => {
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
@@ -772,18 +800,22 @@ const ProductMediaListPage = () => {
return ( return (
<Container> <Container>
<div className="mb-4 flex justify-between"> <div className="flex justify-between mb-4">
<Heading level="h1">Digital Products</Heading> <Heading level="h1">Digital Products</Heading>
<ProductMediaCreateForm onCreate={() => setLoading(true)} /> <ProductMediaCreateForm onCreate={() => setLoading(true)} />
</div> </div>
{loading && <div>Loading...</div>} {loading && <div>Loading...</div>}
{!loading && !productMedias.length && <div>No Digital Products</div>} {!loading && !productMedias.length && (
<div>No Digital Products</div>
)}
{!loading && productMedias.length > 0 && ( {!loading && productMedias.length > 0 && (
<Table> <Table>
<Table.Header> <Table.Header>
<Table.Row> <Table.Row>
<Table.HeaderCell>Product</Table.HeaderCell> <Table.HeaderCell>Product</Table.HeaderCell>
<Table.HeaderCell>Product Variant</Table.HeaderCell> <Table.HeaderCell>
Product Variant
</Table.HeaderCell>
<Table.HeaderCell>File Key</Table.HeaderCell> <Table.HeaderCell>File Key</Table.HeaderCell>
<Table.HeaderCell>Action</Table.HeaderCell> <Table.HeaderCell>Action</Table.HeaderCell>
</Table.Row> </Table.Row>
@@ -791,15 +823,21 @@ const ProductMediaListPage = () => {
<Table.Body> <Table.Body>
{productMedias.map((product_media) => ( {productMedias.map((product_media) => (
<Table.Row key={product_media.id}> <Table.Row key={product_media.id}>
<Table.Cell>{product_media.variant?.product.title}</Table.Cell>
<Table.Cell>{product_media.variant?.title}</Table.Cell>
<Table.Cell>{product_media.file_key}</Table.Cell>
<Table.Cell> <Table.Cell>
{product_media.variant && ( {product_media.variant?.product.title}
<Link to={`/products/${product_media.variant.product_id}`}> </Table.Cell>
<Table.Cell>
{product_media.variant?.title}
</Table.Cell>
<Table.Cell>
{product_media.file_key}
</Table.Cell>
<Table.Cell>
{product_media.variant && <Link to={`/products/${
product_media.variant.product_id
}`}>
View Product View Product
</Link> </Link>}
)}
</Table.Cell> </Table.Cell>
</Table.Row> </Table.Row>
))} ))}
@@ -827,7 +865,14 @@ To create this form, create the file `src/admin/components/product-media/CreateF
```tsx title="src/admin/components/product-media/CreateForm/index.tsx" badgeLabel="Medusa Application" collapsibleLines="1-11" expandButtonLabel="Show Imports" ```tsx title="src/admin/components/product-media/CreateForm/index.tsx" badgeLabel="Medusa Application" collapsibleLines="1-11" expandButtonLabel="Show Imports"
import { useState } from "react" import { useState } from "react"
import { redirect } from "react-router-dom" import { redirect } from "react-router-dom"
import { Button, Container, Input, Label, Select, Drawer } from "@medusajs/ui" import {
Button,
Container,
Input,
Label,
Select,
Drawer,
} from "@medusajs/ui"
type Props = { type Props = {
onCreate: () => void onCreate: () => void
@@ -836,7 +881,10 @@ type Props = {
const ProductMediaCreateForm = ({ onCreate }: Props) => { const ProductMediaCreateForm = ({ onCreate }: Props) => {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [productName, setProductName] = useState("") const [productName, setProductName] = useState("")
const [productVariantName, setProductVariantName] = useState("") const [
productVariantName,
setProductVariantName,
] = useState("")
const [name, setName] = useState("") const [name, setName] = useState("")
const [type, setType] = useState("main") const [type, setType] = useState("main")
const [file, setFile] = useState<File>() const [file, setFile] = useState<File>()
@@ -903,12 +951,17 @@ const ProductMediaCreateForm = ({ onCreate }: Props) => {
</Drawer.Trigger> </Drawer.Trigger>
<Drawer.Content> <Drawer.Content>
<Drawer.Header> <Drawer.Header>
<Drawer.Title>Create Digital Product</Drawer.Title> <Drawer.Title>
Create Digital Product
</Drawer.Title>
</Drawer.Header> </Drawer.Header>
<Drawer.Body> <Drawer.Body>
<Container> <Container>
<form onSubmit={handleSubmit} className="flex flex-col gap-4"> <form
<div className="flex items-center gap-4"> onSubmit={handleSubmit}
className="flex flex-col gap-4"
>
<div className="flex gap-4 items-center">
<Label>Product Name</Label> <Label>Product Name</Label>
<Input <Input
type="text" type="text"
@@ -917,16 +970,18 @@ const ProductMediaCreateForm = ({ onCreate }: Props) => {
onChange={(e) => setProductName(e.target.value)} onChange={(e) => setProductName(e.target.value)}
/> />
</div> </div>
<div className="flex items-center gap-4"> <div className="flex gap-4 items-center">
<Label>Product Variant Name</Label> <Label>Product Variant Name</Label>
<Input <Input
type="text" type="text"
placeholder="Product Variant" placeholder="Product Variant"
value={productVariantName} value={productVariantName}
onChange={(e) => setProductVariantName(e.target.value)} onChange={(e) =>
setProductVariantName(e.target.value)
}
/> />
</div> </div>
<div className="flex items-center gap-4"> <div className="flex gap-4 items-center">
<Label>Media Name</Label> <Label>Media Name</Label>
<Input <Input
type="text" type="text"
@@ -935,26 +990,33 @@ const ProductMediaCreateForm = ({ onCreate }: Props) => {
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
/> />
</div> </div>
<div className="flex items-center gap-4"> <div className="flex gap-4 items-center">
<Label>Type</Label> <Label>Type</Label>
<Select onValueChange={setType} value={type}> <Select onValueChange={setType} value={type}>
<Select.Trigger> <Select.Trigger>
<Select.Value placeholder="Type" /> <Select.Value placeholder="Type" />
</Select.Trigger> </Select.Trigger>
<Select.Content className="z-50"> <Select.Content className="z-50">
<Select.Item value={"main"}>Main</Select.Item> <Select.Item value={"main"}>
<Select.Item value={"preview"}>Preview</Select.Item> Main
</Select.Item>
<Select.Item value={"preview"}>
Preview
</Select.Item>
</Select.Content> </Select.Content>
</Select> </Select>
</div> </div>
<div className="flex items-center gap-4"> <div className="flex gap-4 items-center">
<Label>File</Label> <Label>File</Label>
<Input <Input
type="file" type="file"
onChange={(e) => setFile(e.target.files[0])} onChange={(e) => setFile(e.target.files[0])}
/> />
</div> </div>
<Button variant="primary" type="submit" isLoading={loading}> <Button
variant="primary"
type="submit"
isLoading={loading}>
Create Create
</Button> </Button>
</form> </form>
@@ -1020,7 +1082,7 @@ In the subscriber, you can send a notification, such as an email, to the custome
showLinkIcon={false} showLinkIcon={false}
/> />
{/\* <Details summaryContent="Example"> {/* <Details summaryContent="Example">
<Note> <Note>
@@ -1031,29 +1093,38 @@ An alternative solution is to create a store download API Route that allows auth
Here’s an example of a subscriber that retrieves the download links and sends them to the customer using the installed notification module provider: Here’s an example of a subscriber that retrieves the download links and sends them to the customer using the installed notification module provider:
```ts title="src/subscribers/handle-order.ts" badgeLabel="Medusa Application" collapsibleLines="1-15" expandButtonLabel="Show Imports" ```ts title="src/subscribers/handle-order.ts" badgeLabel="Medusa Application" collapsibleLines="1-15" expandButtonLabel="Show Imports"
import { type SubscriberConfig, type SubscriberArgs } from "@medusajs/medusa" import {
type SubscriberConfig,
type SubscriberArgs,
} from "@medusajs/medusa"
import { import {
IOrderModuleService, IOrderModuleService,
IFileModuleService, IFileModuleService,
INotificationModuleService, INotificationModuleService,
} from "@medusajs/types" } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/utils" import {
import DigitalProductModuleService from "../modules/digital-product/service" ModuleRegistrationName,
} from "@medusajs/modules-sdk"
import DigitalProductModuleService
from "../modules/digital-product/service"
export default async function handleOrderPlaced({ export default async function handleOrderPlaced({
data, data, container,
container,
}: SubscriberArgs<{ id: string }>) { }: SubscriberArgs<{ id: string }>) {
const orderModuleService: IOrderModuleService = container.resolve( const orderModuleService: IOrderModuleService =
container.resolve(
ModuleRegistrationName.ORDER ModuleRegistrationName.ORDER
) )
const fileModuleService: IFileModuleService = container.resolve( const fileModuleService: IFileModuleService =
container.resolve(
ModuleRegistrationName.FILE ModuleRegistrationName.FILE
) )
const notificationModuleService: INotificationModuleService = const notificationModuleService: INotificationModuleService =
container.resolve(ModuleRegistrationName.NOTIFICATION) container.resolve(ModuleRegistrationName.NOTIFICATION)
const digitalProductModuleService: DigitalProductModuleService = const digitalProductModuleService:
container.resolve("digitalProductModuleService") DigitalProductModuleService = container.resolve(
"digitalProductModuleService"
)
const orderId = "data" in data ? data.data.id : data.id const orderId = "data" in data ? data.data.id : data.id
@@ -1064,14 +1135,18 @@ export default async function handleOrderPlaced({
// find product medias in the order // find product medias in the order
const urls = [] const urls = []
for (const item of order.items) { for (const item of order.items) {
const productMedias = await digitalProductModuleService.listProductMedias({ const productMedias = await digitalProductModuleService
.listProductMedias({
variant_id: [item.variant_id], variant_id: [item.variant_id],
}) })
const downloadUrls = await Promise.all( const downloadUrls = await Promise.all(
productMedias.map(async (productMedia) => { productMedias.map(async (productMedia) => {
// get the download URL from the file service // get the download URL from the file service
return (await fileModuleService.retrieveFile(productMedia.file_key)).url return (await fileModuleService.retrieveFile(
productMedia.file_key
)).url
}) })
) )
@@ -61,7 +61,7 @@ apiKey: string
} }
class ErpModuleService { class ErpModuleService {
private client\_: AxiosInstance private client_: AxiosInstance
constructor({}, { apiKey }: ErpModuleOptions) { constructor({}, { apiKey }: ErpModuleOptions) {
this.client_ = axios.create({ this.client_ = axios.create({
@@ -87,12 +87,11 @@ private client\_: AxiosInstance
async deleteProduct(id: string) { async deleteProduct(id: string) {
await this.client_.delete(`/product/${id}`) await this.client_.delete(`/product/${id}`)
} }
} }
export default ErpModuleService export default ErpModuleService
```` ```
This creates the module's main service. Few things to note: This creates the module's main service. Few things to note:
@@ -40,24 +40,22 @@ Module Relationships is coming soon.
</Note> </Note>
<CardList <CardList items={[
items={[
{ {
href: "!docs!/basics/modules-and-services", href: "!docs!/basics/modules-and-services",
title: "Create a Module", title: "Create a Module",
text: "Learn how to create a module", text: "Learn how to create a module",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/advanced-development/modules/module-relationships", href: "!docs!/advanced-development/modules/module-relationships",
title: "Module Relationships", title: "Module Relationships",
text: "Create relationships between modules.", text: "Create relationships between modules.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
<Details summaryContent="Example"> <Details summaryContent="Example">
@@ -126,27 +124,23 @@ To reflect these changes on the database, create the migration `src/modules/mark
import { Migration } from "@mikro-orm/migrations" import { Migration } from "@mikro-orm/migrations"
export class Migration20240514143248 extends Migration { export class Migration20240514143248 extends Migration {
async up(): Promise<void> { async up(): Promise<void> {
this.addSql( this.addSql("create table if not exists \"store_order\" (\"id\" varchar(255) not null, \"store_id\" text not null, \"order_id\" text not null, \"parent_order_id\" text not null, constraint \"store_order_pkey\" primary key (\"id\"));")
'create table if not exists "store_order" ("id" varchar(255) not null, "store_id" text not null, "order_id" text not null, "parent_order_id" text not null, constraint "store_order_pkey" primary key ("id"));'
)
this.addSql( this.addSql("create table if not exists \"store_product\" (\"id\" varchar(255) not null, \"store_id\" text not null, \"product_id\" text not null, constraint \"store_product_pkey\" primary key (\"id\"));")
'create table if not exists "store_product" ("id" varchar(255) not null, "store_id" text not null, "product_id" text not null, constraint "store_product_pkey" primary key ("id"));'
)
this.addSql( this.addSql("create table if not exists \"store_user\" (\"id\" varchar(255) not null, \"store_id\" text not null, \"user_id\" text not null, constraint \"store_user_pkey\" primary key (\"id\"));")
'create table if not exists "store_user" ("id" varchar(255) not null, "store_id" text not null, "user_id" text not null, constraint "store_user_pkey" primary key ("id"));'
)
} }
async down(): Promise<void> { async down(): Promise<void> {
this.addSql('drop table if exists "store_order" cascade;') this.addSql("drop table if exists \"store_order\" cascade;")
this.addSql('drop table if exists "store_product" cascade;') this.addSql("drop table if exists \"store_product\" cascade;")
this.addSql('drop table if exists "store_user" cascade;') this.addSql("drop table if exists \"store_user\" cascade;")
} }
} }
``` ```
@@ -173,8 +167,7 @@ StoreOrder,
} }
export default MarketplaceModuleService export default MarketplaceModuleService
```
````
The module’s main service extends the service factory to generate data management features for the `StoreUser`, `StoreProduct`, and `StoreOrder` data models. The module’s main service extends the service factory to generate data management features for the `StoreUser`, `StoreProduct`, and `StoreOrder` data models.
@@ -182,11 +175,12 @@ Finally, create the module definition at `src/modules/marketplace/index.ts` with
```ts title="src/modules/marketplace/index.ts" ```ts title="src/modules/marketplace/index.ts"
import MarketplaceModuleService from "./service" import MarketplaceModuleService from "./service"
import { Module } from "@medusajs/utils"
export default { export default Module("marketplace", {
service: MarketplaceModuleService, service: MarketplaceModuleService,
} })
```` ```
To use the module, add it to the `modules` object in `medusa-config.js`: To use the module, add it to the `modules` object in `medusa-config.js`:
@@ -234,7 +228,7 @@ To attach admin users to their own stores, create a subscriber that listens to t
showLinkIcon={false} showLinkIcon={false}
/> />
{/\* <Details summaryContent="Example"> {/* <Details summaryContent="Example">
Create the file `src/subscribers/user-created.ts` with the following content: Create the file `src/subscribers/user-created.ts` with the following content:
@@ -284,14 +278,12 @@ const marketplaceModuleService: MarketplaceModuleService = container.resolve(
}) })
console.log(`Created StoreUser ${storeUser.id}`) console.log(`Created StoreUser ${storeUser.id}`)
} }
export const config: SubscriberConfig = { export const config: SubscriberConfig = {
event: "user.created", event: "user.created",
} }
```
````
This adds a subscriber to the `user.created` event. In the subscriber, you: This adds a subscriber to the `user.created` event. In the subscriber, you:
@@ -303,7 +295,7 @@ To test it out, use the `medusa user` command to create a user:
```bash npm2yarn ```bash npm2yarn
npx medusa user -e my-admin@medusa-test.com -p supersecret npx medusa user -e my-admin@medusa-test.com -p supersecret
```` ```
At the end of the output, you should see the message `Created StoreUser {store_user_id}` where the `{store_user_id}` is the ID of the created `StoreUser`. At the end of the output, you should see the message `Created StoreUser {store_user_id}` where the `{store_user_id}` is the ID of the created `StoreUser`.
@@ -330,7 +322,7 @@ Similar to the previous section, to attach products to stores, create a subscrib
showLinkIcon={false} showLinkIcon={false}
/> />
{/\* <Details summaryContent="Example"> {/* <Details summaryContent="Example">
Create the file `src/subscribers/product-created.ts` with the following content: Create the file `src/subscribers/product-created.ts` with the following content:
@@ -374,14 +366,12 @@ ModuleRegistrationName.PRODUCT
store_id: product.metadata.store_id as string, store_id: product.metadata.store_id as string,
product_id: id, product_id: id,
}) })
} }
export const config: SubscriberConfig = { export const config: SubscriberConfig = {
event: "product.created", event: "product.created",
} }
```
````
This adds a subscriber to the `product.created` event. In the subscriber, you: This adds a subscriber to the `product.created` event. In the subscriber, you:
@@ -393,7 +383,7 @@ To test it out, start the Medusa application:
```bash npm2yarn ```bash npm2yarn
npm run dev npm run dev
```` ```
Then, send an authenticated `POST` request to `/admin/products`: Then, send an authenticated `POST` request to `/admin/products`:
@@ -426,26 +416,24 @@ Retrieving module relationship data using the remote query is coming soon.
</Note> </Note>
<CardList <CardList items={[
items={[
{ {
href: "!docs!/basics/api-routes", href: "!docs!/basics/api-routes",
title: "API Routes", title: "API Routes",
text: "Learn how to create an API Route in Medusa.", text: "Learn how to create an API Route in Medusa.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/advanced-development/modules/remote-query", href: "!docs!/advanced-development/modules/remote-query",
title: "Remote Query", title: "Remote Query",
text: "Use the remote query to fetch data across modules.", text: "Use the remote query to fetch data across modules.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
{/\* <Details summaryContent="Example"> {/* <Details summaryContent="Example">
Create the file `src/api/admin/marketplace/products/route.ts` with the following content: Create the file `src/api/admin/marketplace/products/route.ts` with the following content:
@@ -511,10 +499,8 @@ ContainerRegistrationKeys.REMOTE_QUERY
store_id: storeUsers[0].store_id, store_id: storeUsers[0].store_id,
products: result.map((data) => data.product), products: result.map((data) => data.product),
}) })
} }
```
````
This creates a `GET` API route at `/admin/marketplace/products`. In the API route, you: This creates a `GET` API route at `/admin/marketplace/products`. In the API route, you:
@@ -543,7 +529,7 @@ export const config: MiddlewaresConfig = {
}, },
], ],
} }
```` ```
This ensures that only authenticated admin users can access your API route. This ensures that only authenticated admin users can access your API route.
@@ -579,7 +565,7 @@ The `order.placed` event is still not emitted in Medusa V2.
showLinkIcon={false} showLinkIcon={false}
/> />
{/\* <Details summaryContent="Example"> {/* <Details summaryContent="Example">
Create the file `src/subscribers/order-created.ts` with the following content: Create the file `src/subscribers/order-created.ts` with the following content:
@@ -686,14 +672,12 @@ ModuleRegistrationName.ORDER
}) })
}) })
) )
} }
export const config: SubscriberConfig = { export const config: SubscriberConfig = {
event: "order.placed", event: "order.placed",
} }
```
````
This adds a subscriber to the `order.placed` event. In the subscriber, you: This adds a subscriber to the `order.placed` event. In the subscriber, you:
@@ -795,7 +779,7 @@ export async function GET(
orders: result.map((data) => data.order), orders: result.map((data) => data.order),
}) })
} }
```` ```
This creates a `GET` API route at `/admin/marketplace/orders`. In the API route, you: This creates a `GET` API route at `/admin/marketplace/orders`. In the API route, you:
@@ -822,21 +806,19 @@ Medusa provides a Next.js storefront to use with your application. You can eithe
For example, you can create an API route that retrieves available stores and another API route that retrieves the products of each store using the remote query as done in previous sections. For example, you can create an API route that retrieves available stores and another API route that retrieves the products of each store using the remote query as done in previous sections.
<CardList <CardList items={[
items={[
{ {
href: "/nextjs-starter", href: "/nextjs-starter",
title: "Next.js Storefront", title: "Next.js Storefront",
text: "Learn how to install and customize the Next.js storefront.", text: "Learn how to install and customize the Next.js storefront.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
{ {
href: "!docs!/storefront-development/tips", href: "!docs!/storefront-development/tips",
title: "Storefront Tips", title: "Storefront Tips",
text: "Find tips on developing a custom storefront.", text: "Find tips on developing a custom storefront.",
startIcon: <AcademicCapSolid />, startIcon: <AcademicCapSolid />,
showLinkIcon: false, showLinkIcon: false
}, },
]} ]} />
/>
@@ -30,6 +30,7 @@ const Navbar = () => {
mobileSidebarOpen, mobileSidebarOpen,
}} }}
isLoading={false} isLoading={false}
showSearchOpener
/> />
) )
} }
+116 -116
View File
@@ -1,4 +1,8 @@
export const filesMap = [ export const filesMap = [
{
"filePath": "/www/apps/resources/app/_events-reference/page.mdx",
"pathname": "/_events-reference"
},
{ {
"filePath": "/www/apps/resources/app/admin-widget-injection-zones/page.mdx", "filePath": "/www/apps/resources/app/admin-widget-injection-zones/page.mdx",
"pathname": "/admin-widget-injection-zones" "pathname": "/admin-widget-injection-zones"
@@ -79,18 +83,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx", "filePath": "/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx",
"pathname": "/architectural-modules/workflow-engine/redis" "pathname": "/architectural-modules/workflow-engine/redis"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/api-key/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/api-key/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/api-key/_events/page.mdx",
"pathname": "/commerce-modules/api-key/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/api-key/concepts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/api-key/concepts/page.mdx",
"pathname": "/commerce-modules/api-key/concepts" "pathname": "/commerce-modules/api-key/concepts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/api-key/events/_events-table/page.mdx",
"pathname": "/commerce-modules/api-key/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/api-key/events/page.mdx",
"pathname": "/commerce-modules/api-key/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx",
"pathname": "/commerce-modules/api-key/examples" "pathname": "/commerce-modules/api-key/examples"
@@ -103,6 +107,14 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/api-key/relations-to-other-modules/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/api-key/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/api-key/relations-to-other-modules" "pathname": "/commerce-modules/api-key/relations-to-other-modules"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/auth/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/_events/page.mdx",
"pathname": "/commerce-modules/auth/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx",
"pathname": "/commerce-modules/auth/auth-flows" "pathname": "/commerce-modules/auth/auth-flows"
@@ -131,14 +143,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx",
"pathname": "/commerce-modules/auth/create-actor-type" "pathname": "/commerce-modules/auth/create-actor-type"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/events/_events-table/page.mdx",
"pathname": "/commerce-modules/auth/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/events/page.mdx",
"pathname": "/commerce-modules/auth/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/auth/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/auth/examples/page.mdx",
"pathname": "/commerce-modules/auth/examples" "pathname": "/commerce-modules/auth/examples"
@@ -151,18 +155,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/auth/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/auth/page.mdx",
"pathname": "/commerce-modules/auth" "pathname": "/commerce-modules/auth"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/cart/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/cart/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/cart/_events/page.mdx",
"pathname": "/commerce-modules/cart/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/cart/concepts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/cart/concepts/page.mdx",
"pathname": "/commerce-modules/cart/concepts" "pathname": "/commerce-modules/cart/concepts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/cart/events/_events-table/page.mdx",
"pathname": "/commerce-modules/cart/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/cart/events/page.mdx",
"pathname": "/commerce-modules/cart/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/cart/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/cart/examples/page.mdx",
"pathname": "/commerce-modules/cart/examples" "pathname": "/commerce-modules/cart/examples"
@@ -184,12 +188,12 @@ export const filesMap = [
"pathname": "/commerce-modules/cart/tax-lines" "pathname": "/commerce-modules/cart/tax-lines"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/currency/events/_events-table/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/currency/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/currency/events/_events-table" "pathname": "/commerce-modules/currency/_events/_events-table"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/currency/events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/currency/_events/page.mdx",
"pathname": "/commerce-modules/currency/events" "pathname": "/commerce-modules/currency/_events"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/currency/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/currency/examples/page.mdx",
@@ -203,18 +207,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/currency/relations-to-other-modules/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/currency/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/currency/relations-to-other-modules" "pathname": "/commerce-modules/currency/relations-to-other-modules"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/customer/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/customer/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/customer/_events/page.mdx",
"pathname": "/commerce-modules/customer/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/customer/customer-accounts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/customer/customer-accounts/page.mdx",
"pathname": "/commerce-modules/customer/customer-accounts" "pathname": "/commerce-modules/customer/customer-accounts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/customer/events/_events-table/page.mdx",
"pathname": "/commerce-modules/customer/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/customer/events/page.mdx",
"pathname": "/commerce-modules/customer/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/customer/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/customer/examples/page.mdx",
"pathname": "/commerce-modules/customer/examples" "pathname": "/commerce-modules/customer/examples"
@@ -227,18 +231,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/customer/relations-to-other-modules/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/customer/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/customer/relations-to-other-modules" "pathname": "/commerce-modules/customer/relations-to-other-modules"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/fulfillment/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/fulfillment/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/fulfillment/_events/page.mdx",
"pathname": "/commerce-modules/fulfillment/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/fulfillment/concepts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/fulfillment/concepts/page.mdx",
"pathname": "/commerce-modules/fulfillment/concepts" "pathname": "/commerce-modules/fulfillment/concepts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/fulfillment/events/_events-table/page.mdx",
"pathname": "/commerce-modules/fulfillment/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/fulfillment/events/page.mdx",
"pathname": "/commerce-modules/fulfillment/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/fulfillment/fulfillment-provider/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/fulfillment/fulfillment-provider/page.mdx",
"pathname": "/commerce-modules/fulfillment/fulfillment-provider" "pathname": "/commerce-modules/fulfillment/fulfillment-provider"
@@ -263,18 +267,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/fulfillment/shipping-option/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/fulfillment/shipping-option/page.mdx",
"pathname": "/commerce-modules/fulfillment/shipping-option" "pathname": "/commerce-modules/fulfillment/shipping-option"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/inventory/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/inventory/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/inventory/_events/page.mdx",
"pathname": "/commerce-modules/inventory/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/inventory/concepts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/inventory/concepts/page.mdx",
"pathname": "/commerce-modules/inventory/concepts" "pathname": "/commerce-modules/inventory/concepts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/inventory/events/_events-table/page.mdx",
"pathname": "/commerce-modules/inventory/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/inventory/events/page.mdx",
"pathname": "/commerce-modules/inventory/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/inventory/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/inventory/examples/page.mdx",
"pathname": "/commerce-modules/inventory/examples" "pathname": "/commerce-modules/inventory/examples"
@@ -291,18 +295,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/inventory/relations-to-other-modules/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/inventory/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/inventory/relations-to-other-modules" "pathname": "/commerce-modules/inventory/relations-to-other-modules"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/order/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/order/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/order/_events/page.mdx",
"pathname": "/commerce-modules/order/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/order/concepts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/order/concepts/page.mdx",
"pathname": "/commerce-modules/order/concepts" "pathname": "/commerce-modules/order/concepts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/order/events/_events-table/page.mdx",
"pathname": "/commerce-modules/order/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/order/events/page.mdx",
"pathname": "/commerce-modules/order/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/order/order-change/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/order/order-change/page.mdx",
"pathname": "/commerce-modules/order/order-change" "pathname": "/commerce-modules/order/order-change"
@@ -336,12 +340,12 @@ export const filesMap = [
"pathname": "/commerce-modules" "pathname": "/commerce-modules"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/payment/events/_events-table/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/payment/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/payment/events/_events-table" "pathname": "/commerce-modules/payment/_events/_events-table"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/payment/events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/payment/_events/page.mdx",
"pathname": "/commerce-modules/payment/events" "pathname": "/commerce-modules/payment/_events"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/payment/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/payment/examples/page.mdx",
@@ -387,18 +391,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/payment/webhook-events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/payment/webhook-events/page.mdx",
"pathname": "/commerce-modules/payment/webhook-events" "pathname": "/commerce-modules/payment/webhook-events"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/pricing/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/pricing/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/pricing/_events/page.mdx",
"pathname": "/commerce-modules/pricing/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/pricing/concepts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/pricing/concepts/page.mdx",
"pathname": "/commerce-modules/pricing/concepts" "pathname": "/commerce-modules/pricing/concepts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/pricing/events/_events-table/page.mdx",
"pathname": "/commerce-modules/pricing/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/pricing/events/page.mdx",
"pathname": "/commerce-modules/pricing/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx",
"pathname": "/commerce-modules/pricing/examples" "pathname": "/commerce-modules/pricing/examples"
@@ -420,12 +424,12 @@ export const filesMap = [
"pathname": "/commerce-modules/pricing/relations-to-other-modules" "pathname": "/commerce-modules/pricing/relations-to-other-modules"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/product/events/_events-table/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/product/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/product/events/_events-table" "pathname": "/commerce-modules/product/_events/_events-table"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/product/events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/product/_events/page.mdx",
"pathname": "/commerce-modules/product/events" "pathname": "/commerce-modules/product/_events"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/product/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/product/examples/page.mdx",
@@ -439,6 +443,14 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/product/relations-to-other-modules/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/product/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/product/relations-to-other-modules" "pathname": "/commerce-modules/product/relations-to-other-modules"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/promotion/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/promotion/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/promotion/_events/page.mdx",
"pathname": "/commerce-modules/promotion/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/promotion/actions/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/promotion/actions/page.mdx",
"pathname": "/commerce-modules/promotion/actions" "pathname": "/commerce-modules/promotion/actions"
@@ -455,14 +467,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/promotion/concepts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/promotion/concepts/page.mdx",
"pathname": "/commerce-modules/promotion/concepts" "pathname": "/commerce-modules/promotion/concepts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/promotion/events/_events-table/page.mdx",
"pathname": "/commerce-modules/promotion/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/promotion/events/page.mdx",
"pathname": "/commerce-modules/promotion/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/promotion/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/promotion/examples/page.mdx",
"pathname": "/commerce-modules/promotion/examples" "pathname": "/commerce-modules/promotion/examples"
@@ -476,12 +480,12 @@ export const filesMap = [
"pathname": "/commerce-modules/promotion/relations-to-other-modules" "pathname": "/commerce-modules/promotion/relations-to-other-modules"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/region/events/_events-table/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/region/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/region/events/_events-table" "pathname": "/commerce-modules/region/_events/_events-table"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/region/events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/region/_events/page.mdx",
"pathname": "/commerce-modules/region/events" "pathname": "/commerce-modules/region/_events"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/region/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/region/examples/page.mdx",
@@ -496,12 +500,12 @@ export const filesMap = [
"pathname": "/commerce-modules/region/relations-to-other-modules" "pathname": "/commerce-modules/region/relations-to-other-modules"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/sales-channel/events/_events-table/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/sales-channel/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/sales-channel/events/_events-table" "pathname": "/commerce-modules/sales-channel/_events/_events-table"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/sales-channel/events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/sales-channel/_events/page.mdx",
"pathname": "/commerce-modules/sales-channel/events" "pathname": "/commerce-modules/sales-channel/_events"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/sales-channel/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/sales-channel/examples/page.mdx",
@@ -519,18 +523,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/sales-channel/relations-to-other-modules/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/sales-channel/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/sales-channel/relations-to-other-modules" "pathname": "/commerce-modules/sales-channel/relations-to-other-modules"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/stock-location/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/stock-location/_events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/stock-location/_events/page.mdx",
"pathname": "/commerce-modules/stock-location/_events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/stock-location/concepts/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/stock-location/concepts/page.mdx",
"pathname": "/commerce-modules/stock-location/concepts" "pathname": "/commerce-modules/stock-location/concepts"
}, },
{
"filePath": "/www/apps/resources/app/commerce-modules/stock-location/events/_events-table/page.mdx",
"pathname": "/commerce-modules/stock-location/events/_events-table"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/stock-location/events/page.mdx",
"pathname": "/commerce-modules/stock-location/events"
},
{ {
"filePath": "/www/apps/resources/app/commerce-modules/stock-location/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/stock-location/examples/page.mdx",
"pathname": "/commerce-modules/stock-location/examples" "pathname": "/commerce-modules/stock-location/examples"
@@ -544,12 +548,12 @@ export const filesMap = [
"pathname": "/commerce-modules/stock-location/relations-to-other-modules" "pathname": "/commerce-modules/stock-location/relations-to-other-modules"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/store/events/_events-table/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/store/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/store/events/_events-table" "pathname": "/commerce-modules/store/_events/_events-table"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/store/events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/store/_events/page.mdx",
"pathname": "/commerce-modules/store/events" "pathname": "/commerce-modules/store/_events"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/store/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/store/examples/page.mdx",
@@ -564,12 +568,12 @@ export const filesMap = [
"pathname": "/commerce-modules/store/relations-to-other-modules" "pathname": "/commerce-modules/store/relations-to-other-modules"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/tax/events/_events-table/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/tax/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/tax/events/_events-table" "pathname": "/commerce-modules/tax/_events/_events-table"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/tax/events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/tax/_events/page.mdx",
"pathname": "/commerce-modules/tax/events" "pathname": "/commerce-modules/tax/_events"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/tax/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/tax/examples/page.mdx",
@@ -596,12 +600,12 @@ export const filesMap = [
"pathname": "/commerce-modules/tax/tax-region" "pathname": "/commerce-modules/tax/tax-region"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/user/events/_events-table/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/user/_events/_events-table/page.mdx",
"pathname": "/commerce-modules/user/events/_events-table" "pathname": "/commerce-modules/user/_events/_events-table"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/user/events/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/user/_events/page.mdx",
"pathname": "/commerce-modules/user/events" "pathname": "/commerce-modules/user/_events"
}, },
{ {
"filePath": "/www/apps/resources/app/commerce-modules/user/examples/page.mdx", "filePath": "/www/apps/resources/app/commerce-modules/user/examples/page.mdx",
@@ -671,10 +675,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/deployment/storefront/vercel/page.mdx", "filePath": "/www/apps/resources/app/deployment/storefront/vercel/page.mdx",
"pathname": "/deployment/storefront/vercel" "pathname": "/deployment/storefront/vercel"
}, },
{
"filePath": "/www/apps/resources/app/events-reference/page.mdx",
"pathname": "/events-reference"
},
{ {
"filePath": "/www/apps/resources/app/favicon.ico", "filePath": "/www/apps/resources/app/favicon.ico",
"pathname": "/" "pathname": "/"
-133
View File
@@ -162,13 +162,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/api-key/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -371,13 +364,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/auth/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -880,13 +866,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/cart/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -990,13 +969,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/currency/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -1275,13 +1247,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/customer/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -1931,13 +1896,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/fulfillment/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -2293,13 +2251,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/inventory/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -3187,13 +3138,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/order/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -3557,13 +3501,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/payment/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -3947,13 +3884,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/pricing/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -4533,13 +4463,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/product/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -4881,13 +4804,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/promotion/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -5061,13 +4977,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/region/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -5220,13 +5129,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/sales-channel/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -5386,13 +5288,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/stock-location/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -5545,13 +5440,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/store/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -5823,13 +5711,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/tax/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -6052,13 +5933,6 @@ export const generatedSidebar = [
] ]
} }
] ]
},
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/user/events",
"title": "Events Reference",
"children": []
} }
] ]
} }
@@ -7917,13 +7791,6 @@ export const generatedSidebar = [
"title": "Medusa Container Resources", "title": "Medusa Container Resources",
"children": [] "children": []
}, },
{
"loaded": true,
"isPathHref": true,
"path": "/events-reference",
"title": "Events",
"children": []
},
{ {
"loaded": true, "loaded": true,
"isPathHref": true, "isPathHref": true,
+76 -76
View File
@@ -65,10 +65,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/api-key/events", // path: "/commerce-modules/api-key/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -156,10 +156,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/auth/events", // path: "/commerce-modules/auth/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -224,10 +224,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/cart/events", // path: "/commerce-modules/cart/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -280,10 +280,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/currency/events", // path: "/commerce-modules/currency/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -340,10 +340,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/customer/events", // path: "/commerce-modules/customer/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -417,10 +417,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/fulfillment/events", // path: "/commerce-modules/fulfillment/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -482,10 +482,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/inventory/events", // path: "/commerce-modules/inventory/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -558,10 +558,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/order/events", // path: "/commerce-modules/order/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -657,10 +657,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/payment/events", // path: "/commerce-modules/payment/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -725,10 +725,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/pricing/events", // path: "/commerce-modules/pricing/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -781,10 +781,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/product/events", // path: "/commerce-modules/product/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -853,10 +853,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/promotion/events", // path: "/commerce-modules/promotion/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -909,10 +909,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/region/events", // path: "/commerce-modules/region/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -971,10 +971,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/sales-channel/events", // path: "/commerce-modules/sales-channel/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -1034,10 +1034,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/stock-location/events", // path: "/commerce-modules/stock-location/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -1090,10 +1090,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/store/events", // path: "/commerce-modules/store/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -1162,10 +1162,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/tax/events", // path: "/commerce-modules/tax/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -1222,10 +1222,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
}, },
], ],
}, },
{ // {
path: "/commerce-modules/user/events", // path: "/commerce-modules/user/events",
title: "Events Reference", // title: "Events Reference",
}, // },
], ],
}, },
], ],
@@ -2104,10 +2104,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([
path: "/medusa-container-resources", path: "/medusa-container-resources",
title: "Medusa Container Resources", title: "Medusa Container Resources",
}, },
{ // {
path: "/events-reference", // path: "/events-reference",
title: "Events", // title: "Events",
}, // },
{ {
path: "/admin-widget-injection-zones", path: "/admin-widget-injection-zones",
title: "Admin Widget Injection Zones", title: "Admin Widget Injection Zones",
-1
View File
@@ -9,4 +9,3 @@ NEXT_PUBLIC_SEGMENT_API_KEY=
NEXT_PUBLIC_AI_ASSISTANT_URL= NEXT_PUBLIC_AI_ASSISTANT_URL=
NEXT_PUBLIC_AI_WEBSITE_ID= NEXT_PUBLIC_AI_WEBSITE_ID=
NEXT_PUBLIC_AI_API_ASSISTANT_RECAPTCHA_SITE_KEY= NEXT_PUBLIC_AI_API_ASSISTANT_RECAPTCHA_SITE_KEY=
NEXT_PUBLIC_SHOW_V2=
+3 -10
View File
@@ -1,10 +1,5 @@
import { ArrowUpRightOnBox } from "@medusajs/icons" import { ArrowUpRightOnBox } from "@medusajs/icons"
import { import { NavbarItem, getNavbarItems, mobileSidebarItemsV1 } from "docs-ui"
NavbarItem,
getNavbarItems,
legacyMobileSidebarItems,
mobileSidebarItemsV1,
} from "docs-ui"
import { SidebarSectionItemsType } from "types" import { SidebarSectionItemsType } from "types"
import { siteConfig } from "./site" import { siteConfig } from "./site"
@@ -17,7 +12,7 @@ export const docsConfig: DocsConfig = {
mainNav: getNavbarItems({ mainNav: getNavbarItems({
basePath: siteConfig.baseUrl, basePath: siteConfig.baseUrl,
activePath: process.env.NEXT_PUBLIC_BASE_PATH || "/ui", activePath: process.env.NEXT_PUBLIC_BASE_PATH || "/ui",
version: process.env.NEXT_PUBLIC_SHOW_V2 ? "v1" : "legacy", version: "v1",
}), }),
sidebar: { sidebar: {
top: [ top: [
@@ -285,8 +280,6 @@ export const docsConfig: DocsConfig = {
], ],
}, },
], ],
mobile: process.env.NEXT_PUBLIC_SHOW_V2 mobile: mobileSidebarItemsV1,
? mobileSidebarItemsV1
: legacyMobileSidebarItems,
}, },
} }
+29 -123
View File
@@ -52,22 +52,23 @@ export const navbarItemsV1: NavbarItem[] = [
href: `/ui`, href: `/ui`,
}, },
}, },
{ // TODO enable them later
type: "divider", // {
}, // type: "divider",
{ // },
type: "link", // {
props: { // type: "link",
label: "Learn Medusa v2", // props: {
target: "_blank", // label: "Learn Medusa v2",
rel: "noreferrer", // target: "_blank",
href: `/v2`, // rel: "noreferrer",
badge: { // href: `/v2`,
variant: "blue", // badge: {
children: "New", // variant: "blue",
}, // children: "New",
}, // },
}, // },
// },
] ]
export const navbarItemsV2: NavbarItem[] = [ export const navbarItemsV2: NavbarItem[] = [
@@ -122,71 +123,10 @@ export const navbarItemsV2: NavbarItem[] = [
{ {
type: "link", type: "link",
props: { props: {
label: "Medusa V1", label: "Medusa v1",
target: "_blank", target: "_blank",
rel: "noreferrer", rel: "noreferrer",
href: `/`, href: `/`,
badge: {
variant: "neutral",
children: "v1",
},
},
},
]
export const legacyNavbarItems: NavbarItem[] = [
{
type: "link",
props: {
label: "Docs",
target: "_blank",
rel: "noreferrer",
href: `/`,
},
},
{
type: "link",
props: {
label: "Resources",
target: "_blank",
rel: "noreferrer",
href: `/resources`,
},
},
{
type: "link",
props: {
label: "User Guide",
target: "_blank",
rel: "noreferrer",
href: `/user-guide`,
},
},
{
type: "link",
props: {
label: "Store API",
target: "_blank",
rel: "noreferrer",
href: `/api/store`,
},
},
{
type: "link",
props: {
label: "Admin API",
target: "_blank",
rel: "noreferrer",
href: `/api/admin`,
},
},
{
type: "link",
props: {
label: "UI",
target: "_blank",
rel: "noreferrer",
href: `/ui`,
}, },
}, },
] ]
@@ -222,13 +162,13 @@ export const mobileSidebarItemsV1: SidebarItemType[] = [
loaded: true, loaded: true,
isPathHref: true, isPathHref: true,
}, },
{ // {
title: "Learn Medusa V2", // title: "Learn Medusa V2",
path: `/v2`, // path: `/v2`,
loaded: true, // loaded: true,
isPathHref: true, // isPathHref: true,
additionalElms: <Badge variant="blue">v2</Badge>, // additionalElms: <Badge variant="blue">v2</Badge>,
}, // },
] ]
export const mobileSidebarItemsV2: SidebarItemType[] = [ export const mobileSidebarItemsV2: SidebarItemType[] = [
@@ -263,51 +203,17 @@ export const mobileSidebarItemsV2: SidebarItemType[] = [
isPathHref: true, isPathHref: true,
}, },
{ {
title: "Docs", title: "Medusa v1",
path: `/`, path: `/`,
loaded: true, loaded: true,
isPathHref: true, isPathHref: true,
additionalElms: <Badge variant="neutral">v1</Badge>,
},
]
export const legacyMobileSidebarItems: SidebarItemType[] = [
{
title: "Docs",
path: `/`,
loaded: true,
isPathHref: true,
},
{
title: "User Guide",
path: `/user-guide`,
loaded: true,
isPathHref: true,
},
{
title: "Store API",
path: `/api/store`,
loaded: true,
isPathHref: true,
},
{
title: "Admin API",
path: `/api/admin`,
loaded: true,
isPathHref: true,
},
{
title: "UI",
path: `/ui`,
loaded: true,
isPathHref: true,
}, },
] ]
export const searchFiltersV2: OptionType[] = [ export const searchFiltersV2: OptionType[] = [
{ {
value: "book", value: "book",
label: "Docs V2", label: "Docs v2",
}, },
{ {
value: "resources", value: "resources",
@@ -315,11 +221,11 @@ export const searchFiltersV2: OptionType[] = [
}, },
{ {
value: "admin-v2", value: "admin-v2",
label: "Admin API", label: "Admin API (v2)",
}, },
{ {
value: "store-v2", value: "store-v2",
label: "Store API", label: "Store API (v2)",
}, },
// TODO add more filters // TODO add more filters
] ]
@@ -1,22 +1,17 @@
import { NavbarItem, legacyNavbarItems, navbarItemsV1, navbarItemsV2 } from ".." import { NavbarItem, navbarItemsV1, navbarItemsV2 } from ".."
type Options = { type Options = {
basePath: string basePath: string
activePath: string activePath: string
version?: "v1" | "v2" | "legacy" version?: "v1" | "v2"
} }
export function getNavbarItems({ export function getNavbarItems({
basePath, basePath,
activePath, activePath,
version = "legacy", version = "v1",
}: Options): NavbarItem[] { }: Options): NavbarItem[] {
const navbarItems = const navbarItems = version === "v2" ? navbarItemsV2 : navbarItemsV1
version === "v2"
? navbarItemsV2
: version === "v1"
? navbarItemsV1
: legacyNavbarItems
return navbarItems.map((item) => { return navbarItems.map((item) => {
if (item.type === "divider") { if (item.type === "divider") {
return item return item