@mercurjs/docs 2.3.7 → 2.3.8-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,7 @@ This reference lists the workflows for the Offer domain. Import them from
12
12
  | Workflow | Input | Purpose |
13
13
  | --- | --- | --- |
14
14
  | `createOffersWorkflow` | `{ offers[], additional_data? }` | Create offers with prices, inventory, and links |
15
- | `updateOffersWorkflow` | `{ offers[], additional_data? }` | Update offer rows and rewrite their price ladders |
15
+ | `updateOffersWorkflow` | `{ offers[], updated_by?, additional_data? }` | Update offer rows and rewrite their price ladders |
16
16
  | `deleteOffersWorkflow` | `{ ids[], additional_data? }` | Delete offers |
17
17
  | `batchOfferInventoryItemsWorkflow` | `{ offer_id, create?, update?, delete?, additional_data? }` | Add, update, and detach an offer's inventory-item links |
18
18
 
@@ -24,9 +24,37 @@ Each workflow exposes hooks so you can extend it without forking:
24
24
  | --- | --- |
25
25
  | `createOffersWorkflow` | `validate`, `offersCreated` |
26
26
  | `updateOffersWorkflow` | `validate`, `offersUpdated` |
27
+ | `upsertOfferPricesWorkflow` | `offerPricesUpserted` |
27
28
  | `deleteOffersWorkflow` | `offersDeleted` |
28
29
  | `batchOfferInventoryItemsWorkflow` | `validate`, `offerInventoryItemsBatched` |
29
30
 
31
+ ### Hook payloads
32
+
33
+ | Hook | Payload |
34
+ | --- | --- |
35
+ | `offersCreated` | `{ offers: OfferDTO[], additional_data? }` — each offer carries `created_by` and its `prices` |
36
+ | `offersUpdated` | `{ offers: OfferDTO[], previous_offers: OfferDTO[], updated_by?, additional_data? }` — `previous_offers` is the row state before the write |
37
+ | `offerPricesUpserted` | `{ offers: Array<{ offer_id, previous_prices: OfferPriceDTO[], prices: OfferPriceDTO[], created: string[], updated: string[], deleted: string[] }>, updated_by: string \| null }` |
38
+ | `offersDeleted` | `{ ids: string[], offers: OfferDTO[], additional_data? }` — `offers` is a snapshot taken before deletion, including `prices` |
39
+
40
+ `updated_by` is the authenticated actor id. Vendor routes fill it from the session; pass it yourself when running `updateOffersWorkflow` or `upsertOfferPricesWorkflow` directly.
41
+
42
+ In `offerPricesUpserted`, `previous_prices` and `prices` are the offer's ladder before and after the write (`amount`, `currency_code`, `min_quantity`, `max_quantity`, `price_rules`). `created` and `deleted` hold the price ids added and removed; `updated` holds the ids rewritten in place whose amount, quantity bounds, or rules actually changed — an unchanged row resent with its id is not listed. The hook also fires when `updateOffersWorkflow` runs the price upsert for you, so a single handler on `upsertOfferPricesWorkflow` covers both entry points. Prices are hard-deleted and Medusa's pricing events carry ids only, so these payloads (and the `offersDeleted` snapshot) are the only place the previous values can be read.
43
+
44
+ ```ts
45
+ import { upsertOfferPricesWorkflow } from "@mercurjs/core/workflows"
46
+ import { StepResponse } from "@medusajs/framework/workflows-sdk"
47
+
48
+ upsertOfferPricesWorkflow.hooks.offerPricesUpserted(
49
+ async ({ offers, updated_by }, { container }) => {
50
+ for (const { offer_id, previous_prices, prices, updated } of offers) {
51
+ // record a price-history entry for every id in `updated`
52
+ }
53
+ return new StepResponse(undefined)
54
+ }
55
+ )
56
+ ```
57
+
30
58
  ## Behavior notes
31
59
 
32
60
  - **Prices** are written on the master variant's shared price set, each row scoped by an `offer_id` `PriceRule`. On update, supplying `prices` replaces the ladder with the given rows; omitting it leaves prices untouched.
@@ -134,6 +134,60 @@ Each field is a `CustomFormField`.
134
134
  onto the product's `metadata`.
135
135
  </Warning>
136
136
 
