@medusajs/dashboard 2.10.4-snapshot-20250925200335 → 2.10.4-snapshot-20250926124023

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.
Files changed (35) hide show
  1. package/dist/{add-campaign-promotions-3BB3BLFD.mjs → add-campaign-promotions-66OUK5IZ.mjs} +3 -3
  2. package/dist/app.js +69 -7
  3. package/dist/app.mjs +2 -2
  4. package/dist/{campaign-create-CQ3XBHSY.mjs → campaign-create-SGLXQU2F.mjs} +3 -2
  5. package/dist/{campaign-detail-LASOFZ2O.mjs → campaign-detail-64BFNH6C.mjs} +4 -4
  6. package/dist/{chunk-U4R5MBF2.mjs → chunk-546WSFKK.mjs} +1 -1
  7. package/dist/{chunk-AXXGAOQL.mjs → chunk-ENN7KGKR.mjs} +9 -4
  8. package/dist/{chunk-NFQXNOP7.mjs → chunk-FEQBZNAR.mjs} +1 -1
  9. package/dist/{chunk-CY33DS7K.mjs → chunk-GOJZH5OP.mjs} +52 -1
  10. package/dist/{chunk-QPLPGRYF.mjs → chunk-HZ6YSP3B.mjs} +1 -1
  11. package/dist/{chunk-7DFTLGA5.mjs → chunk-RL6WXPVT.mjs} +18 -18
  12. package/dist/{chunk-RBDAWRFF.mjs → chunk-W4JWOYEI.mjs} +1 -1
  13. package/dist/{chunk-IP2QPPWC.mjs → chunk-WMBKZ3WT.mjs} +1 -1
  14. package/dist/{chunk-DKOCYXB5.mjs → chunk-X3FQBD35.mjs} +6 -2
  15. package/dist/{product-attributes-WVQRK3GQ.mjs → product-attributes-WT6V3O6K.mjs} +3 -3
  16. package/dist/{product-create-PWSPOVUS.mjs → product-create-YOAIOVWR.mjs} +3 -3
  17. package/dist/{product-detail-EBPCCBI4.mjs → product-detail-UG5DB3KF.mjs} +3 -3
  18. package/dist/{product-edit-5E6D43KE.mjs → product-edit-ISUGWU7Q.mjs} +3 -3
  19. package/dist/{product-media-TRKQTA4G.mjs → product-media-HBJQ6R4T.mjs} +2 -2
  20. package/dist/{product-organization-OCVSTKEK.mjs → product-organization-6ZCHJOKQ.mjs} +3 -3
  21. package/dist/{product-shipping-profile-SG6NDHF4.mjs → product-shipping-profile-2PNCCHKU.mjs} +3 -3
  22. package/dist/{promotion-add-campaign-YOUUM6RB.mjs → promotion-add-campaign-SOGZKDNX.mjs} +2 -2
  23. package/dist/{promotion-create-NBFV4XQV.mjs → promotion-create-6TASTM72.mjs} +7 -3
  24. package/dist/{promotion-detail-247QD6DA.mjs → promotion-detail-H2J4TH7H.mjs} +2 -2
  25. package/dist/{promotion-list-WDHOSD55.mjs → promotion-list-RCYVKDR6.mjs} +3 -3
  26. package/dist/{reset-password-LCVV4NOA.mjs → reset-password-JZCLEBGV.mjs} +1 -1
  27. package/dist/{tax-region-create-4DTM3RTZ.mjs → tax-region-create-4SKSWULN.mjs} +1 -1
  28. package/package.json +9 -9
  29. package/src/i18n/translations/$schema.json +22 -1
  30. package/src/i18n/translations/en.json +6 -2
  31. package/src/routes/campaigns/campaign-create/components/create-campaign-form/create-campaign-form.tsx +7 -2
  32. package/src/routes/campaigns/campaign-detail/components/campaign-budget/campaign-budget.tsx +5 -1
  33. package/src/routes/campaigns/common/components/create-campaign-form-fields/create-campaign-form-fields.tsx +50 -1
  34. package/src/routes/campaigns/common/constants.ts +1 -0
  35. package/src/routes/promotions/promotion-create/components/create-promotion-form/create-promotion-form.tsx +7 -0
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  usePromotionTableColumns,
3
3
  usePromotionTableQuery
4
- } from "./chunk-U4R5MBF2.mjs";
5
- import "./chunk-IP2QPPWC.mjs";
4
+ } from "./chunk-546WSFKK.mjs";
5
+ import "./chunk-WMBKZ3WT.mjs";
6
6
  import "./chunk-MSDRGCRR.mjs";
7
7
  import "./chunk-ADOCJB6L.mjs";
8
8
  import "./chunk-LQTHYS2Z.mjs";
@@ -30,7 +30,7 @@ import {
30
30
  useRouteModal
31
31
  } from "./chunk-4TC5YS65.mjs";
32
32
  import "./chunk-4GQOUCX6.mjs";
33
- import "./chunk-DKOCYXB5.mjs";
33
+ import "./chunk-X3FQBD35.mjs";
34
34
  import "./chunk-LPEUYMRK.mjs";
35
35
  import "./chunk-OC7BQLYI.mjs";
36
36
  import "./chunk-S4DMV3ZT.mjs";
