docs: update docusaurus to v3 (#5625)

* update dependencies

* update onboarding mdx

* fixes for mdx issues

* fixes for mdx compatibility

* resolve mdx errors

* fixes in reference

* fix check errors

* revert change in vale action

* fix node version in action

* fix summary in markdown
This commit is contained in:
Shahed Nasser
2023-11-13 20:11:50 +02:00
committed by GitHub
parent cedab58339
commit c6dff873de
2265 changed files with 46163 additions and 47195 deletions
+47 -49
View File
@@ -266,62 +266,60 @@ Medusa allows you to create custom API Routes exposed as REST APIs.
}
}} />
<details>
<summary>
Example Implementation
</summary>
<Details>
<Summary>Example Implementation</Summary>
For example, create the following API Route that allows you to check the customers group and whether it has the `is_b2b` flag enabled:
For example, create the following API Route that allows you to check the customers group and whether it has the `is_b2b` flag enabled:
```ts title=src/api/store/customers/is-b2b/route.ts
import type {
CustomerService,
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
const customerService: CustomerService = req.scope.resolve(
"customerService"
)
const customer = await customerService
.retrieve(req.user.customer_id, {
relations: ["groups"],
})
const is_b2b = customer.groups.some(
(group) => group.metadata.is_b2b === "true"
)
```ts title=src/api/store/customers/is-b2b/route.ts
import type {
CustomerService,
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
const customerService: CustomerService = req.scope.resolve(
"customerService"
)
const customer = await customerService
.retrieve(req.user.customer_id, {
relations: ["groups"],
return res.json({
is_b2b,
})
}
```
const is_b2b = customer.groups.some(
(group) => group.metadata.is_b2b === "true"
)
return res.json({
is_b2b,
})
}
```
Then add the `requireCustomerAuthentication` middleware in `src/api/middlewares.ts` that ensures only authenticated customer can access this API Route:
Then add the `requireCustomerAuthentication` middleware in `src/api/middlewares.ts` that ensures only authenticated customer can access this API Route:
```ts title=src/api/middlewares.ts
import {
requireCustomerAuthentication,
type MiddlewaresConfig,
} from "@medusajs/medusa"
```ts title=src/api/middlewares.ts
import {
requireCustomerAuthentication,
type MiddlewaresConfig,
} from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/store/customers/is-b2b",
middlewares: [requireCustomerAuthentication()],
},
],
}
```
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/store/customers/is-b2b",
middlewares: [requireCustomerAuthentication()],
},
],
}
```
</details>
</Details>
---
@@ -100,85 +100,83 @@ Medusa also provides official notification plugins that integrate with third-par
},
]} />
<details>
<summary>
Example: Sending an email for new notes
</summary>
Heres an example of a subscriber that uses the SendGrid plugin to send an email to the customer when the order has a new note:
<Details>
<Summary>Example: Sending an email for new notes</Summary>
```ts title=src/subscribers/new-note.ts
import {
EventBusService,
NoteService,
OrderService,
} from "@medusajs/medusa"
Heres an example of a subscriber that uses the SendGrid plugin to send an email to the customer when the order has a new note:
type InjectedDependencies = {
eventBusService: EventBusService
sendgridService: any
noteService: NoteService
orderService: OrderService
}
```ts title=src/subscribers/new-note.ts
import {
EventBusService,
NoteService,
OrderService,
} from "@medusajs/medusa"
class NewNoteSubscriber {
protected sendGridService_: any
protected noteService_: NoteService
protected orderService_: OrderService
constructor({
eventBusService,
sendgridService,
noteService,
orderService,
}: InjectedDependencies) {
this.noteService_ = noteService
this.orderService_ = orderService
this.sendGridService_ = sendgridService
eventBusService.subscribe(
"note.created",
this.handleNoteCreated
)
type InjectedDependencies = {
eventBusService: EventBusService
sendgridService: any
noteService: NoteService
orderService: OrderService
}
handleNoteCreated = async (data) => {
// retrieve note by id
const note = await this.noteService_.retrieve(data.id, {
relations: ["author"],
})
class NewNoteSubscriber {
protected sendGridService_: any
protected noteService_: NoteService
protected orderService_: OrderService
if (!note || note.resource_type !== "order") {
return
constructor({
eventBusService,
sendgridService,
noteService,
orderService,
}: InjectedDependencies) {
this.noteService_ = noteService
this.orderService_ = orderService
this.sendGridService_ = sendgridService
eventBusService.subscribe(
"note.created",
this.handleNoteCreated
)
}
// retrieve note's order
const order = await this.orderService_.retrieve(
note.resource_id
)
handleNoteCreated = async (data) => {
// retrieve note by id
const note = await this.noteService_.retrieve(data.id, {
relations: ["author"],
})
if (!order) {
return
if (!note || note.resource_type !== "order") {
return
}
// retrieve note's order
const order = await this.orderService_.retrieve(
note.resource_id
)
if (!order) {
return
}
this.sendGridService_.sendEmail({
templateId: "order-update",
from: "hello@medusajs.com",
to: order.email,
dynamic_template_data: {
// any data necessary for your template...
note_text: note.value,
note_author: note.author.first_name,
note_date: note.created_at,
order_id: order.display_id,
},
})
}
this.sendGridService_.sendEmail({
templateId: "order-update",
from: "hello@medusajs.com",
to: order.email,
dynamic_template_data: {
// any data necessary for your template...
note_text: note.value,
note_author: note.author.first_name,
note_date: note.created_at,
order_id: order.display_id,
},
})
}
}
export default NewNoteSubscriber
```
export default NewNoteSubscriber
```
</details>
</Details>
---
@@ -198,75 +196,73 @@ You can implement automatic synchronization in Medusa using scheduled jobs. A sc
}
}} />
<details>
<summary>
Example: Synchronizing products with a third-party service
</summary>
<Details>
<Summary>Example: Synchronizing products with a third-party service</Summary>
Heres an example of synchronizing products with a third party service using a [loader](../development/loaders/create.md):
Heres an example of synchronizing products with a third party service using a [loader](../development/loaders/create.md):
```ts title=src/loaders/sync-products.ts
import {
Logger,
ProductService,
StoreService,
} from "@medusajs/medusa"
import {
ProductSelector,
} from "@medusajs/medusa/dist/types/product"
import { AwilixContainer } from "awilix"
```ts title=src/loaders/sync-products.ts
import {
Logger,
ProductService,
StoreService,
} from "@medusajs/medusa"
import {
ProductSelector,
} from "@medusajs/medusa/dist/types/product"
import { AwilixContainer } from "awilix"
export default async (
container: AwilixContainer,
config: Record<string, unknown>
): Promise<void> => {
const logger = container.resolve<Logger>("logger")
logger.info("Synchronizing products...")
const productService = container.resolve<ProductService>(
"productService"
)
const storeService = container.resolve<StoreService>(
"storeService"
)
// retrieve store to get last sync date
const store = await storeService.retrieve()
export default async (
container: AwilixContainer,
config: Record<string, unknown>
): Promise<void> => {
const logger = container.resolve<Logger>("logger")
logger.info("Synchronizing products...")
const productService = container.resolve<ProductService>(
"productService"
)
const storeService = container.resolve<StoreService>(
"storeService"
)
// retrieve store to get last sync date
const store = await storeService.retrieve()
const productFilters: ProductSelector = {}
const productFilters: ProductSelector = {}
if (store.metadata.last_sync_date) {
productFilters.updated_at = {
gt: new Date(
store.metadata.last_sync_date as string
),
if (store.metadata.last_sync_date) {
productFilters.updated_at = {
gt: new Date(
store.metadata.last_sync_date as string
),
}
}
const updatedProducts = await productService.list(
productFilters
)
updatedProducts.forEach((product) => {
// assuming client is an initialized connection
// with a third-party service
client.sync(product)
})
await storeService.update({
metadata: {
last_sync_date: new Date(),
},
})
logger.info("Finish synchronizing products")
}
```
const updatedProducts = await productService.list(
productFilters
)
updatedProducts.forEach((product) => {
// assuming client is an initialized connection
// with a third-party service
client.sync(product)
})
Notice that here its assumed that:
await storeService.update({
metadata: {
last_sync_date: new Date(),
},
})
logger.info("Finish synchronizing products")
}
```
1. The last update date is stored in the `Store`'s metadata object. You can instead use a custom entity to handle this.
2. The connection to the third-party service is assumed to be available and handled within the `client` variable.
Notice that here its assumed that:
1. The last update date is stored in the `Store`'s metadata object. You can instead use a custom entity to handle this.
2. The connection to the third-party service is assumed to be available and handled within the `client` variable.
</details>
</Details>
---
@@ -419,88 +415,86 @@ For example, if you're grouping customers with over twenty orders, you can use a
},
]} />
<details>
<summary>
Example: Add customer to VIP group
</summary>
<Details>
<Summary>Example: Add customer to VIP group</Summary>
Heres an example of a subscriber that listens to the `order.placed` event and checks if the customer should be added to the VIP customer group based on their number of orders:
Heres an example of a subscriber that listens to the `order.placed` event and checks if the customer should be added to the VIP customer group based on their number of orders:
```ts title=src/subscribers/add-custom-to-vip.ts
import {
CustomerGroupService,
CustomerService,
EventBusService,
OrderService,
} from "@medusajs/medusa"
```ts title=src/subscribers/add-custom-to-vip.ts
import {
CustomerGroupService,
CustomerService,
EventBusService,
OrderService,
} from "@medusajs/medusa"
type InjectedDependencies = {
orderService: OrderService
customerService: CustomerService
customerGroupService: CustomerGroupService
eventBusService: EventBusService
}
class AddCustomerToVipSubscriber {
protected orderService_: OrderService
protected customerService_: CustomerService
protected customerGroupService_: CustomerGroupService
constructor({
orderService,
customerService,
customerGroupService,
eventBusService,
}: InjectedDependencies) {
this.orderService_ = orderService
this.customerService_ = customerService
this.customerGroupService_ = customerGroupService
eventBusService.subscribe(
"order.placed",
this.handleOrderPlaced
)
type InjectedDependencies = {
orderService: OrderService
customerService: CustomerService
customerGroupService: CustomerGroupService
eventBusService: EventBusService
}
handleOrderPlaced = async ({ id }) => {
// check if VIP group exists
const vipGroup = await this.customerGroupService_.list({
name: "VIP",
}, {
relations: ["customers"],
})
if (!vipGroup.length) {
return
}
class AddCustomerToVipSubscriber {
protected orderService_: OrderService
protected customerService_: CustomerService
protected customerGroupService_: CustomerGroupService
// retrieve order and its customer
const order = await this.orderService_.retrieve(id)
if (!order || !order.customer_id ||
vipGroup[0].customers.find(
(customer) => customer.id === order.customer_id
) !== undefined) {
return
}
// retrieve orders of this customer
const [, count] = await this.orderService_.listAndCount({
customer_id: order.customer_id,
})
if (count >= 20) {
// add customer to VIP group
this.customerGroupService_.addCustomers(
vipGroup[0].id,
order.customer_id
constructor({
orderService,
customerService,
customerGroupService,
eventBusService,
}: InjectedDependencies) {
this.orderService_ = orderService
this.customerService_ = customerService
this.customerGroupService_ = customerGroupService
eventBusService.subscribe(
"order.placed",
this.handleOrderPlaced
)
}
handleOrderPlaced = async ({ id }) => {
// check if VIP group exists
const vipGroup = await this.customerGroupService_.list({
name: "VIP",
}, {
relations: ["customers"],
})
if (!vipGroup.length) {
return
}
// retrieve order and its customer
const order = await this.orderService_.retrieve(id)
if (!order || !order.customer_id ||
vipGroup[0].customers.find(
(customer) => customer.id === order.customer_id
) !== undefined) {
return
}
// retrieve orders of this customer
const [, count] = await this.orderService_.listAndCount({
customer_id: order.customer_id,
})
if (count >= 20) {
// add customer to VIP group
this.customerGroupService_.addCustomers(
vipGroup[0].id,
order.customer_id
)
}
}
}
}
export default AddCustomerToVipSubscriber
```
export default AddCustomerToVipSubscriber
```
</details>
</Details>
---
@@ -543,105 +537,103 @@ You can alternatively have a Scheduled Job that checks if the number of new prod
},
]} />
<details>
<summary>
Example: Sending a newsletter email after adding ten products
</summary>
<Details>
<Summary>Example: Sending a newsletter email after adding ten products</Summary>
Heres an example of listening to the `product.created` event in a subscriber and send a newsletter if the condition is met:
Heres an example of listening to the `product.created` event in a subscriber and send a newsletter if the condition is met:
```ts title=src/subscribers/send-products-newsletter.ts
import {
CustomerService,
EventBusService,
NoteService,
OrderService,
ProductService,
StoreService,
} from "@medusajs/medusa"
import {
ProductSelector,
} from "@medusajs/medusa/dist/types/product"
```ts title=src/subscribers/send-products-newsletter.ts
import {
CustomerService,
EventBusService,
NoteService,
OrderService,
ProductService,
StoreService,
} from "@medusajs/medusa"
import {
ProductSelector,
} from "@medusajs/medusa/dist/types/product"
type InjectedDependencies = {
eventBusService: EventBusService
sendgridService: any
productService: ProductService
storeService: StoreService
customerService: CustomerService
}
class SendProductsNewsletterSubscriber {
protected sendGridService_: any
protected productService_: ProductService
protected storeService_: StoreService
protected customerService_: CustomerService
constructor({
eventBusService,
sendgridService,
productService,
storeService,
customerService,
}: InjectedDependencies) {
this.productService_ = productService
this.sendGridService_ = sendgridService
this.storeService_ = storeService
this.customerService_ = customerService
eventBusService.subscribe(
"product.created",
this.handleProductCreated
)
type InjectedDependencies = {
eventBusService: EventBusService
sendgridService: any
productService: ProductService
storeService: StoreService
customerService: CustomerService
}
handleProductCreated = async ({ id }) => {
// retrieve store to have access to last send date
const store = await this.storeService_.retrieve()
const productFilters: ProductSelector = {}
if (store.metadata.last_send_date) {
productFilters.created_at = {
gt: new Date(store.metadata.last_send_date as string),
class SendProductsNewsletterSubscriber {
protected sendGridService_: any
protected productService_: ProductService
protected storeService_: StoreService
protected customerService_: CustomerService
constructor({
eventBusService,
sendgridService,
productService,
storeService,
customerService,
}: InjectedDependencies) {
this.productService_ = productService
this.sendGridService_ = sendgridService
this.storeService_ = storeService
this.customerService_ = customerService
eventBusService.subscribe(
"product.created",
this.handleProductCreated
)
}
handleProductCreated = async ({ id }) => {
// retrieve store to have access to last send date
const store = await this.storeService_.retrieve()
const productFilters: ProductSelector = {}
if (store.metadata.last_send_date) {
productFilters.created_at = {
gt: new Date(store.metadata.last_send_date as string),
}
}
const products = await this.productService_.list(
productFilters
)
if (products.length > 10) {
// get subscribed customers
const customers = await this.customerService_.list({
metadata: {
is_subscribed: true,
},
})
this.sendGridService_.sendEmail({
templateId: "product-newsletter",
from: "hello@medusajs.com",
to: customers.map((customer) => ({
name: customer.first_name,
email: customer.email,
})),
dynamic_template_data: {
// any data necessary for your template...
products,
},
})
await this.storeService_.update({
metadata: {
last_send_date: new Date(),
},
})
}
}
const products = await this.productService_.list(
productFilters
)
if (products.length > 10) {
// get subscribed customers
const customers = await this.customerService_.list({
metadata: {
is_subscribed: true,
},
})
this.sendGridService_.sendEmail({
templateId: "product-newsletter",
from: "hello@medusajs.com",
to: customers.map((customer) => ({
name: customer.first_name,
email: customer.email,
})),
dynamic_template_data: {
// any data necessary for your template...
products,
},
})
await this.storeService_.update({
metadata: {
last_send_date: new Date(),
},
})
}
}
}
export default SendProductsNewsletterSubscriber
```
export default SendProductsNewsletterSubscriber
```
</details>
</Details>
---
File diff suppressed because it is too large Load Diff
+154 -152
View File
@@ -41,105 +41,105 @@ To associate these entities with the `Store` entity, you need to extend and cust
}
}} />
<details>
<summary>Example: Associate User with Store</summary>
<Details>
<Summary>Example: Associate User with Store</Summary>
For example, to associate the `User` entity with the `Store` entity, create the file `src/models/user.ts` with the following content:
For example, to associate the `User` entity with the `Store` entity, create the file `src/models/user.ts` with the following content:
```ts title=src/models/user.ts
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
} from "typeorm"
import {
User as MedusaUser,
} from "@medusajs/medusa"
import { Store } from "./store"
```ts title=src/models/user.ts
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
} from "typeorm"
import {
User as MedusaUser,
} from "@medusajs/medusa"
import { Store } from "./store"
@Entity()
export class User extends MedusaUser {
@Index("UserStoreId")
@Column({ nullable: true })
store_id?: string
@Entity()
export class User extends MedusaUser {
@Index("UserStoreId")
@Column({ nullable: true })
store_id?: string
@ManyToOne(() => Store, (store) => store.members)
@JoinColumn({ name: "store_id", referencedColumnName: "id" })
store?: Store
}
```
@ManyToOne(() => Store, (store) => store.members)
@JoinColumn({ name: "store_id", referencedColumnName: "id" })
store?: Store
}
```
Then, you need to extend the `UserRepository` to point to your extended entity. To do that, create the file `src/repositories/user.ts` with the following content:
Then, you need to extend the `UserRepository` to point to your extended entity. To do that, create the file `src/repositories/user.ts` with the following content:
```ts title=src/repositories/user.ts
import { User } from "../models/user"
import {
dataSource,
} from "@medusajs/medusa/dist/loaders/database"
import {
UserRepository as MedusaUserRepository,
} from "@medusajs/medusa/dist/repositories/user"
```ts title=src/repositories/user.ts
import { User } from "../models/user"
import {
dataSource,
} from "@medusajs/medusa/dist/loaders/database"
import {
UserRepository as MedusaUserRepository,
} from "@medusajs/medusa/dist/repositories/user"
export const UserRepository = dataSource
.getRepository(User)
.extend({
...Object.assign(
MedusaUserRepository,
{ target: User }
),
})
export const UserRepository = dataSource
.getRepository(User)
.extend({
...Object.assign(
MedusaUserRepository,
{ target: User }
),
})
export default UserRepository
```
export default UserRepository
```
Next, you need to create a migration that reflects the changes on the `User` entity in your database. To do that, run the following command to create a migration file:
Next, you need to create a migration that reflects the changes on the `User` entity in your database. To do that, run the following command to create a migration file:
```bash
npx typeorm migration:create src/migrations/add-user-store-id
```
```bash
npx typeorm migration:create src/migrations/add-user-store-id
```
This creates a file in the `src/migrations` directory of the format `<TIMESTAMP>_add-user-store-id.ts`. Replace the `up` and `down` methods in that file with the methods here:
This creates a file in the `src/migrations` directory of the format `<TIMESTAMP>_add-user-store-id.ts`. Replace the `up` and `down` methods in that file with the methods here:
```ts title=src/migrations/<TIMESTAMP>_add-user-store-id.ts
// ...
```ts title=src/migrations/<TIMESTAMP>_add-user-store-id.ts
// ...
export class AddUserStoreId1681287255173
implements MigrationInterface {
// ...
export class AddUserStoreId1681287255173
implements MigrationInterface {
// ...
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "user" ADD "store_id" character varying`
)
await queryRunner.query(
`CREATE INDEX "UserStoreId" ON "user" ("store_id")`
)
}
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "user" ADD "store_id" character varying`
)
await queryRunner.query(
`CREATE INDEX "UserStoreId" ON "user" ("store_id")`
)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX "public"."UserStoreId"`
)
await queryRunner.query(
`ALTER TABLE "user" DROP COLUMN "store_id"`
)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX "public"."UserStoreId"`
)
await queryRunner.query(
`ALTER TABLE "user" DROP COLUMN "store_id"`
)
}
}
```
}
```
Finally, to reflect these changes and start using them, `build` your changes and run migrations with the following commands:
Finally, to reflect these changes and start using them, `build` your changes and run migrations with the following commands:
```bash npm2yarn
npm run build
npx medusa migrations run
```
```bash npm2yarn
npm run build
npx medusa migrations run
```
You can extend other entities in a similar manner to associate them with a store.
You can extend other entities in a similar manner to associate them with a store.
</details>
</Details>
---
@@ -179,75 +179,76 @@ You can also extend services if you need to customize a functionality implemente
}
}} />
<details>
<summary>Example: Extend User Service</summary>
<Details>
<Summary>Example: Extend User Service</Summary>
You can extend the user service to change how the `create` method is implemented.
You can extend the user service to change how the `create` method is implemented.
To extend the user service, create the file `src/services/user.ts` with the following content:
To extend the user service, create the file `src/services/user.ts` with the following content:
<!-- eslint-disable prefer-rest-params -->
```ts title=src/services/user.ts
import { Lifetime } from "awilix"
import {
UserService as MedusaUserService,
} from "@medusajs/medusa"
import { User } from "../models/user"
import {
CreateUserInput as MedusaCreateUserInput,
} from "@medusajs/medusa/dist/types/user"
import StoreRepository from "../repositories/store"
```ts title=src/services/user.ts
import { Lifetime } from "awilix"
import {
UserService as MedusaUserService,
} from "@medusajs/medusa"
import { User } from "../models/user"
import {
CreateUserInput as MedusaCreateUserInput,
} from "@medusajs/medusa/dist/types/user"
import StoreRepository from "../repositories/store"
type CreateUserInput = {
store_id?: string
} & MedusaCreateUserInput
type CreateUserInput = {
store_id?: string
} & MedusaCreateUserInput
class UserService extends MedusaUserService {
static LIFE_TIME = Lifetime.SCOPED
protected readonly loggedInUser_: User | null
protected readonly storeRepository_: typeof StoreRepository
class UserService extends MedusaUserService {
static LIFE_TIME = Lifetime.SCOPED
protected readonly loggedInUser_: User | null
protected readonly storeRepository_: typeof StoreRepository
constructor(container, options) {
super(...arguments)
this.storeRepository_ = container.storeRepository
constructor(container, options) {
super(...arguments)
this.storeRepository_ = container.storeRepository
try {
this.loggedInUser_ = container.loggedInUser
} catch (e) {
// avoid errors when backend first runs
try {
this.loggedInUser_ = container.loggedInUser
} catch (e) {
// avoid errors when backend first runs
}
}
async create(
user: CreateUserInput,
password: string
): Promise<User> {
if (!user.store_id) {
const storeRepo = this.manager_.withRepository(
this.storeRepository_
)
let newStore = storeRepo.create()
newStore = await storeRepo.save(newStore)
user.store_id = newStore.id
}
return await super.create(user, password)
}
}
async create(
user: CreateUserInput,
password: string
): Promise<User> {
if (!user.store_id) {
const storeRepo = this.manager_.withRepository(
this.storeRepository_
)
let newStore = storeRepo.create()
newStore = await storeRepo.save(newStore)
user.store_id = newStore.id
}
export default UserService
```
return await super.create(user, password)
}
}
In the `create` method of this extended service, you create a new store if the user being created doesn't have a store associated with it.
export default UserService
```
You can then test out your customization by running the `build` command and starting the backend:
In the `create` method of this extended service, you create a new store if the user being created doesn't have a store associated with it.
```bash
npm run build
npx medusa develop
```
You can then test out your customization by running the `build` command and starting the backend:
```bash
npm run build
npx medusa develop
```
</details>
</Details>
---
@@ -267,34 +268,35 @@ To listen to events, you need to create Subscribers that subscribe a handler met
}
}} />
<details>
<summary>Example: Listen to Order Created Event</summary>
<Details>
<Summary>Example: Listen to Order Created Event</Summary>
To listen to the `order.placed` event, create the file `src/subscribers/orderNotifier.ts` with the following content:
To listen to the `order.placed` event, create the file `src/subscribers/orderNotifier.ts` with the following content:
```ts title=src/subscribers/orderNotifier.ts
class OrderNotifierSubscriber {
constructor({ eventBusService }) {
eventBusService.subscribe("order.placed", this.handleOrder)
```ts title=src/subscribers/orderNotifier.ts
class OrderNotifierSubscriber {
constructor({ eventBusService }) {
eventBusService.subscribe("order.placed", this.handleOrder)
}
handleOrder = async (data) => {
// TODO perform functionality
}
}
handleOrder = async (data) => {
// TODO perform functionality
}
}
export default OrderNotifierSubscriber
```
export default OrderNotifierSubscriber
```
This subscribes the `handleOrder` method to be executed whenever the `order.placed` event is emitted.
This subscribes the `handleOrder` method to be executed whenever the `order.placed` event is emitted.
You can then test out your subscriber by running the `build` command and starting the backend:
You can then test out your subscriber by running the `build` command and starting the backend:
```bash
npm run build
npx medusa develop
```
```bash
npm run build
npx medusa develop
```
</details>
</Details>
---
+36 -38
View File
@@ -94,50 +94,48 @@ To search through product variants by their barcode, you can create a custom API
},
]} />
<details>
<summary>
Example: Search Products By Barcode API Route
</summary>
<Details>
<Summary>Example: Search Products By Barcode API Route</Summary>
Heres an example of creating a custom API Route at `/store/pos/search-barcode` that searches product variants by a barcode:
Heres an example of creating a custom API Route at `/store/pos/search-barcode` that searches product variants by a barcode:
```ts title=src/api/store/pos/search-barcode/route.ts
import type {
MedusaRequest,
MedusaResponse,
ProductVariantService,
} from "@medusajs/medusa"
import { MedusaError } from "@medusajs/utils"
```ts title=src/api/store/pos/search-barcode/route.ts
import type {
MedusaRequest,
MedusaResponse,
ProductVariantService,
} from "@medusajs/medusa"
import { MedusaError } from "@medusajs/utils"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
const barcode = (req.query.barcode as string) || ""
if (!barcode) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Barcode is required"
)
}
// get product service
const productVariantService = req.scope.resolve<
ProductVariantService
>("productVariantService")
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
const barcode = (req.query.barcode as string) || ""
if (!barcode) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Barcode is required"
)
}
// get product service
const productVariantService = req.scope.resolve<
ProductVariantService
>("productVariantService")
// retrieve product variants by barcode
const productVariants = await productVariantService
.list({
barcode,
// retrieve product variants by barcode
const productVariants = await productVariantService
.list({
barcode,
})
res.json({
product_variants: productVariants,
})
}
```
res.json({
product_variants: productVariants,
})
}
```
</details>
</Details>
---