137
+ ## Customize the onboarding wizard
138
+
139
+ The vendor onboarding wizard is the `onboarding` form zone of the `seller` model. Each step is a `tab`. Use the same `forms` entries to add fields to a step, add a step, remove a step, or reorder the steps.
140
+
141
+ ```tsx apps/vendor/src/custom-fields/seller.tsx
142
+ import { defineCustomFieldsConfig } from "@mercurjs/dashboard-sdk"
143
+ import { createFormHelper } from "@mercurjs/dashboard-shared"
144
+
145
+ const form = createFormHelper()
146
+
147
+ export default defineCustomFieldsConfig({
148
+ model: "seller",
149
+ forms: [
150
+ // Add fields to a built-in step
151
+ { zone: "onboarding", tab: "address", fields: { region_note: form.define({ validation: form.string().optional() }) } },
152
+ // An unknown tab becomes a new step
153
+ {
154
+ zone: "onboarding",
155
+ tab: "documents",
156
+ label: "Documents",
157
+ rank: 25,
158
+ optional: true,
159
+ fields: {
160
+ vat_document_url: form.define({ validation: form.string().url(), label: "VAT document URL" }),
161
+ },
162
+ },
163
+ // Remove a built-in step
164
+ { zone: "onboarding", tab: "company", disabled: true },
165
+ ],
166
+ })
167
+ ```
168
+
169
+ | Option | Type | Description |
170
+ | ---------- | --------- | ------------------------------------------------------------------------------------------------- |
171
+ | `label` | `string` | Step heading. Set it on every new step. |
172
+ | `rank` | `number` | Sort position. New steps without a rank go last. Also reorders a built-in step. |
173
+ | `optional` | `boolean` | Shows a **Skip** button. Set `false` on a built-in step to hide its Skip button. |
174
+ | `disabled` | `true` | Removes a built-in step. Takes no `fields`. The `store` step can't be removed. |
175
+
176
+ The built-in steps and their defaults:
177
+
178
+ | Step | `rank` | `optional` |
179
+ | --------- | ------ | ---------- |
180
+ | `store` | 10 | `false` |
181
+ | `address` | 20 | `true` |
182
+ | `company` | 30 | `true` |
183
+ | `payment` | 40 | `true` |
184
+
185
+ The last step's button reads **Finish** and creates the seller. Values from every step's custom fields are merged into one `additional_data` object on `POST /vendor/sellers`, which reaches the `sellerAccountCreated` hook of `createSellerAccountWorkflow`. A skipped step contributes nothing, even if its fields are required.
186
+
187
+ <Note>
188
+ Always set `tab` on an onboarding entry. An entry without a `tab` renders its fields on every step.
189
+ </Note>
190
+
137
191
  ## Extend detail sections
138
192
 
139
193
  Add, replace, or remove fields on a detail section, and add actions to its
@@ -238,6 +292,36 @@ built-in ones.
238
292
  the field list. The `link` declaration drives it.
239
293
  </Warning>
240
294
 
295
+ ## Combine configs from plugins and your app
296
+
297
+ Every config for a model applies in order: installed plugins first, then your
298
+ app's `src/custom-fields/` files. A later config sees everything earlier configs
299
+ added, not only the built-ins, so your app can change what a plugin contributed.
300
+
301
+ | Contribution | Matched by | A later config with the same id/key |
302
+ | --------------------- | ---------- | -------------------------------------------------------------------------- |
303
+ | `list.columns` | `id` | Replaces the column in place. Hide it with `columnVisibility: { id: false }`. |
304
+ | `list.filters` | `key` | Replaces the filter in place, or drops it with `remove: true`. |
305
+ | `displays[].fields` | `id` | Replaces the field in place, or drops it with `component: null`. |
306
+ | `forms[].fields` | field name | Replaces the field, including its `zone` and `tab`. |
307
+ | `columnVisibility` | column id | Overrides the earlier value for that column. |
308
+ | `columnOrder` | n/a | Replaces the earlier order. |
309
+
310
+ `link`, `bulkActions`, display `actions`, `activity`, and `actionLocks` add up
311
+ across configs.
312
+
313
+ ```tsx
314
+ // src/custom-fields/product-brand.tsx: rework the plugin's "brand" column
315
+ export default defineCustomFieldsConfig({
316
+ model: "product",
317
+ link: "brand",
318
+ list: {
319
+ columns: [{ id: "brand", header: "Maker", component: ({ row }) => row.brand?.name }],
320
+ filters: [{ key: "brand_id", remove: true }],
321
+ },
322
+ })
323
+ ```
324
+
241
325
  ## Fetch linked module data
242
326
 
243
327
  Declare `link` to fetch a module link alongside the entity. Its data rides on the
@@ -12,6 +12,10 @@ The vendor store-setup and onboarding surface is a widget zone, `seller.setup`,
12
12
  **Three layers, one flow.** The panel, a `seller.setup` widget, renders and collects. The vendor seller route carries the value through `additional_data` with no core schema change. A `sellersUpdated` workflow hook persists it. Each layer is additive: nothing built-in is replaced.
13
13
  </Info>
14
14
 
15
+ <Tip>
16
+ To change the onboarding wizard itself (fields on any step, new steps, removed or reordered steps), use `forms` entries with `zone: "onboarding"`. See [Customize the onboarding wizard](/references/panel-extensions/custom-fields#customize-the-onboarding-wizard).
17
+ </Tip>
18
+
15
19
  ## What you build
16
20
 
17
21
  A "Tax ID" prompt on the vendor store-setup surface. The vendor types a VAT number. It rides `additional_data` to `POST /vendor/sellers/:id`, and a workflow hook stores it durably through the [Custom Fields module](/rc/resources/customization/custom-fields).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mercurjs/docs",
3
- "version": "2.3.7",
3
+ "version": "2.3.8-canary.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/mercurjs/mercur",