package/dist/app.js CHANGED
@@ -11004,7 +11004,7 @@ var init_en = __esm({
11004
11004
  delete: {
11005
11005
  title: "Are you sure?",
11006
11006
  description: "You are about to delete the campaign '{{name}}'. This action cannot be undone.",
11007
- successToast: "Campaign '{{name}}' was successfully created."
11007
+ successToast: "Campaign '{{name}}' was successfully deleted."
11008
11008
  },
11009
11009
  edit: {
11010
11010
  header: "Edit Campaign",
@@ -11048,7 +11048,11 @@ var init_en = __esm({
11048
11048
  type: "Type",
11049
11049
  currency: "Currency",
11050
11050
  limit: "Limit",
11051
- used: "Used"
11051
+ used: "Used",
11052
+ budgetAttribute: "Limit usage per",
11053
+ budgetAttributeTooltip: "Define how many times the promotion can be used by a specific customer or email.",
11054
+ limitBudgetAttributeCustomer: "Budget limit per customer",
11055
+ limitBudgetAttributeEmail: "Budget limit per email"
11052
11056
  },
11053
11057
  type: {
11054
11058
  spend: {
@@ -138688,7 +138692,8 @@ var init_constants14 = __esm({
138688
138692
  budget: {
138689
138693
  type: "usage",
138690
138694
  currency_code: null,
138691
- limit: null
138695
+ limit: null,
138696
+ attribute: null
138692
138697
  }
138693
138698
  };
138694
138699
  }
@@ -139222,6 +139227,7 @@ var init_create_campaign_form_fields = __esm({
139222
139227
  init_store();
139223
139228
  init_use_document_direction();
139224
139229
  init_currencies2();
139230
+ init_combobox2();
139225
139231
  import_jsx_runtime295 = require("react/jsx-runtime");
139226
139232
  CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
139227
139233
  const { t: t5 } = (0, import_react_i18next219.useTranslation)();
@@ -139373,13 +139379,14 @@ var init_create_campaign_form_fields = __esm({
139373
139379
  import_ui214.RadioGroup,
139374
139380
  {
139375
139381
  dir: direction,
139376
- className: "flex gap-y-3",
139382
+ className: "flex gap-x-4 gap-y-3",
139377
139383
  ...field,
139378
139384
  onValueChange: field.onChange,
139379
139385
  children: [
139380
139386
  /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(
139381
139387
  import_ui214.RadioGroup.ChoiceBox,
139382
139388
  {
139389
+ className: "flex-1",
139383
139390
  value: "usage",
139384
139391
  label: t5("campaigns.budget.type.usage.title"),
139385
139392
  description: t5("campaigns.budget.type.usage.description")
@@ -139388,6 +139395,7 @@ var init_create_campaign_form_fields = __esm({
139388
139395
  /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(
139389
139396
  import_ui214.RadioGroup.ChoiceBox,
139390
139397
  {
139398
+ className: "flex-1",
139391
139399
  value: "spend",
139392
139400
  label: t5("campaigns.budget.type.spend.title"),
139393
139401
  description: t5("campaigns.budget.type.spend.description"),
@@ -139490,6 +139498,52 @@ var init_create_campaign_form_fields = __esm({
139490
139498
  ] });
139491
139499
  }
139492
139500
  }
139501
+ ),
139502
+ !isTypeSpend && /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(
139503
+ Form.Field,
139504
+ {
139505
+ control: form.control,
139506
+ name: `${fieldScope}budget.attribute`,
139507
+ render: ({ field }) => {
139508
+ return /* @__PURE__ */ (0, import_jsx_runtime295.jsxs)(Form.Item, { className: "basis-1/2", children: [
139509
+ /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(
139510
+ Form.Label,
139511
+ {
139512
+ tooltip: t5(
139513
+ "campaigns.budget.fields.budgetAttributeTooltip"
139514
+ ),
139515
+ children: t5("campaigns.budget.fields.budgetAttribute")
139516
+ }
139517
+ ),
139518
+ /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(Form.Control, { children: /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(
139519
+ Combobox,
139520
+ {
139521
+ ...field,
139522
+ onChange: (e) => {
139523
+ if (typeof e === "undefined") {
139524
+ field.onChange(null);
139525
+ } else {
139526
+ field.onChange(e);
139527
+ }
139528
+ },
139529
+ allowClear: true,
139530
+ options: [
139531
+ {
139532
+ label: t5("fields.customer"),
139533
+ value: "customer_id"
139534
+ },
139535
+ {
139536
+ label: t5("fields.email"),
139537
+ value: "customer_email"
139538
+ }
139539
+ ]
139540
+ },
139541
+ "attribute"
139542
+ ) }),
139543
+ /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(Form.ErrorMessage, {})
139544
+ ] });
139545
+ }
139546
+ }
139493
139547
  )
139494
139548
  ] })
139495
139549
  ] });
@@ -139832,8 +139886,9 @@ var init_create_campaign_form = __esm({
139832
139886
  starts_at: zod16.date().nullable(),
139833
139887
  ends_at: zod16.date().nullable(),
139834
139888
  budget: zod16.object({
139889
+ attribute: zod16.string().nullish(),
139835
139890
  limit: zod16.number().min(0).nullish(),
139836
- type: zod16.enum(["spend", "usage"]),
139891
+ type: zod16.enum(["spend", "usage", "use_by_attribute"]),
139837
139892
  currency_code: zod16.string().nullish()
139838
139893
  })
139839
139894
  });
@@ -139846,6 +139901,8 @@ var init_create_campaign_form = __esm({
139846
139901
  resolver: (0, import_zod51.zodResolver)(CreateCampaignSchema)
139847
139902
  });
139848
139903
  const handleSubmit = form.handleSubmit(async (data) => {
139904
+ const attribute = data.budget.attribute || null;
139905
+ const type = attribute ? "use_by_attribute" : data.budget.type;
139849
139906
  await mutateAsync(
139850
139907
  {
139851
139908
  name: data.name,
@@ -139854,7 +139911,8 @@ var init_create_campaign_form = __esm({
139854
139911
  starts_at: data.starts_at,
139855
139912
  ends_at: data.ends_at,
139856
139913
  budget: {
139857
- type: data.budget.type,
139914
+ type,
139915
+ attribute,
139858
139916
  limit: data.budget.limit ? data.budget.limit : void 0,
139859
139917
  currency_code: data.budget.currency_code
139860
139918
  }
@@ -140197,6 +140255,10 @@ var init_create_promotion_form = __esm({
140197
140255
  values: rule.values
140198
140256
  }));
140199
140257
  };
140258
+ if (data.campaign) {
140259
+ data.campaign.budget.attribute = data.campaign.budget.attribute || null;
140260
+ data.campaign.budget.type = data.campaign.budget.attribute ? "use_by_attribute" : data.campaign.budget.type;
140261
+ }
140200
140262
  createPromotion(
140201
140263
  {
140202
140264
  ...promotionData,
@@ -142774,7 +142836,7 @@ var init_campaign_budget = __esm({
142774
142836
  {
142775
142837
  className: "text-ui-fg-subtle ms-10 mt-[1.5px] font-normal",
142776
142838
  level: "h3",
142777
- children: t5("campaigns.fields.budget_limit")
142839
+ children: campaign.budget?.type === "use_by_attribute" ? campaign.budget?.attribute === "customer_id" ? t5("campaigns.budget.fields.limitBudgetAttributeCustomer") : t5("campaigns.budget.fields.limitBudgetAttributeEmail") : t5("campaigns.fields.budget_limit")
142778
142840
  }
142779
142841
  )
142780
142842
  ] }),
package/dist/app.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  DashboardApp
3
- } from "./chunk-7DFTLGA5.mjs";
3
+ } from "./chunk-RL6WXPVT.mjs";
4
4
  import "./chunk-NQIC7ZFS.mjs";
5
5
  import "./chunk-ONB3JEHR.mjs";
6
6
  import "./chunk-VLOA5XAC.mjs";
7
7
  import "./chunk-4GQOUCX6.mjs";
8
8
  import "./chunk-2VTICXJR.mjs";
9
9
  import "./chunk-D3YQN7HV.mjs";
10
- import "./chunk-DKOCYXB5.mjs";
10
+ import "./chunk-X3FQBD35.mjs";
11
11
  import "./chunk-MNXC6Q4F.mjs";
12
12
  import "./chunk-C5P5PL3E.mjs";
13
13
  import "./chunk-DG7J63J2.mjs";
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  CreateCampaignForm
3
- } from "./chunk-AXXGAOQL.mjs";
4
- import "./chunk-CY33DS7K.mjs";
3
+ } from "./chunk-ENN7KGKR.mjs";
4
+ import "./chunk-GOJZH5OP.mjs";
5
5
  import "./chunk-F6ZOHZVB.mjs";
6
+ import "./chunk-OFN7DIZA.mjs";
6
7
  import "./chunk-DK4WIVY6.mjs";
7
8
  import "./chunk-IUCDCPJU.mjs";
8
9
  import "./chunk-6HTZNHPT.mjs";
@@ -4,8 +4,8 @@ import {
4
4
  import {
5
5
  usePromotionTableColumns,
6
6
  usePromotionTableQuery
7
- } from "./chunk-U4R5MBF2.mjs";
8
- import "./chunk-IP2QPPWC.mjs";
7
+ } from "./chunk-546WSFKK.mjs";
8
+ import "./chunk-WMBKZ3WT.mjs";
9
9
  import "./chunk-MSDRGCRR.mjs";
10
10
  import "./chunk-ADOCJB6L.mjs";
11
11
  import "./chunk-LQTHYS2Z.mjs";
@@ -31,7 +31,7 @@ import {
31
31
  import "./chunk-C76H5USB.mjs";
32
32
  import "./chunk-PFKKVLZX.mjs";
33
33
  import "./chunk-4GQOUCX6.mjs";
34
- import "./chunk-DKOCYXB5.mjs";
34
+ import "./chunk-X3FQBD35.mjs";
35
35
  import {
36
36
  useExtension
37
37
  } from "./chunk-C5P5PL3E.mjs";
@@ -129,7 +129,7 @@ var CampaignBudget = ({ campaign }) => {
129
129
  {
130
130
  className: "text-ui-fg-subtle ms-10 mt-[1.5px] font-normal",
131
131
  level: "h3",
132
- children: t("campaigns.fields.budget_limit")
132
+ children: campaign.budget?.type === "use_by_attribute" ? campaign.budget?.attribute === "customer_id" ? t("campaigns.budget.fields.limitBudgetAttributeCustomer") : t("campaigns.budget.fields.limitBudgetAttributeEmail") : t("campaigns.fields.budget_limit")
133
133
  }
134
134
  )
135
135
  ] }),
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getPromotionStatus
3
- } from "./chunk-IP2QPPWC.mjs";
3
+ } from "./chunk-WMBKZ3WT.mjs";
4
4
  import {
5
5
  TextCell,
6
6
  TextHeader
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CreateCampaignFormFields
3
- } from "./chunk-CY33DS7K.mjs";
3
+ } from "./chunk-GOJZH5OP.mjs";
4
4
  import {
5
5
  VisuallyHidden
6
6
  } from "./chunk-F6ZOHZVB.mjs";
@@ -32,7 +32,8 @@ var DEFAULT_CAMPAIGN_VALUES = {
32
32
  budget: {
33
33
  type: "usage",
34
34
  currency_code: null,
35
- limit: null
35
+ limit: null,
36
+ attribute: null
36
37
  }
37
38
  };
38
39
 
@@ -45,8 +46,9 @@ var CreateCampaignSchema = zod.object({
45
46
  starts_at: zod.date().nullable(),
46
47
  ends_at: zod.date().nullable(),
47
48
  budget: zod.object({
49
+ attribute: zod.string().nullish(),
48
50
  limit: zod.number().min(0).nullish(),
49
- type: zod.enum(["spend", "usage"]),
51
+ type: zod.enum(["spend", "usage", "use_by_attribute"]),
50
52
  currency_code: zod.string().nullish()
51
53
  })
52
54
  });
@@ -59,6 +61,8 @@ var CreateCampaignForm = () => {
59
61
  resolver: zodResolver(CreateCampaignSchema)
60
62
  });
61
63
  const handleSubmit = form.handleSubmit(async (data) => {
64
+ const attribute = data.budget.attribute || null;
65
+ const type = attribute ? "use_by_attribute" : data.budget.type;
62
66
  await mutateAsync(
63
67
  {
64
68
  name: data.name,
@@ -67,7 +71,8 @@ var CreateCampaignForm = () => {
67
71
  starts_at: data.starts_at,
68
72
  ends_at: data.ends_at,
69
73
  budget: {
70
- type: data.budget.type,
74
+ type,
75
+ attribute,
71
76
  limit: data.budget.limit ? data.budget.limit : void 0,
72
77
  currency_code: data.budget.currency_code
73
78
  }
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-6GU6IDUA.mjs";
11
11
  import {
12
12
  i18n
13
- } from "./chunk-DKOCYXB5.mjs";
13
+ } from "./chunk-X3FQBD35.mjs";
14
14
  import {
15
15
  Form
16
16
  } from "./chunk-OBQI23QM.mjs";
@@ -1,3 +1,6 @@
1
+ import {
2
+ Combobox
3
+ } from "./chunk-OFN7DIZA.mjs";
1
4
  import {
2
5
  currencies,
3
6
  getCurrencySymbol
@@ -177,13 +180,14 @@ var CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
177
180
  RadioGroup,
178
181
  {
179
182
  dir: direction,
180
- className: "flex gap-y-3",
183
+ className: "flex gap-x-4 gap-y-3",
181
184
  ...field,
182
185
  onValueChange: field.onChange,
183
186
  children: [
184
187
  /* @__PURE__ */ jsx(
185
188
  RadioGroup.ChoiceBox,
186
189
  {
190
+ className: "flex-1",
187
191
  value: "usage",
188
192
  label: t("campaigns.budget.type.usage.title"),
189
193
  description: t("campaigns.budget.type.usage.description")
@@ -192,6 +196,7 @@ var CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
192
196
  /* @__PURE__ */ jsx(
193
197
  RadioGroup.ChoiceBox,
194
198
  {
199
+ className: "flex-1",
195
200
  value: "spend",
196
201
  label: t("campaigns.budget.type.spend.title"),
197
202
  description: t("campaigns.budget.type.spend.description"),
@@ -294,6 +299,52 @@ var CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
294
299
  ] });
295
300
  }
296
301
  }
302
+ ),
303
+ !isTypeSpend && /* @__PURE__ */ jsx(
304
+ Form.Field,
305
+ {
306
+ control: form.control,
307
+ name: `${fieldScope}budget.attribute`,
308
+ render: ({ field }) => {
309
+ return /* @__PURE__ */ jsxs(Form.Item, { className: "basis-1/2", children: [
310
+ /* @__PURE__ */ jsx(
311
+ Form.Label,
312
+ {
313
+ tooltip: t(
314
+ "campaigns.budget.fields.budgetAttributeTooltip"
315
+ ),
316
+ children: t("campaigns.budget.fields.budgetAttribute")
317
+ }
318
+ ),
319
+ /* @__PURE__ */ jsx(Form.Control, { children: /* @__PURE__ */ jsx(
320
+ Combobox,
321
+ {
322
+ ...field,
323
+ onChange: (e) => {
324
+ if (typeof e === "undefined") {
325
+ field.onChange(null);
326
+ } else {
327
+ field.onChange(e);
328
+ }
329
+ },
330
+ allowClear: true,
331
+ options: [
332
+ {
333
+ label: t("fields.customer"),
334
+ value: "customer_id"
335
+ },
336
+ {
337
+ label: t("fields.email"),
338
+ value: "customer_email"
339
+ }
340
+ ]
341
+ },
342
+ "attribute"
343
+ ) }),
344
+ /* @__PURE__ */ jsx(Form.ErrorMessage, {})
345
+ ] });
346
+ }
347
+ }
297
348
  )
298
349
  ] })
299
350
  ] });
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getLinkedFields
3
- } from "./chunk-7DFTLGA5.mjs";
3
+ } from "./chunk-RL6WXPVT.mjs";
4
4
 
