docs: added restock notification guide (#10413)
* docs: added restock notification guide * changes * lint fixes * fixes * more changes * remove get email step * add og image * update sendRestockNotificationsWorkflow * updates * fix links
This commit is contained in:
@@ -182,14 +182,14 @@ export const serviceHighlights1 = [
|
||||
|
||||
```ts title="src/modules/resend/service.ts" highlights={serviceHighlights1}
|
||||
import {
|
||||
AbstractNotificationProviderService
|
||||
AbstractNotificationProviderService,
|
||||
} from "@medusajs/framework/utils"
|
||||
import {
|
||||
Logger
|
||||
} from "@medusajs/framework/types";
|
||||
Logger,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
Resend
|
||||
} from "resend";
|
||||
Resend,
|
||||
} from "resend"
|
||||
|
||||
type ResendOptions = {
|
||||
api_key: string
|
||||
@@ -263,7 +263,7 @@ So, add to the `ResendNotificationProviderService` the `validateOptions` method:
|
||||
// other imports...
|
||||
import {
|
||||
// other imports...
|
||||
MedusaError
|
||||
MedusaError,
|
||||
} from "@medusajs/framework/utils"
|
||||
|
||||
// ...
|
||||
@@ -397,7 +397,7 @@ class ResendNotificationProviderService extends AbstractNotificationProviderServ
|
||||
from: this.options.from,
|
||||
to: [notification.to],
|
||||
subject: this.getTemplateSubject(notification.template as Templates),
|
||||
html: ""
|
||||
html: "",
|
||||
}
|
||||
|
||||
if (typeof template === "string") {
|
||||
@@ -440,7 +440,7 @@ Create the file `src/modules/resend/index.ts` with the following content:
|
||||
```ts title="src/modules/resend/index.ts"
|
||||
import {
|
||||
ModuleProvider,
|
||||
Modules
|
||||
Modules,
|
||||
} from "@medusajs/framework/utils"
|
||||
import ResendNotificationProviderService from "./service"
|
||||
|
||||
@@ -562,7 +562,7 @@ function OrderPlacedEmailComponent({ order }: OrderPlacedEmailProps) {
|
||||
<Heading>Thank you for your order</Heading>
|
||||
{order.email}'s Items
|
||||
<Container>
|
||||
{order.items.map(item => {
|
||||
{order.items.map((item) => {
|
||||
return (
|
||||
<Section
|
||||
key={item.id}
|
||||
@@ -606,10 +606,10 @@ Next, update the `templates` variable in `src/modules/resend/service.ts` to assi
|
||||
|
||||
```ts title="src/modules/resend/service.ts"
|
||||
// other imports...
|
||||
import { orderPlacedEmail } from "./emails/order-placed";
|
||||
import { orderPlacedEmail } from "./emails/order-placed"
|
||||
|
||||
const templates: {[key in Templates]?: (props: unknown) => React.ReactNode} = {
|
||||
[Templates.ORDER_PLACED]: orderPlacedEmail
|
||||
[Templates.ORDER_PLACED]: orderPlacedEmail,
|
||||
}
|
||||
```
|
||||
|
||||
@@ -696,10 +696,10 @@ export const workflowHighlights = [
|
||||
```ts title="src/workflows/send-order-confirmation.ts" highlights={workflowHighlights}
|
||||
import {
|
||||
createWorkflow,
|
||||
WorkflowResponse
|
||||
} from "@medusajs/framework/workflows-sdk";
|
||||
import { useQueryGraphStep } from "@medusajs/medusa/core-flows";
|
||||
import { sendNotificationStep } from "./steps/send-notification";
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
|
||||
import { sendNotificationStep } from "./steps/send-notification"
|
||||
|
||||
type WorkflowInput = {
|
||||
id: string
|
||||
@@ -719,8 +719,8 @@ export const sendOrderConfirmationWorkflow = createWorkflow(
|
||||
"items.*",
|
||||
],
|
||||
filters: {
|
||||
id
|
||||
}
|
||||
id,
|
||||
},
|
||||
})
|
||||
|
||||
const notification = sendNotificationStep([{
|
||||
@@ -728,8 +728,8 @@ export const sendOrderConfirmationWorkflow = createWorkflow(
|
||||
channel: "email",
|
||||
template: "order-placed",
|
||||
data: {
|
||||
order: orders[0]
|
||||
}
|
||||
order: orders[0],
|
||||
},
|
||||
}])
|
||||
|
||||
return new WorkflowResponse(notification)
|
||||
@@ -787,8 +787,8 @@ export default async function orderPlacedHandler({
|
||||
await sendOrderConfirmationWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
id: data.id
|
||||
}
|
||||
id: data.id,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -19,371 +19,14 @@ Medusa provides the necessary architecture and tools to implement commerce autom
|
||||
|
||||
## Re-Stock Notifications
|
||||
|
||||
Customers may be interested in a product that is currently out of stock.
|
||||
|
||||
To implement sending restock notifications, you can:
|
||||
|
||||
- Create a module that manages the customers subscribed to a variant's restock notification.
|
||||
- Create relationships to the Product and Sales Channel modules. A variant's inventory is managed by the sales channel's associated stock locations.
|
||||
- Create an API route that allows customers to subscribe to a variant's restock notification.
|
||||
- Create a subscriber that listens to the `inventory-item.updated` event and sends a notification to the subscribed customers if the variant's quantity is more than `0`.
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
The `inventory-item.updated` event is currently not emitted.
|
||||
|
||||
</Note>
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "!docs!/learn/fundamentals/modules",
|
||||
title: "Create a Module",
|
||||
text: "Learn how to create a module in Medusa.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
{
|
||||
href: "!docs!/learn/fundamentals/modules#1-create-data-model",
|
||||
title: "Create a Data Model",
|
||||
text: "Learn how to create a data model.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "!docs!/learn/fundamentals/api-routes",
|
||||
title: "Create an API Route",
|
||||
text: "Learn how to create an API route in Medusa.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
{
|
||||
href: "!docs!/learn/fundamentals/events-and-subscribers",
|
||||
title: "Create a Subscriber",
|
||||
text: "Learn how to create a subscriber in Medusa.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} className="mt-1" />
|
||||
|
||||
<Details summaryContent="Example">
|
||||
|
||||
In this example, you'll create a Restock Notification Module with the features explained above.
|
||||
|
||||
### Create Restock Notification Module
|
||||
|
||||
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:
|
||||
|
||||
export const restockModelHighlights = [
|
||||
["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."],
|
||||
["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}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const RestockNotification = model.define("restock_notification", {
|
||||
id: model.id().primaryKey(),
|
||||
email: model.text(),
|
||||
variant_id: model.text(),
|
||||
sales_channel_id: model.text(),
|
||||
})
|
||||
|
||||
export default RestockNotification
|
||||
```
|
||||
|
||||
This creates a `RestockNotification` data model with the following properties:
|
||||
|
||||
- `id`: An automatically generated ID.
|
||||
- `email`: The email of the customer to send the notification to when the item is restocked.
|
||||
- `variant_id`: The ID of the variant the customer is subscribed to. This will later be used to form a relationship with the `ProductVariant` data model of the Product Module.
|
||||
- `sales_channel_id`: The ID of the sales channel the customer is viewing the product variant from. This will later be used to form a relationship with the `SalesChannel` data model of the Sales Channel Module.
|
||||
|
||||
Since a variant's inventory is managed based on the locations of each sales channel, you have to specify which sales channel to check stock quantity in.
|
||||
|
||||
Next, create the file `src/modules/restock-notification/migrations/Migration20240516140616.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/restock-notification/migrations/Migration20240516140616.ts"
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
|
||||
export class Migration20240516140616 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
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\"));")
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql("drop table if exists \"restock_notification\" cascade;")
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
You'll run the migration to reflect the changes on the database after finishing the module's definition.
|
||||
|
||||
Then, create the module's main service at `src/modules/restock-notification/service.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/restock-notification/service.ts"
|
||||
import { MedusaService } from "@medusajs/framework/utils"
|
||||
import RestockNotification from "./models/restock-notification"
|
||||
|
||||
class RestockNotificationModuleService extends MedusaService({
|
||||
RestockNotification,
|
||||
}){
|
||||
// TODO add custom methods
|
||||
}
|
||||
|
||||
export default RestockNotificationModuleService
|
||||
```
|
||||
|
||||
The module's main service extends the service factory which generates basic management features for the `RestockNotification` data model.
|
||||
|
||||
Next, create the module's definition file `src/modules/restock-notification/index.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/restock-notification/index.ts"
|
||||
import RestockNotificationModuleService from "./service"
|
||||
import { Module } from "@medusajs/framework/utils"
|
||||
|
||||
export default Module("restock-notification", {
|
||||
service: RestockNotificationModuleService,
|
||||
})
|
||||
```
|
||||
|
||||
Finally, add the module to the `modules` object in `medusa-config.ts`:
|
||||
|
||||
```ts title="medusa-config.ts"
|
||||
module.exports = defineConfig({
|
||||
// ...
|
||||
modules: [
|
||||
{
|
||||
resolve: "./src/modules/restock-notification",
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
You can now run the migrations with the following command:
|
||||
|
||||
```bash npm2yarn
|
||||
npx medusa db:migrate
|
||||
```
|
||||
|
||||
### Create Restock Notification API Route
|
||||
|
||||
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"
|
||||
import type {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/framework/http"
|
||||
import RestockNotificationModuleService
|
||||
from "../../../modules/restock-notification/service"
|
||||
|
||||
type RestockNotificationReq = {
|
||||
email: string
|
||||
variant_id: string
|
||||
sales_channel_id: string
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
req: MedusaRequest<RestockNotificationReq>,
|
||||
res: MedusaResponse
|
||||
) {
|
||||
const restockNotificationModuleService:
|
||||
RestockNotificationModuleService = req.scope.resolve(
|
||||
"restockNotificationModuleService"
|
||||
)
|
||||
|
||||
await restockNotificationModuleService.createRestockNotifications(
|
||||
req.body
|
||||
)
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
This creates a `POST` API route at `/store/restock-notification`. It accepts the `email`, `variant_id`, and `sales_channel_id` request body parameters and creates a restock notification.
|
||||
|
||||
### Create Inventory Item Updated Subscriber
|
||||
|
||||
To handle the sending of the restock notifications, create a subscriber that listens to the `inventory-item.updated` event, then sends a notification using the Notification Module to subscribed emails.
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
The `inventory-item.updated` event is currently not emitted.
|
||||
|
||||
</Note>
|
||||
|
||||
{/* To handle the sending of the restock notifications, create the file `src/subscribers/inventory-item-update.ts` with the following content: */}
|
||||
|
||||
export const subscriberHighlights = [
|
||||
["48", "inventoryVariantLinkService", "Retrieve an instance of the link service for the product-variant-inventory-item link module."],
|
||||
["55", "inventoryVariantItems", "Retrieve the variants linked to the updated inventory item."],
|
||||
["68", "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"
|
||||
import type {
|
||||
SubscriberArgs,
|
||||
SubscriberConfig,
|
||||
} from "@medusajs/framework"
|
||||
import {
|
||||
IInventoryService,
|
||||
INotificationModuleService,
|
||||
RemoteQueryFunction,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
Modules,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/framework/utils"
|
||||
import {
|
||||
RemoteLink,
|
||||
} from "@medusajs/framework/modules-sdk"
|
||||
import RestockNotificationModuleService
|
||||
from "../modules/restock-notification/service"
|
||||
|
||||
// subscriber function
|
||||
export default async function inventoryItemUpdateHandler({
|
||||
data,
|
||||
container,
|
||||
}: SubscriberArgs<{ id: string }>) {
|
||||
const remoteQuery: RemoteQueryFunction = container.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
const remoteLink: RemoteLink = container.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_LINK
|
||||
)
|
||||
const restockNotificationModuleService:
|
||||
RestockNotificationModuleService = container.resolve(
|
||||
"restockNotificationModuleService"
|
||||
)
|
||||
const inventoryModuleService: IInventoryService =
|
||||
container.resolve(Modules.INVENTORY)
|
||||
const notificationModuleService: INotificationModuleService =
|
||||
container.resolve(
|
||||
Modules.NOTIFICATION
|
||||
)
|
||||
|
||||
const inventoryItemId = data.data.id
|
||||
|
||||
const inventoryVariantLinkService = remoteLink.getLinkModule(
|
||||
Modules.PRODUCT,
|
||||
"variant_id",
|
||||
Modules.INVENTORY,
|
||||
"inventory_item_id"
|
||||
)
|
||||
|
||||
const inventoryVariantItems =
|
||||
await inventoryVariantLinkService.list({
|
||||
inventory_item_id: [inventoryItemId],
|
||||
}) as {
|
||||
variant_id: string,
|
||||
inventory_item_id: string
|
||||
}[]
|
||||
|
||||
if (!inventoryVariantItems.length) {
|
||||
console.log("no inventory variant items")
|
||||
return
|
||||
}
|
||||
|
||||
const restockQuery = remoteQueryObjectFromString({
|
||||
entryPoint: "restock_notification",
|
||||
fields: [
|
||||
"email",
|
||||
"variant.name",
|
||||
],
|
||||
variables: {
|
||||
filters: {
|
||||
variant_id: inventoryVariantItems[0].variant_id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const restockNotifications =
|
||||
await remoteQuery(restockQuery)
|
||||
|
||||
const salesChannelLocationService = remoteLink.getLinkModule(
|
||||
Modules.SALES_CHANNEL,
|
||||
"sales_channel_id",
|
||||
Modules.STOCK_LOCATION,
|
||||
"stock_location_id"
|
||||
)
|
||||
|
||||
for (const restockNotification of restockNotifications) {
|
||||
const salesChannelLocations =
|
||||
await salesChannelLocationService.list({
|
||||
sales_channel_id: [
|
||||
restockNotification.sales_channel_id,
|
||||
],
|
||||
}) as {
|
||||
stock_location_id: string
|
||||
sales_channel_id: string
|
||||
}[]
|
||||
|
||||
if (!salesChannelLocations.length) {
|
||||
continue
|
||||
}
|
||||
|
||||
const availableQuantity = await inventoryModuleService
|
||||
.retrieveAvailableQuantity(
|
||||
inventoryItemId,
|
||||
salesChannelLocations.map(
|
||||
(salesChannelLocation) =>
|
||||
salesChannelLocation.stock_location_id
|
||||
)
|
||||
)
|
||||
|
||||
if (availableQuantity === 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
notificationModuleService.createNotifications({
|
||||
to: restockNotification.email,
|
||||
channel: "email",
|
||||
template: "test_template",
|
||||
data: {
|
||||
variant_id: restockNotification.variant_id,
|
||||
variant_name: restockNotification.variant.title,
|
||||
// other data...
|
||||
},
|
||||
})
|
||||
|
||||
// delete the restock notification
|
||||
await restockNotificationModuleService
|
||||
.deleteRestockNotifications(restockNotification.id)
|
||||
}
|
||||
}
|
||||
|
||||
// subscriber config
|
||||
export const config: SubscriberConfig = {
|
||||
event: "inventory-item.updated",
|
||||
}
|
||||
```
|
||||
|
||||
This adds a subscriber to the `inventory-item.updated` event. In the subscriber handler function, you:
|
||||
|
||||
- Retrieve an instance of the link service for the product-variant-inventory-item link module.
|
||||
- Retrieve the variants linked to the updated inventory item.
|
||||
- Retrieve the restock notifications of those variants.
|
||||
- For each restock notification, you:
|
||||
- Retrieve its quantity based on the stock location associated with the restock notification's sales channel.
|
||||
- If the quantity is greater than `0`, you send a notification using the Notification Module and delete the restock notification. */}
|
||||
|
||||
</Details>
|
||||
Customers may be interested in a product that is currently out of stock. The following guide explains how to add restock notifications in your Medusa application:
|
||||
|
||||
<Card
|
||||
href="/recipes/commerce-automation/restock-notification"
|
||||
title="Restock Notification Guide"
|
||||
text="Learn how to implement restock notifications in the Medusa application."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
@@ -458,13 +101,13 @@ export const syncProductsWorkflowHighlight = [
|
||||
|
||||
```ts title="src/workflows/sync-products.ts" highlights={syncProductsWorkflowHighlight} collapsibleLines="1-16" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
Modules
|
||||
Modules,
|
||||
} from "@medusajs/framework/utils"
|
||||
import {
|
||||
IProductModuleService,
|
||||
IStoreModuleService,
|
||||
ProductDTO,
|
||||
StoreDTO
|
||||
StoreDTO,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
StepResponse,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -894,7 +894,7 @@ import {
|
||||
import { Modules, promiseAll } from "@medusajs/framework/utils"
|
||||
import {
|
||||
cancelOrderWorkflow,
|
||||
createOrderWorkflow
|
||||
createOrderWorkflow,
|
||||
} from "@medusajs/medusa/core-flows"
|
||||
import MarketplaceModuleService from "../../../../modules/marketplace/service"
|
||||
import { MARKETPLACE_MODULE } from "../../../../modules/marketplace"
|
||||
@@ -1010,9 +1010,9 @@ try {
|
||||
await promiseAll(
|
||||
vendorIds.map(async (vendorId) => {
|
||||
const items = vendorsItems[vendorId]
|
||||
const vendor = vendors.find(v => v.id === vendorId)!
|
||||
const vendor = vendors.find((v) => v.id === vendorId)!
|
||||
|
||||
const {result: childOrder} = await createOrderWorkflow(
|
||||
const { result: childOrder } = await createOrderWorkflow(
|
||||
container
|
||||
)
|
||||
.run({
|
||||
@@ -1025,11 +1025,11 @@ try {
|
||||
|
||||
linkDefs.push({
|
||||
[MARKETPLACE_MODULE]: {
|
||||
vendor_id: vendor.id
|
||||
vendor_id: vendor.id,
|
||||
},
|
||||
[Modules.ORDER]: {
|
||||
order_id: childOrder.id
|
||||
}
|
||||
order_id: childOrder.id,
|
||||
},
|
||||
})
|
||||
})
|
||||
)
|
||||
@@ -1037,7 +1037,7 @@ try {
|
||||
return StepResponse.permanentFailure(
|
||||
`An error occured while creating vendor orders: ${e}`,
|
||||
{
|
||||
created_orders: createdOrders
|
||||
created_orders: createdOrders,
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -1174,7 +1174,7 @@ const createVendorOrdersWorkflow = createWorkflow(
|
||||
})
|
||||
|
||||
const { vendorsItems } = groupVendorItemsStep({
|
||||
cart: carts[0]
|
||||
cart: carts[0],
|
||||
})
|
||||
|
||||
const order = getOrderDetailWorkflow.runAsStep({
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ export const fetchHighlights = [
|
||||
const searchParams = new URLSearchParams({
|
||||
fields: "category_children.id,category_children.name",
|
||||
include_descendants_tree: true,
|
||||
parent_category_id: null
|
||||
parent_category_id: null,
|
||||
})
|
||||
|
||||
fetch(`http://localhost:9000/store/product-categories/${id}?${
|
||||
@@ -84,7 +84,7 @@ export const highlights = [
|
||||
|
||||
const searchParams = new URLSearchParams({
|
||||
fields: "category_children.id,category_children.name",
|
||||
parent_category_id: null
|
||||
parent_category_id: null,
|
||||
})
|
||||
|
||||
fetch(`http://localhost:9000/store/product-categories/${id}?${
|
||||
|
||||
@@ -5659,5 +5659,6 @@ export const generatedEditDates = {
|
||||
"references/workflows/classes/workflows.WorkflowResponse/page.mdx": "2024-12-09T13:22:04.820Z",
|
||||
"references/workflows/interfaces/workflows.ApplyStepOptions/page.mdx": "2024-12-09T13:22:04.808Z",
|
||||
"references/workflows/types/workflows.WorkflowData/page.mdx": "2024-12-09T13:22:04.836Z",
|
||||
"app/integrations/guides/resend/page.mdx": "2024-12-09T16:19:17.798Z"
|
||||
"app/integrations/guides/resend/page.mdx": "2024-12-09T16:19:17.798Z",
|
||||
"app/recipes/commerce-automation/restock-notification/page.mdx": "2024-12-10T14:15:39.178Z"
|
||||
}
|
||||
@@ -667,6 +667,10 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/recipes/commerce-automation/page.mdx",
|
||||
"pathname": "/recipes/commerce-automation"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/recipes/commerce-automation/restock-notification/page.mdx",
|
||||
"pathname": "/recipes/commerce-automation/restock-notification"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/recipes/digital-products/examples/standard/page.mdx",
|
||||
"pathname": "/recipes/digital-products/examples/standard"
|
||||
|
||||
@@ -96,7 +96,16 @@ export const generatedSidebar = [
|
||||
"type": "link",
|
||||
"path": "/recipes/commerce-automation",
|
||||
"title": "Commerce Automation",
|
||||
"children": []
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"type": "link",
|
||||
"path": "/recipes/commerce-automation/restock-notification",
|
||||
"title": "Example: Restock Notifications",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
|
||||
@@ -68,6 +68,13 @@ export const sidebar = sidebarAttachHrefCommonOptions([
|
||||
type: "link",
|
||||
path: "/recipes/commerce-automation",
|
||||
title: "Commerce Automation",
|
||||
children: [
|
||||
{
|
||||
type: "link",
|
||||
path: "/recipes/commerce-automation/restock-notification",
|
||||
title: "Example: Restock Notifications",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
|
||||
@@ -17,8 +17,8 @@ export const WorkflowDiagramCanvasDepth = ({
|
||||
return (
|
||||
<div className="flex items-start">
|
||||
<div className="flex flex-col justify-center gap-y-docs_0.5">
|
||||
{cluster.map((step) => (
|
||||
<WorkflowDiagramStepNode key={step.name} step={step} />
|
||||
{cluster.map((step, index) => (
|
||||
<WorkflowDiagramStepNode key={`${step.name}-${index}`} step={step} />
|
||||
))}
|
||||
</div>
|
||||
<WorkflowDiagramLine step={next} />
|
||||
|
||||
@@ -17,8 +17,8 @@ export const WorkflowDiagramDepth = ({
|
||||
return (
|
||||
<div className="flex items-start">
|
||||
<div className="flex flex-col justify-center gap-y-docs_0.5">
|
||||
{cluster.map((step) => (
|
||||
<WorkflowDiagramStepNode key={step.name} step={step} />
|
||||
{cluster.map((step, index) => (
|
||||
<WorkflowDiagramStepNode key={`${step.name}-${index}`} step={step} />
|
||||
))}
|
||||
</div>
|
||||
<WorkflowDiagramLine step={next} />
|
||||
|
||||
@@ -17,8 +17,8 @@ export const WorkflowDiagramListDepth = ({
|
||||
<div className="flex items-start">
|
||||
<WorkflowDiagramLine step={cluster} />
|
||||
<div className="flex flex-col justify-center gap-y-docs_0.5">
|
||||
{cluster.map((step) => (
|
||||
<WorkflowDiagramStepNode key={step.name} step={step} />
|
||||
{cluster.map((step, index) => (
|
||||
<WorkflowDiagramStepNode key={`${step.name}-${index}`} step={step} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user