5
5
  // src/routes/products/product-detail/constants.ts
6
6
  var PRODUCT_DETAIL_FIELDS = getLinkedFields(
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-D3YQN7HV.mjs";
17
17
  import {
18
18
  I18n
19
- } from "./chunk-DKOCYXB5.mjs";
19
+ } from "./chunk-X3FQBD35.mjs";
20
20
  import {
21
21
  Thumbnail
22
22
  } from "./chunk-MNXC6Q4F.mjs";
@@ -3248,7 +3248,7 @@ function getRouteMap({
3248
3248
  children: [
3249
3249
  {
3250
3250
  path: "create",
3251
- lazy: () => import("./product-create-PWSPOVUS.mjs")
3251
+ lazy: () => import("./product-create-YOAIOVWR.mjs")
3252
3252
  },
3253
3253
  {
3254
3254
  path: "import",
@@ -3264,7 +3264,7 @@ function getRouteMap({
3264
3264
  path: ":id",
3265
3265
  errorElement: /* @__PURE__ */ jsx17(ErrorBoundary, {}),
3266
3266
  lazy: async () => {
3267
- const { Breadcrumb, loader } = await import("./product-detail-EBPCCBI4.mjs");
3267
+ const { Breadcrumb, loader } = await import("./product-detail-UG5DB3KF.mjs");
3268
3268
  return {
3269
3269
  Component: Outlet4,
3270
3270
  loader,
@@ -3276,11 +3276,11 @@ function getRouteMap({
3276
3276
  children: [
3277
3277
  {
3278
3278
  path: "",
3279
- lazy: () => import("./product-detail-EBPCCBI4.mjs"),
3279
+ lazy: () => import("./product-detail-UG5DB3KF.mjs"),
3280
3280
  children: [
3281
3281
  {
3282
3282
  path: "edit",
3283
- lazy: () => import("./product-edit-5E6D43KE.mjs")
3283
+ lazy: () => import("./product-edit-ISUGWU7Q.mjs")
3284
3284
  },
3285
3285
  {
3286
3286
  path: "edit-variant",
@@ -3292,19 +3292,19 @@ function getRouteMap({
3292
3292
  },
3293
3293
  {
3294
3294
  path: "attributes",
3295
- lazy: () => import("./product-attributes-WVQRK3GQ.mjs")
3295
+ lazy: () => import("./product-attributes-WT6V3O6K.mjs")
3296
3296
  },
3297
3297
  {
3298
3298
  path: "organization",
3299
- lazy: () => import("./product-organization-OCVSTKEK.mjs")
3299
+ lazy: () => import("./product-organization-6ZCHJOKQ.mjs")
3300
3300
  },
3301
3301
  {
3302
3302
  path: "shipping-profile",
3303
- lazy: () => import("./product-shipping-profile-SG6NDHF4.mjs")
3303
+ lazy: () => import("./product-shipping-profile-2PNCCHKU.mjs")
3304
3304
  },
3305
3305
  {
3306
3306
  path: "media",
3307
- lazy: () => import("./product-media-TRKQTA4G.mjs")
3307
+ lazy: () => import("./product-media-HBJQ6R4T.mjs")
3308
3308
  },
3309
3309
  {
3310
3310
  path: "prices",
@@ -3514,16 +3514,16 @@ function getRouteMap({
3514
3514
  children: [
3515
3515
  {
3516
3516
  path: "",
3517
- lazy: () => import("./promotion-list-WDHOSD55.mjs")
3517
+ lazy: () => import("./promotion-list-RCYVKDR6.mjs")
3518
3518
  },
3519
3519
  {
3520
3520
  path: "create",
3521
- lazy: () => import("./promotion-create-NBFV4XQV.mjs")
3521
+ lazy: () => import("./promotion-create-6TASTM72.mjs")
3522
3522
  },
3523
3523
  {
3524
3524
  path: ":id",
3525
3525
  lazy: async () => {
3526
- const { Component, Breadcrumb, loader } = await import("./promotion-detail-247QD6DA.mjs");
3526
+ const { Component, Breadcrumb, loader } = await import("./promotion-detail-H2J4TH7H.mjs");
3527
3527
  return {
3528
3528
  Component,
3529
3529
  loader,
@@ -3539,7 +3539,7 @@ function getRouteMap({
3539
3539
  },
3540
3540
  {
3541
3541
  path: "add-to-campaign",
3542
- lazy: () => import("./promotion-add-campaign-YOUUM6RB.mjs")
3542
+ lazy: () => import("./promotion-add-campaign-SOGZKDNX.mjs")
3543
3543
  },
3544
3544
  {
3545
3545
  path: ":ruleType/edit",
@@ -3563,12 +3563,12 @@ function getRouteMap({
3563
3563
  },
3564
3564
  {
3565
3565
  path: "create",
3566
- lazy: () => import("./campaign-create-CQ3XBHSY.mjs")
3566
+ lazy: () => import("./campaign-create-SGLXQU2F.mjs")
3567
3567
  },
3568
3568
  {
3569
3569
  path: ":id",
3570
3570
  lazy: async () => {
3571
- const { Component, Breadcrumb, loader } = await import("./campaign-detail-LASOFZ2O.mjs");
3571
+ const { Component, Breadcrumb, loader } = await import("./campaign-detail-64BFNH6C.mjs");
3572
3572
  return {
3573
3573
  Component,
3574
3574
  loader,
@@ -3592,7 +3592,7 @@ function getRouteMap({
3592
3592
  },
3593
3593
  {
3594
3594
  path: "add-promotions",
3595
- lazy: () => import("./add-campaign-promotions-3BB3BLFD.mjs")
3595
+ lazy: () => import("./add-campaign-promotions-66OUK5IZ.mjs")
3596
3596
  }
3597
3597
  ]
3598
3598
  }
@@ -4472,7 +4472,7 @@ function getRouteMap({
4472
4472
  children: [
4473
4473
  {
4474
4474
  path: "create",
4475
- lazy: () => import("./tax-region-create-4DTM3RTZ.mjs")
4475
+ lazy: () => import("./tax-region-create-4SKSWULN.mjs")
4476
4476
  }
4477
4477
  ]
4478
4478
  },
@@ -4627,7 +4627,7 @@ function getRouteMap({
4627
4627
  },
4628
4628
  {
4629
4629
  path: "/reset-password",
4630
- lazy: () => import("./reset-password-LCVV4NOA.mjs")
4630
+ lazy: () => import("./reset-password-JZCLEBGV.mjs")
4631
4631
  },
4632
4632
  {
4633
4633
  path: "/invite",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CreateCampaignFormFields
3
- } from "./chunk-CY33DS7K.mjs";
3
+ } from "./chunk-GOJZH5OP.mjs";
4
4
  import {
5
5
  useComboboxData
6
6
  } from "./chunk-HFB3OQXI.mjs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  i18n
3
- } from "./chunk-DKOCYXB5.mjs";
3
+ } from "./chunk-X3FQBD35.mjs";
4
4
 
5
5
  // src/lib/promotions.ts
6
6
  var promotionStatusMap = {
@@ -10954,7 +10954,7 @@ var en_default = {
10954
10954
  delete: {
10955
10955
  title: "Are you sure?",
10956
10956
  description: "You are about to delete the campaign '{{name}}'. This action cannot be undone.",
10957
- successToast: "Campaign '{{name}}' was successfully created."
10957
+ successToast: "Campaign '{{name}}' was successfully deleted."
10958
10958
  },
10959
10959
  edit: {
10960
10960
  header: "Edit Campaign",
@@ -10998,7 +10998,11 @@ var en_default = {
10998
10998
  type: "Type",
10999
10999
  currency: "Currency",
11000
11000
  limit: "Limit",
11001
- used: "Used"
11001
+ used: "Used",
11002
+ budgetAttribute: "Limit usage per",
11003
+ budgetAttributeTooltip: "Define how many times the promotion can be used by a specific customer or email.",
11004
+ limitBudgetAttributeCustomer: "Budget limit per customer",
11005
+ limitBudgetAttributeEmail: "Budget limit per email"
11002
11006
  },
11003
11007
  type: {
11004
11008
  spend: {
@@ -11,18 +11,18 @@ import {
11
11
  } from "./chunk-4TC5YS65.mjs";
12
12
  import {
13
13
  PRODUCT_DETAIL_FIELDS
14
- } from "./chunk-QPLPGRYF.mjs";
14
+ } from "./chunk-HZ6YSP3B.mjs";
15
15
  import {
16
16
  FormExtensionZone,
17
17
  useExtendableForm
18
- } from "./chunk-7DFTLGA5.mjs";
18
+ } from "./chunk-RL6WXPVT.mjs";
19
19
  import "./chunk-NQIC7ZFS.mjs";
20
20
  import "./chunk-ONB3JEHR.mjs";
21
21
  import "./chunk-VLOA5XAC.mjs";
22
22
  import "./chunk-4GQOUCX6.mjs";
23
23
  import "./chunk-2VTICXJR.mjs";
24
24
  import "./chunk-D3YQN7HV.mjs";
25
- import "./chunk-DKOCYXB5.mjs";
25
+ import "./chunk-X3FQBD35.mjs";
26
26
  import "./chunk-MNXC6Q4F.mjs";
27
27
  import {
28
28
  useExtension
@@ -25,7 +25,7 @@ import {
25
25
  UploadMediaFormItem,
26
26
  decorateVariantsWithDefaultValues,
27
27
  normalizeProductFormValues
28
- } from "./chunk-NFQXNOP7.mjs";
28
+ } from "./chunk-FEQBZNAR.mjs";
29
29
  import "./chunk-ZQRKUG6J.mjs";
30
30
  import {
31
31
  DataGrid,
@@ -61,14 +61,14 @@ import {
61
61
  import {
62
62
  FormExtensionZone,
63
63
  useExtendableForm
64
- } from "./chunk-7DFTLGA5.mjs";
64
+ } from "./chunk-RL6WXPVT.mjs";
65
65
  import "./chunk-NQIC7ZFS.mjs";
66
66
  import "./chunk-ONB3JEHR.mjs";
67
67
  import "./chunk-VLOA5XAC.mjs";
68
68
  import "./chunk-4GQOUCX6.mjs";
69
69
  import "./chunk-2VTICXJR.mjs";
70
70
  import "./chunk-D3YQN7HV.mjs";
71
- import "./chunk-DKOCYXB5.mjs";
71
+ import "./chunk-X3FQBD35.mjs";
72
72
  import "./chunk-MNXC6Q4F.mjs";
73
73
  import {
74
74
  useExtension
@@ -30,15 +30,15 @@ import {
30
30
  import "./chunk-PFKKVLZX.mjs";
31
31
  import {
32
32
  PRODUCT_DETAIL_FIELDS
33
- } from "./chunk-QPLPGRYF.mjs";
34
- import "./chunk-7DFTLGA5.mjs";
33
+ } from "./chunk-HZ6YSP3B.mjs";
34
+ import "./chunk-RL6WXPVT.mjs";
35
35
  import "./chunk-NQIC7ZFS.mjs";
36
36
  import "./chunk-ONB3JEHR.mjs";
37
37
  import "./chunk-VLOA5XAC.mjs";
38
38
  import "./chunk-4GQOUCX6.mjs";
39
39
  import "./chunk-2VTICXJR.mjs";
40
40
  import "./chunk-D3YQN7HV.mjs";
41
- import "./chunk-DKOCYXB5.mjs";
41
+ import "./chunk-X3FQBD35.mjs";
42
42
  import "./chunk-MNXC6Q4F.mjs";
43
43
  import {
44
44
  useExtension
@@ -15,18 +15,18 @@ import {
15
15
  } from "./chunk-4TC5YS65.mjs";
16
16
  import {
17
17
  PRODUCT_DETAIL_FIELDS
18
- } from "./chunk-QPLPGRYF.mjs";
18
+ } from "./chunk-HZ6YSP3B.mjs";
19
19
  import {
20
20
  FormExtensionZone,
21
21
  useExtendableForm
22
- } from "./chunk-7DFTLGA5.mjs";
22
+ } from "./chunk-RL6WXPVT.mjs";
23
23
  import "./chunk-NQIC7ZFS.mjs";
24
24
  import "./chunk-ONB3JEHR.mjs";
25
25
  import "./chunk-VLOA5XAC.mjs";
26
26
  import "./chunk-4GQOUCX6.mjs";
27
27
  import "./chunk-2VTICXJR.mjs";
28
28
  import "./chunk-D3YQN7HV.mjs";
29
- import "./chunk-DKOCYXB5.mjs";
29
+ import "./chunk-X3FQBD35.mjs";
30
30
  import "./chunk-MNXC6Q4F.mjs";
31
31
  import {
32
32
  useExtension
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  EditProductMediaSchema,
3
3
  UploadMediaFormItem
4
- } from "./chunk-NFQXNOP7.mjs";
4
+ } from "./chunk-FEQBZNAR.mjs";
5
5
  import "./chunk-ZQRKUG6J.mjs";
6
6
  import "./chunk-TYTNUPXB.mjs";
7
7
  import "./chunk-6GU6IDUA.mjs";
@@ -13,7 +13,7 @@ import {
13
13
  RouteFocusModal,
14
14
  useRouteModal
15
15
  } from "./chunk-4TC5YS65.mjs";
16
- import "./chunk-DKOCYXB5.mjs";
16
+ import "./chunk-X3FQBD35.mjs";
17
17
  import "./chunk-OBQI23QM.mjs";
18
18
  import {
19
19
  useProduct,
@@ -17,18 +17,18 @@ import {
17
17
  } from "./chunk-4TC5YS65.mjs";
18
18
  import {
19
19
  PRODUCT_DETAIL_FIELDS
20
- } from "./chunk-QPLPGRYF.mjs";
20
+ } from "./chunk-HZ6YSP3B.mjs";
21
21
  import {
22
22
  FormExtensionZone,
23
23
  useExtendableForm
24
- } from "./chunk-7DFTLGA5.mjs";
24
+ } from "./chunk-RL6WXPVT.mjs";
25
25
  import "./chunk-NQIC7ZFS.mjs";
26
26
  import "./chunk-ONB3JEHR.mjs";
27
27
  import "./chunk-VLOA5XAC.mjs";
28
28
  import "./chunk-4GQOUCX6.mjs";
29
29
  import "./chunk-2VTICXJR.mjs";
30
30
  import "./chunk-D3YQN7HV.mjs";
31
- import "./chunk-DKOCYXB5.mjs";
31
+ import "./chunk-X3FQBD35.mjs";
32
32
  import "./chunk-MNXC6Q4F.mjs";
33
33
  import {
34
34
  useExtension
@@ -14,15 +14,15 @@ import {
14
14
  } from "./chunk-4TC5YS65.mjs";
15
15
  import {
16
16
  PRODUCT_DETAIL_FIELDS
17
- } from "./chunk-QPLPGRYF.mjs";
18
- import "./chunk-7DFTLGA5.mjs";
17
+ } from "./chunk-HZ6YSP3B.mjs";
18
+ import "./chunk-RL6WXPVT.mjs";
19
19
  import "./chunk-NQIC7ZFS.mjs";
20
20
  import "./chunk-ONB3JEHR.mjs";
21
21
  import "./chunk-VLOA5XAC.mjs";
22
22
  import "./chunk-4GQOUCX6.mjs";
23
23
  import "./chunk-2VTICXJR.mjs";
24
24
  import "./chunk-D3YQN7HV.mjs";
25
- import "./chunk-DKOCYXB5.mjs";
25
+ import "./chunk-X3FQBD35.mjs";
26
26
  import "./chunk-MNXC6Q4F.mjs";
27
27
  import "./chunk-C5P5PL3E.mjs";
28
28
  import "./chunk-DG7J63J2.mjs";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AddCampaignPromotionForm
3
- } from "./chunk-RBDAWRFF.mjs";
4
- import "./chunk-CY33DS7K.mjs";
3
+ } from "./chunk-W4JWOYEI.mjs";
4
+ import "./chunk-GOJZH5OP.mjs";
5
5
  import "./chunk-HFB3OQXI.mjs";
6
6
  import "./chunk-OFN7DIZA.mjs";
7
7
  import "./chunk-DK4WIVY6.mjs";
@@ -3,15 +3,15 @@ import {
3
3
  } from "./chunk-KEQOAJC2.mjs";
4
4
  import {
5
5
  AddCampaignPromotionFields
6
- } from "./chunk-RBDAWRFF.mjs";
6
+ } from "./chunk-W4JWOYEI.mjs";
7
7
  import {
8
8
  RulesFormField
9
9
  } from "./chunk-VI7MI3US.mjs";
10
10
  import {
11
11
  CreateCampaignSchema,
12
12
  DEFAULT_CAMPAIGN_VALUES
13
- } from "./chunk-AXXGAOQL.mjs";
14
- import "./chunk-CY33DS7K.mjs";
13
+ } from "./chunk-ENN7KGKR.mjs";
14
+ import "./chunk-GOJZH5OP.mjs";
15
15
  import "./chunk-F6ZOHZVB.mjs";
16
16
  import "./chunk-HFB3OQXI.mjs";
17
17
  import "./chunk-OFN7DIZA.mjs";
@@ -338,6 +338,10 @@ var CreatePromotionForm = () => {
338
338
  values: rule.values
339
339
  }));
340
340
  };
341
+ if (data.campaign) {
342
+ data.campaign.budget.attribute = data.campaign.budget.attribute || null;
343
+ data.campaign.budget.type = data.campaign.budget.attribute ? "use_by_attribute" : data.campaign.budget.type;
344
+ }
341
345
  createPromotion(
342
346
  {
343
347
  ...promotionData,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-VAIHVNV6.mjs";
4
4
  import {
5
5
  getPromotionStatus
6
- } from "./chunk-IP2QPPWC.mjs";
6
+ } from "./chunk-WMBKZ3WT.mjs";
7
7
  import {
8
8
  formatPercentage
9
9
  } from "./chunk-4FM6S5CX.mjs";
@@ -18,7 +18,7 @@ import {
18
18
  } from "./chunk-GIZFNLKK.mjs";
19
19
  import "./chunk-PFKKVLZX.mjs";
20
20
  import "./chunk-4GQOUCX6.mjs";
21
- import "./chunk-DKOCYXB5.mjs";
21
+ import "./chunk-X3FQBD35.mjs";
22
22
  import {
23
23
  useExtension
24
24
  } from "./chunk-C5P5PL3E.mjs";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  usePromotionTableColumns,
3
3
  usePromotionTableQuery
4
- } from "./chunk-U4R5MBF2.mjs";
5
- import "./chunk-IP2QPPWC.mjs";
4
+ } from "./chunk-546WSFKK.mjs";
5
+ import "./chunk-WMBKZ3WT.mjs";
6
6
  import "./chunk-MSDRGCRR.mjs";
7
7
  import "./chunk-ADOCJB6L.mjs";
8
8
  import "./chunk-LQTHYS2Z.mjs";
@@ -25,7 +25,7 @@ import {
25
25
  import "./chunk-C76H5USB.mjs";
26
26
  import "./chunk-PFKKVLZX.mjs";
27
27
  import "./chunk-4GQOUCX6.mjs";
28
- import "./chunk-DKOCYXB5.mjs";
28
+ import "./chunk-X3FQBD35.mjs";
29
29
  import {
30
30
  useExtension
31
31
  } from "./chunk-C5P5PL3E.mjs";
@@ -3,7 +3,7 @@ import "./chunk-EQTBJSBZ.mjs";
3
3
  import "./chunk-4GQOUCX6.mjs";
4
4
  import {
5
5
  i18n
6
- } from "./chunk-DKOCYXB5.mjs";
6
+ } from "./chunk-X3FQBD35.mjs";
7
7
  import {
8
8
  Form
9
9
  } from "./chunk-OBQI23QM.mjs";
@@ -24,7 +24,7 @@ import {
24
24
  import "./chunk-4GQOUCX6.mjs";
25
25
  import {
26
26
  i18n
27
- } from "./chunk-DKOCYXB5.mjs";
27
+ } from "./chunk-X3FQBD35.mjs";
28
28
  import "./chunk-DG7J63J2.mjs";
29
29
  import {
30
30
  Form
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medusajs/dashboard",
3
- "version": "2.10.4-snapshot-20250925200335",
3
+ "version": "2.10.4-snapshot-20250926124023",
4
4
  "scripts": {
5
5
  "generate:static": "node ./scripts/generate-currencies.js && prettier --write ./src/lib/currencies.ts",
6
6
  "dev": "vite",
@@ -45,10 +45,10 @@
45
45
  "@dnd-kit/utilities": "^3.2.2",
46
46
  "@hookform/error-message": "^2.0.1",
47
47
  "@hookform/resolvers": "3.4.2",
48
- "@medusajs/admin-shared": "2.10.4-snapshot-20250925200335",
49
- "@medusajs/icons": "2.10.4-snapshot-20250925200335",
50
- "@medusajs/js-sdk": "2.10.4-snapshot-20250925200335",
51
- "@medusajs/ui": "4.0.24-snapshot-20250925200335",
48
+ "@medusajs/admin-shared": "2.10.4-snapshot-20250926124023",
49
+ "@medusajs/icons": "2.10.4-snapshot-20250926124023",
50
+ "@medusajs/js-sdk": "2.10.4-snapshot-20250926124023",
51
+ "@medusajs/ui": "4.0.24-snapshot-20250926124023",
52
52
  "@radix-ui/react-dialog": "1.1.4",
53
53
  "@radix-ui/react-dismissable-layer": "1.1.4",
54
54
  "@tanstack/react-query": "5.64.2",
@@ -78,10 +78,10 @@
78
78
  "zod": "3.25.76"
79
79
  },
80
80
  "devDependencies": {
81
- "@medusajs/admin-shared": "2.10.4-snapshot-20250925200335",
82
- "@medusajs/admin-vite-plugin": "2.10.4-snapshot-20250925200335",
83
- "@medusajs/types": "2.10.4-snapshot-20250925200335",
84
- "@medusajs/ui-preset": "2.10.4-snapshot-20250925200335",
81
+ "@medusajs/admin-shared": "2.10.4-snapshot-20250926124023",
82
+ "@medusajs/admin-vite-plugin": "2.10.4-snapshot-20250926124023",
83
+ "@medusajs/types": "2.10.4-snapshot-20250926124023",
84
+ "@medusajs/ui-preset": "2.10.4-snapshot-20250926124023",
85
85
  "@types/node": "^20.11.15",
86
86
  "@types/react": "^18.2.79",
87
87
  "@types/react-dom": "^18.2.25",
@@ -8371,9 +8371,30 @@
8371
8371
  },
8372
8372
  "used": {
8373
8373
  "type": "string"
8374
+ },
8375
+ "budgetAttribute": {
8376
+ "type": "string"
8377
+ },
8378
+ "budgetAttributeTooltip": {
8379
+ "type": "string"
8380
+ },
8381
+ "limitBudgetAttributeCustomer": {
8382
+ "type": "string"
8383
+ },
8384
+ "limitBudgetAttributeEmail": {
8385
+ "type": "string"
8374
8386
  }
8375
8387
  },
8376
- "required": ["type", "currency", "limit", "used"],
8388
+ "required": [
8389
+ "type",
8390
+ "currency",
8391
+ "limit",
8392
+ "used",
8393
+ "budgetAttribute",
8394
+ "budgetAttributeTooltip",
8395
+ "limitBudgetAttributeCustomer",
8396
+ "limitBudgetAttributeEmail"
8397
+ ],
8377
8398
  "additionalProperties": false
8378
8399
  },
8379
8400
  "type": {
@@ -2204,7 +2204,7 @@
2204
2204
  "delete": {
2205
2205
  "title": "Are you sure?",
2206
2206
  "description": "You are about to delete the campaign '{{name}}'. This action cannot be undone.",
2207
- "successToast": "Campaign '{{name}}' was successfully created."
2207
+ "successToast": "Campaign '{{name}}' was successfully deleted."
2208
2208
  },
2209
2209
  "edit": {
2210
2210
  "header": "Edit Campaign",
@@ -2248,7 +2248,11 @@
2248
2248
  "type": "Type",
2249
2249
  "currency": "Currency",
2250
2250
  "limit": "Limit",
2251
- "used": "Used"
2251
+ "used": "Used",
2252
+ "budgetAttribute": "Limit usage per",
2253
+ "budgetAttributeTooltip": "Define how many times the promotion can be used by a specific customer or email.",
2254
+ "limitBudgetAttributeCustomer": "Budget limit per customer",
2255
+ "limitBudgetAttributeEmail": "Budget limit per email"
2252
2256
  },
2253
2257
  "type": {
2254
2258
  "spend": {
@@ -21,8 +21,9 @@ export const CreateCampaignSchema = zod.object({
21
21
  starts_at: zod.date().nullable(),
22
22
  ends_at: zod.date().nullable(),
23
23
  budget: zod.object({
24
+ attribute: zod.string().nullish(),
24
25
  limit: zod.number().min(0).nullish(),
25
- type: zod.enum(["spend", "usage"]),
26
+ type: zod.enum(["spend", "usage", "use_by_attribute"]),
26
27
  currency_code: zod.string().nullish(),
27
28
  }),
28
29
  })
@@ -38,6 +39,9 @@ export const CreateCampaignForm = () => {
38
39
  })
39
40
 
40
41
  const handleSubmit = form.handleSubmit(async (data) => {
42
+ const attribute = data.budget.attribute || null
43
+ const type = attribute ? "use_by_attribute" : data.budget.type
44
+
41
45
  await mutateAsync(
42
46
  {
43
47
  name: data.name,
@@ -46,7 +50,8 @@ export const CreateCampaignForm = () => {
46
50
  starts_at: data.starts_at,
47
51
  ends_at: data.ends_at,
48
52
  budget: {
49
- type: data.budget.type,
53
+ type,
54
+ attribute,
50
55
  limit: data.budget.limit ? data.budget.limit : undefined,
51
56
  currency_code: data.budget.currency_code,
52
57
  },
@@ -25,7 +25,11 @@ export const CampaignBudget = ({ campaign }: CampaignBudgetProps) => {
25
25
  className="text-ui-fg-subtle ms-10 mt-[1.5px] font-normal"
26
26
  level="h3"
27
27
  >
28
- {t("campaigns.fields.budget_limit")}
28
+ {campaign.budget?.type === "use_by_attribute"
29
+ ? campaign.budget?.attribute === "customer_id"
30
+ ? t("campaigns.budget.fields.limitBudgetAttributeCustomer")
31
+ : t("campaigns.budget.fields.limitBudgetAttributeEmail")
32
+ : t("campaigns.fields.budget_limit")}
29
33
  </Heading>
30
34
  </div>
31
35
 
@@ -19,6 +19,7 @@ import {
19
19
  currencies,
20
20
  getCurrencySymbol,
21
21
  } from "../../../../../lib/data/currencies"
22
+ import { Combobox } from "../../../../../components/inputs/combobox"
22
23
 
23
24
  export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
24
25
  const { t } = useTranslation()
@@ -209,17 +210,19 @@ export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
209
210
  <Form.Control>
210
211
  <RadioGroup
211
212
  dir={direction}
212
- className="flex gap-y-3"
213
+ className="flex gap-x-4 gap-y-3"
213
214
  {...field}
214
215
  onValueChange={field.onChange}
215
216
  >
216
217
  <RadioGroup.ChoiceBox
218
+ className="flex-1"
217
219
  value={"usage"}
218
220
  label={t("campaigns.budget.type.usage.title")}
219
221
  description={t("campaigns.budget.type.usage.description")}
220
222
  />
221
223
 
222
224
  <RadioGroup.ChoiceBox
225
+ className="flex-1"
223
226
  value={"spend"}
224
227
  label={t("campaigns.budget.type.spend.title")}
225
228
  description={t("campaigns.budget.type.spend.description")}
@@ -342,6 +345,52 @@ export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
342
345
  )
343
346
  }}
344
347
  />
348
+
349
+ {!isTypeSpend && (
350
+ <Form.Field
351
+ control={form.control}
352
+ name={`${fieldScope}budget.attribute`}
353
+ render={({ field }) => {
354
+ return (
355
+ <Form.Item className="basis-1/2">
356
+ <Form.Label
357
+ tooltip={t(
358
+ "campaigns.budget.fields.budgetAttributeTooltip"
359
+ )}
360
+ >
361
+ {t("campaigns.budget.fields.budgetAttribute")}
362
+ </Form.Label>
363
+
364
+ <Form.Control>
365
+ <Combobox
366
+ key="attribute"
367
+ {...field}
368
+ onChange={(e) => {
369
+ if (typeof e === "undefined") {
370
+ field.onChange(null)
371
+ } else {
372
+ field.onChange(e)
373
+ }
374
+ }}
375
+ allowClear
376
+ options={[
377
+ {
378
+ label: t("fields.customer"),
379
+ value: "customer_id",
380
+ },
381
+ {
382
+ label: t("fields.email"),
383
+ value: "customer_email",
384
+ },
385
+ ]}
386
+ ></Combobox>
387
+ </Form.Control>
388
+ <Form.ErrorMessage />
389
+ </Form.Item>
390
+ )
391
+ }}
392
+ />
393
+ )}
345
394
  </div>
346
395
  </div>
347
396
  )
@@ -10,5 +10,6 @@ export const DEFAULT_CAMPAIGN_VALUES = {
10
10
  type: "usage" as CampaignBudgetTypeValues,
11
11
  currency_code: null,
12
12
  limit: null,
13
+ attribute: null,
13
14
  },
14
15
  }
@@ -139,6 +139,13 @@ export const CreatePromotionForm = () => {
139
139
  }))
140
140
  }
141
141
 
142
+ if (data.campaign) {
143
+ data.campaign.budget.attribute = data.campaign.budget.attribute || null
144
+ data.campaign.budget.type = data.campaign.budget.attribute
145
+ ? "use_by_attribute"
146
+ : data.campaign.budget.type
147
+ }
148
+
142
149
  createPromotion(
143
150
  {
144
151
  ...promotionData,