@useinsider/guido 3.18.1 → 3.18.2-beta.32d291d

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 (56) hide show
  1. package/README.md +21 -3
  2. package/dist/@types/config/schemas.js +59 -51
  3. package/dist/components/Guido.vue.js +4 -4
  4. package/dist/components/Guido.vue2.js +55 -53
  5. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +7 -7
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +82 -57
  7. package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js +18 -0
  8. package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue2.js +25 -0
  9. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +24 -22
  10. package/dist/components/organisms/onboarding/OnboardingWrapper.vue2.js +28 -24
  11. package/dist/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue.js +21 -0
  12. package/dist/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue2.js +46 -0
  13. package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.js +21 -0
  14. package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue2.js +46 -0
  15. package/dist/components/organisms/save-as-template/SaveAsTemplateDrawer.vue2.js +34 -34
  16. package/dist/composables/useCustomInterfaceAppearance.js +46 -42
  17. package/dist/composables/useHttp.js +24 -22
  18. package/dist/composables/useLegacyStrategyConversion.js +61 -0
  19. package/dist/enums/extensions/recommendationBlock.js +40 -31
  20. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +91 -84
  21. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +72 -28
  22. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +45 -44
  23. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +123 -58
  24. package/dist/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js +42 -0
  25. package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +7 -7
  26. package/dist/guido.css +1 -1
  27. package/dist/node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js +29 -28
  28. package/dist/package.json.js +1 -1
  29. package/dist/services/recommendationApi.js +46 -37
  30. package/dist/services/templateLibraryApi.js +17 -14
  31. package/dist/src/@types/config/schemas.d.ts +16 -0
  32. package/dist/src/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.d.ts +2 -0
  33. package/dist/src/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue.d.ts +2 -0
  34. package/dist/src/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.d.ts +2 -0
  35. package/dist/src/composables/useConfig.d.ts +4 -0
  36. package/dist/src/composables/useLegacyStrategyConversion.d.ts +3 -0
  37. package/dist/src/enums/extensions/recommendationBlock.d.ts +5 -1
  38. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +5 -1
  39. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +2 -0
  40. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +4 -0
  41. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +82 -1
  42. package/dist/src/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.d.ts +32 -0
  43. package/dist/src/services/recommendationApi.d.ts +2 -1
  44. package/dist/src/stores/config.d.ts +322 -0
  45. package/dist/src/stores/onboarding.d.ts +808 -10
  46. package/dist/src/utils/genericUtil.d.ts +6 -0
  47. package/dist/src/utils/liquidDynamicContent.d.ts +20 -0
  48. package/dist/static/assets/icons/filled-arrow-rising.svg.js +5 -0
  49. package/dist/static/assets/icons/line-info.svg.js +5 -0
  50. package/dist/static/styles/components/recommendation-strategy.css.js +70 -5
  51. package/dist/stores/config.js +74 -60
  52. package/dist/stores/onboarding.js +46 -36
  53. package/dist/utils/genericUtil.js +63 -54
  54. package/dist/utils/liquidDynamicContent.js +15 -0
  55. package/dist/utils/templatePreparation.js +54 -52
  56. package/package.json +3 -3
@@ -94,9 +94,9 @@ function j(e, t = {}) {
94
94
  const u = s ?? P(n), l = y.getConfig(n);
95
95
  if (u === "list" || !l.mobileLayoutEnabled)
96
96
  return te({ currentNode: n, documentModifier: o });
97
- const c = A(), a = $(r, c.recommendationProducts), f = i ?? U(n, c.filterList), p = `<td><table class="ins-recommendation-product-container ins-recommendation-mobile-container" width="100%" cellpadding="0" cellspacing="0" border="0">${k(a, u, {
97
+ const c = A(), f = $(r, c.recommendationProducts), a = i ?? U(n, c.filterList), p = `<td><table class="ins-recommendation-product-container ins-recommendation-mobile-container" width="100%" cellpadding="0" cellspacing="0" border="0">${k(f, u, {
98
98
  productsPerRow: l.mobileCardsInRow,
99
- composition: f,
99
+ composition: a,
100
100
  filterList: c.filterList,
101
101
  priceInline: !l.priceMovedToNextLine,
102
102
  // Match the initial render's gutter so a regeneration never changes block height (SD-143023, #386).
@@ -122,9 +122,9 @@ function ie(e, t = {}) {
122
122
  const u = n.querySelector(L) ?? n.querySelector(W);
123
123
  if (!u)
124
124
  return !1;
125
- const l = A(), c = $(r, l.recommendationProducts), { cardsInRow: a } = y.getConfig(n), f = i ?? U(n, l.filterList), d = s ?? P(n), p = y.getConfig(n), E = k(c, d, {
126
- productsPerRow: a,
127
- composition: f,
125
+ const l = A(), c = $(r, l.recommendationProducts), { cardsInRow: f } = y.getConfig(n), a = i ?? U(n, l.filterList), d = s ?? P(n), p = y.getConfig(n), E = k(c, d, {
126
+ productsPerRow: f,
127
+ composition: a,
128
128
  filterList: l.filterList,
129
129
  priceInline: !p.priceMovedToNextLine,
130
130
  // Match the initial render's gutter so a regeneration never changes block height (SD-143023, #386).
@@ -153,10 +153,10 @@ function ce(e, t, n) {
153
153
  return !1;
154
154
  const s = A(), i = r.split(",").filter(Boolean), u = D(i, o, s.filterList), l = [], c = u.join(",") !== i.join(",");
155
155
  c && l.push([R, u.join(",")]);
156
- const a = le(
156
+ const f = le(
157
157
  o.getAttribute(q)
158
- ), f = a && z(a, o, s.filterList);
159
- if (a && f && f.join(",") !== a.join(",") && l.push([q, JSON.stringify(f)]), l.length === 0)
158
+ ), a = f && z(f, o, s.filterList);
159
+ if (f && a && a.join(",") !== f.join(",") && l.push([q, JSON.stringify(a)]), l.length === 0)
160
160
  return !1;
161
161
  if (l.forEach(([d, p]) => {
162
162
  t.modifyHtml(o).setAttribute(d, p);
@@ -177,19 +177,20 @@ function Te(e) {
177
177
  products: r,
178
178
  layout: s,
179
179
  composition: i,
180
- skipStylePreservation: u
180
+ skipStylePreservation: u,
181
+ forceApply: l = !1
181
182
  } = e;
182
183
  if (!t)
183
184
  return;
184
- const l = u ? {} : x(t), c = {
185
+ const c = u ? {} : x(t), f = {
185
186
  currentNode: t,
186
187
  documentModifier: n,
187
188
  products: r,
188
189
  layout: s,
189
190
  composition: i
190
191
  };
191
- let a = ie(c, l);
192
- a = j(c, l) || a, a && (ce(t, n, i), n.apply(new S("Regenerate products with styles"))), o == null || o();
192
+ let a = ie(f, c);
193
+ a = j(f, c) || a, a && ce(t, n, i), (a || l) && n.apply(new S("Regenerate products with styles")), o == null || o();
193
194
  }
194
195
  function Re(e, t) {
195
196
  return e.length === t ? e : e.length > t ? e.slice(0, t) : [...e, ...H(t - e.length)];
@@ -250,16 +251,16 @@ function se(e) {
250
251
  omnibusDiscountEl: l,
251
252
  buttonEl: c
252
253
  } = e;
253
- let a = !1;
254
+ let f = !1;
254
255
  if (o && "querySelector" in o) {
255
- const f = o.querySelector("img");
256
- f && (t.modifyHtml(f).setAttribute("src", X(n.image_url)).setAttribute("alt", n.name), a = !0);
256
+ const a = o.querySelector("img");
257
+ a && (t.modifyHtml(a).setAttribute("src", X(n.image_url)).setAttribute("alt", n.name), f = !0);
257
258
  const d = o.querySelector("a");
258
- d && (t.modifyHtml(d).setAttribute("href", n.url), a = !0);
259
+ d && (t.modifyHtml(d).setAttribute("href", n.url), f = !0);
259
260
  }
260
261
  if (r && "querySelector" in r) {
261
- const f = r.querySelector("strong") ?? r.querySelector("p");
262
- b(t, f ?? null, n.name) && (a = !0);
262
+ const a = r.querySelector("strong") ?? r.querySelector("p");
263
+ b(t, a ?? null, n.name) && (f = !0);
263
264
  }
264
265
  if (K({
265
266
  documentModifier: t,
@@ -268,11 +269,11 @@ function se(e) {
268
269
  oldPriceEl: i,
269
270
  omnibusPriceEl: u,
270
271
  omnibusDiscountEl: l
271
- }) && (a = !0), c && "querySelector" in c) {
272
- const f = c.querySelector("a.es-button") || c.querySelector("a");
273
- f && (t.modifyHtml(f).setAttribute("href", n.url), a = !0);
272
+ }) && (f = !0), c && "querySelector" in c) {
273
+ const a = c.querySelector("a.es-button") || c.querySelector("a");
274
+ a && (t.modifyHtml(a).setAttribute("href", n.url), f = !0);
274
275
  }
275
- return a;
276
+ return f;
276
277
  }
277
278
  function V(e) {
278
279
  return "querySelector" in e ? e.querySelector(L) ?? e : e;
@@ -308,14 +309,14 @@ function fe(e, t, n) {
308
309
  let s = !1;
309
310
  return r.forEach((i, u) => {
310
311
  const l = Math.min(i.length, n.length);
311
- i.slice(0, l).forEach((c, a) => {
312
+ i.slice(0, l).forEach((c, f) => {
312
313
  if (!("querySelector" in c))
313
314
  return;
314
- const f = ae(u, n[a]);
315
- if (f === null)
315
+ const a = ae(u, n[f]);
316
+ if (a === null)
316
317
  return;
317
318
  const d = c.querySelector("p") ?? null;
318
- b(t, d, f) && (s = !0);
319
+ b(t, d, a) && (s = !0);
319
320
  });
320
321
  }), s;
321
322
  }
@@ -336,9 +337,9 @@ function O(e, t, n) {
336
337
  `[esd-extension-block-id="${m.OMNIBUS_DISCOUNT}"]`
337
338
  ), c = e.querySelectorAll(
338
339
  `[esd-extension-block-id="${m.BUTTON}"]`
339
- ), a = Math.min(o.length, n.length);
340
- let f = !1;
341
- for (let d = 0; d < a; d++) {
340
+ ), f = Math.min(o.length, n.length);
341
+ let a = !1;
342
+ for (let d = 0; d < f; d++) {
342
343
  const p = se({
343
344
  documentModifier: t,
344
345
  product: n[d],
@@ -350,33 +351,33 @@ function O(e, t, n) {
350
351
  omnibusDiscountEl: l[d] ?? null,
351
352
  buttonEl: c[d] ?? null
352
353
  });
353
- f = f || p;
354
+ a = a || p;
354
355
  }
355
- return fe(e, t, n) && (f = !0), f;
356
+ return fe(e, t, n) && (a = !0), a;
356
357
  }
357
358
  function qe(e) {
358
- const { currentNode: t, documentModifier: n, products: o } = e;
359
+ const { currentNode: t, documentModifier: n, products: o, forceApply: r = !1 } = e;
359
360
  if (!t || !("querySelectorAll" in t))
360
361
  return !1;
361
- const r = V(t);
362
- if (!("querySelectorAll" in r) || r.querySelectorAll(
362
+ const s = V(t);
363
+ if (!("querySelectorAll" in s) || s.querySelectorAll(
363
364
  `[esd-extension-block-id="${m.IMAGE}"]`
364
365
  ).length !== o.length)
365
366
  return !1;
366
- let i = O(r, n, o);
367
- const u = P(t), l = y.getConfig(t);
368
- if (u !== "list" && l.mobileLayoutEnabled && "querySelector" in t) {
369
- const c = t.querySelector(N);
370
- if (c) {
367
+ let u = O(s, n, o);
368
+ const l = P(t), c = y.getConfig(t);
369
+ if (l !== "list" && c.mobileLayoutEnabled && "querySelector" in t) {
370
+ const f = t.querySelector(N);
371
+ if (f) {
371
372
  const a = O(
372
- c,
373
+ f,
373
374
  n,
374
375
  o
375
376
  );
376
- i = i || a;
377
+ u = u || a;
377
378
  }
378
379
  }
379
- return i && n.apply(new S("Updated product content in-place")), !0;
380
+ return (u || r) && n.apply(new S("Updated product content in-place")), !0;
380
381
  }
381
382
  function _(e, t, n) {
382
383
  if (!("querySelectorAll" in e))
@@ -417,8 +418,8 @@ function Me(e) {
417
418
  if (u !== "list" && l.mobileLayoutEnabled && "querySelector" in t) {
418
419
  const c = t.querySelector(N);
419
420
  if (c) {
420
- const a = _(c, n, r);
421
- i = i || a;
421
+ const f = _(c, n, r);
422
+ i = i || f;
422
423
  }
423
424
  }
424
425
  return i && n.apply(new S("Updated price formatting in-place")), i;
@@ -1,22 +1,23 @@
1
- import { getRecommendationFeedSourceMaps as b, getOperatorOptions as G, PriceAttributes as v } from "../../../../enums/extensions/recommendationBlock.js";
1
+ import { getRecommendationFeedSourceMaps as R, getOperatorOptions as F, PriceAttributes as P } from "../../../../enums/extensions/recommendationBlock.js";
2
2
  import { useRecommendationApi as D } from "../../../../services/recommendationApi.js";
3
- import { useConfigStore as P } from "../../../../stores/config.js";
4
- import { defineStore as F } from "pinia";
3
+ import { useConfigStore as k } from "../../../../stores/config.js";
4
+ import { defineStore as L } from "pinia";
5
5
  import "../constants/selectors.js";
6
- import { DEFAULT_MOBILE_CARDS_IN_ROW as _, DEFAULT_CARDS_IN_ROW as U } from "../constants/layout.js";
7
- import { DEFAULT_NODE_CONFIG as N, EXCLUDED_ALGORITHM_IDS as L } from "../constants/defaultConfig.js";
8
- import { getDefaultProducts as R } from "../templates/utils.js";
9
- import { generateCompleteFilterQuery as k } from "../utils/filterUtil.js";
10
- import { getPartnerRecommendationParams as x } from "../utils/partnerCustomizations.js";
11
- import { sanitizeProductIds as A } from "../utils/productIds.js";
12
- import { isFilterValid as B } from "../validation/filterSchema.js";
13
- import { isConfigValid as M } from "../validation/requiredFields.js";
14
- const u = D();
15
- let f = null, h = null, g = null, S = null;
6
+ import { DEFAULT_MOBILE_CARDS_IN_ROW as U, DEFAULT_CARDS_IN_ROW as _ } from "../constants/layout.js";
7
+ import { CURRENT_CONFIG_VERSION as y, DEFAULT_NODE_CONFIG as N, EXCLUDED_ALGORITHM_IDS as M } from "../constants/defaultConfig.js";
8
+ import { getDefaultProducts as C } from "../templates/utils.js";
9
+ import { generateCompleteFilterQuery as v } from "../utils/filterUtil.js";
10
+ import { isLegacyStrategyConfig as x } from "../utils/legacyStrategyMigration.js";
11
+ import { getPartnerRecommendationParams as B } from "../utils/partnerCustomizations.js";
12
+ import { sanitizeProductIds as z } from "../utils/productIds.js";
13
+ import { isFilterValid as A } from "../validation/filterSchema.js";
14
+ import { isConfigValid as O } from "../validation/requiredFields.js";
15
+ const m = D();
16
+ let f = null, g = null, h = null, S = null;
16
17
  const p = /* @__PURE__ */ new Map();
17
- function w() {
18
+ function G() {
18
19
  return {
19
- cardsInRow: U,
20
+ cardsInRow: _,
20
21
  currencySettings: {
21
22
  name: "USD",
22
23
  value: "USD",
@@ -30,7 +31,7 @@ function w() {
30
31
  productIds: [],
31
32
  id: 1,
32
33
  language: "en_US",
33
- mobileCardsInRow: _,
34
+ mobileCardsInRow: U,
34
35
  mobileLayoutEnabled: !1,
35
36
  orientation: "grid",
36
37
  recommendedProducts: [],
@@ -38,6 +39,7 @@ function w() {
38
39
  shuffleProducts: !1,
39
40
  strategy: "mostPopular",
40
41
  strategyId: "",
42
+ nodeConfigVersion: y,
41
43
  textTrimming: !0,
42
44
  unresponsive: !1,
43
45
  size: "6",
@@ -46,20 +48,23 @@ function w() {
46
48
  priceHideIfSameAsDiscounted: !1
47
49
  };
48
50
  }
49
- function C() {
51
+ function w() {
50
52
  return {
51
- recommendationConfigs: w(),
53
+ recommendationConfigs: G(),
52
54
  recommendationProducts: [],
53
55
  filterStatus: !1,
54
56
  filterSelectionDrawerStatus: !1,
55
57
  assignStrategyDrawerStatus: !1,
56
58
  removeStrategyModalStatus: !1,
59
+ legacyStrategyUpdatedModalStatus: !1,
57
60
  filterGroup: 1,
58
61
  isInitialized: !1,
59
- filterSnapshot: null
62
+ filterSnapshot: null,
63
+ syncedConfigFingerprint: null,
64
+ legacyConversionLoading: !1
60
65
  };
61
66
  }
62
- const z = () => ({
67
+ const E = () => ({
63
68
  recommendationCampaignUrls: {},
64
69
  activePredictiveAlgorithms: [],
65
70
  languages: {},
@@ -71,8 +76,8 @@ const z = () => ({
71
76
  blockStates: {},
72
77
  currentRecommendationId: null,
73
78
  configVersion: 0
74
- }), Y = F("guidoRecommendationExtension", {
75
- state: () => z(),
79
+ }), et = L("guidoRecommendationExtension", {
80
+ state: () => E(),
76
81
  getters: {
77
82
  // ====================================================================
78
83
  // Proxy Getters — Backward Compatible Access to Current Block State
@@ -82,7 +87,7 @@ const z = () => ({
82
87
  * This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
83
88
  */
84
89
  recommendationConfigs(t) {
85
- return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : w();
90
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : G();
86
91
  },
87
92
  /**
88
93
  * Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
@@ -102,6 +107,15 @@ const z = () => ({
102
107
  removeStrategyModalStatus(t) {
103
108
  return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].removeStrategyModalStatus : !1;
104
109
  },
110
+ isLegacyStrategyBlock() {
111
+ return k().isFeatureEnabled("reusableRecommendationStrategy") && x(this.recommendationConfigs);
112
+ },
113
+ legacyConversionLoading(t) {
114
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].legacyConversionLoading : !1;
115
+ },
116
+ legacyStrategyUpdatedModalStatus(t) {
117
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].legacyStrategyUpdatedModalStatus : !1;
118
+ },
105
119
  assignedStrategy(t) {
106
120
  const { strategyId: e } = this.recommendationConfigs;
107
121
  return e ? t.strategies.find((r) => String(r.strategy_id) === e) ?? null : null;
@@ -137,8 +151,8 @@ const z = () => ({
137
151
  return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
138
152
  },
139
153
  getActivePredictiveAlgorithms: (t) => {
140
- const e = b(), r = [];
141
- return t.activePredictiveAlgorithms.filter((n) => !L.includes(n)).forEach((n) => {
154
+ const e = R(), r = [];
155
+ return t.activePredictiveAlgorithms.filter((n) => !M.includes(n)).forEach((n) => {
142
156
  r.push(...e.filter((s) => s.id === n));
143
157
  }), r.map((n) => ({
144
158
  text: n.name,
@@ -156,7 +170,7 @@ const z = () => ({
156
170
  getFilterList() {
157
171
  return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
158
172
  let e;
159
- return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : v.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
173
+ return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : P.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
160
174
  text: t.displayName,
161
175
  value: e,
162
176
  type: t.attributeType
@@ -178,7 +192,7 @@ const z = () => ({
178
192
  setCurrentBlock(t) {
179
193
  this.blockStates[t] || (this.blockStates = {
180
194
  ...this.blockStates,
181
- [t]: C()
195
+ [t]: w()
182
196
  }), this.currentRecommendationId = t;
183
197
  },
184
198
  /**
@@ -241,12 +255,12 @@ const z = () => ({
241
255
  const r = (o, c) => o === "." || o === "," || o === " " ? o : c, n = {
242
256
  name: e.currencyCode,
243
257
  value: e.currencyCode,
244
- symbol: e.currencyCode,
258
+ symbol: e.currencySymbol,
245
259
  alignment: e.currencyAlignment === "before" ? "0" : "1",
246
260
  decimalCount: String(e.currencyDecimalCount),
247
261
  decimalSeparator: r(e.currencyDecimalSeparator, ","),
248
262
  thousandSeparator: r(e.currencyThousandSeparator, ".")
249
- }, s = !this.blockStates[t], i = s ? C() : this.blockStates[t];
263
+ }, s = !this.blockStates[t], i = s ? w() : this.blockStates[t];
250
264
  i.recommendationConfigs = {
251
265
  ...i.recommendationConfigs,
252
266
  strategy: e.strategy,
@@ -285,7 +299,7 @@ const z = () => ({
285
299
  * Creates a filter with the first available attribute and operator pre-selected.
286
300
  */
287
301
  createDefaultFilter(t, e) {
288
- const [r] = this.getFilterList, [n] = G(r == null ? void 0 : r.type);
302
+ const [r] = this.getFilterList, [n] = F(r == null ? void 0 : r.type);
289
303
  return {
290
304
  type: "standardFilter",
291
305
  attribute: (r == null ? void 0 : r.value) ?? "",
@@ -338,6 +352,12 @@ const z = () => ({
338
352
  closeAssignStrategyDrawer() {
339
353
  this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].assignStrategyDrawerStatus = !1);
340
354
  },
355
+ openLegacyStrategyUpdatedModal() {
356
+ this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].legacyStrategyUpdatedModalStatus = !0);
357
+ },
358
+ closeLegacyStrategyUpdatedModal() {
359
+ this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].legacyStrategyUpdatedModalStatus = !1);
360
+ },
341
361
  openRemoveStrategyModal() {
342
362
  this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !0);
343
363
  },
@@ -352,7 +372,7 @@ const z = () => ({
352
372
  S = (async () => {
353
373
  this.strategiesLoading = !0;
354
374
  try {
355
- this.strategies = await u.fetchRecommendationStrategies();
375
+ this.strategies = await m.fetchRecommendationStrategies();
356
376
  } finally {
357
377
  this.strategiesLoading = !1;
358
378
  }
@@ -367,7 +387,7 @@ const z = () => ({
367
387
  const r = typeof t.updated_at == "string" ? t.updated_at : "", n = r ? `${t.strategy_id}:${r}:${e}` : "", s = n ? this.strategyUrlTemplates[n] : void 0;
368
388
  if (s)
369
389
  return s;
370
- const { full_path: i = "" } = await u.generateStrategyEndpoint(t, e) ?? {};
390
+ const { full_path: i = "" } = await m.generateStrategyEndpoint(t, e) ?? {};
371
391
  return n && i && (this.strategyUrlTemplates = {
372
392
  ...this.strategyUrlTemplates,
373
393
  [n]: i
@@ -379,8 +399,44 @@ const z = () => ({
379
399
  ...t.size !== void 0 ? { size: String(t.size) } : {}
380
400
  });
381
401
  },
402
+ async convertLegacyStrategy(t, e = { scope: "campaign" }) {
403
+ const r = this.currentRecommendationId;
404
+ if (r === null || !this.blockStates[r])
405
+ throw new Error("[Guido] convertLegacyStrategy called without an active block");
406
+ this.blockStates[r].legacyConversionLoading = !0;
407
+ try {
408
+ const n = await m.migrateLegacyStrategy(t, e);
409
+ try {
410
+ await this.fetchStrategies();
411
+ } catch (o) {
412
+ console.error("[Guido] strategy listing refresh after conversion failed", o);
413
+ }
414
+ const s = this.strategies.find((o) => String(o.strategy_id) === n), i = this.blockStates[r];
415
+ return i && (i.recommendationConfigs = {
416
+ ...i.recommendationConfigs,
417
+ strategyId: n,
418
+ nodeConfigVersion: y,
419
+ ...(s == null ? void 0 : s.size) !== void 0 ? { size: String(s.size) } : {}
420
+ }), this.currentRecommendationId === r && this.configVersion++, n;
421
+ } finally {
422
+ this.blockStates[r] && (this.blockStates[r].legacyConversionLoading = !1);
423
+ }
424
+ },
425
+ /**
426
+ * Undoes the config half of a conversion whose document write never landed, so the
427
+ * panel and the drawer fall back to "Legacy Strategy" instead of showing an assignment
428
+ * the document never received.
429
+ */
430
+ revertLegacyConversion(t, e) {
431
+ const r = this.blockStates[t];
432
+ r && (r.recommendationConfigs = { ...r.recommendationConfigs, ...e }, this.currentRecommendationId === t && this.configVersion++);
433
+ },
382
434
  removeStrategy() {
383
- this.patchCurrentBlockConfig({ strategyId: "", size: N.size });
435
+ this.patchCurrentBlockConfig({
436
+ strategyId: "",
437
+ size: N.size,
438
+ nodeConfigVersion: y
439
+ });
384
440
  },
385
441
  // ====================================================================
386
442
  // Shared Data Fetching (fetched once, used by all blocks)
@@ -396,7 +452,7 @@ const z = () => ({
396
452
  activePredictiveAlgorithms: t,
397
453
  languages: e,
398
454
  currencies: r
399
- } = await u.fetchRecommendationCreateData();
455
+ } = await m.fetchRecommendationCreateData();
400
456
  if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
401
457
  const n = this.blockStates[this.currentRecommendationId];
402
458
  n.filterStatus = !!n.recommendationConfigs.filters.length;
@@ -412,18 +468,18 @@ const z = () => ({
412
468
  },
413
469
  async fetchRecommendationFilters() {
414
470
  if (!Object.keys(this.filterList).length) {
415
- if (h) {
416
- await h;
471
+ if (g) {
472
+ await g;
417
473
  return;
418
474
  }
419
- h = (async () => {
420
- const t = await u.fetchRecommendationFilters();
475
+ g = (async () => {
476
+ const t = await m.fetchRecommendationFilters();
421
477
  this.filterList = t;
422
478
  })();
423
479
  try {
424
- await h;
480
+ await g;
425
481
  } finally {
426
- h = null;
482
+ g = null;
427
483
  }
428
484
  }
429
485
  },
@@ -452,7 +508,7 @@ const z = () => ({
452
508
  const n = [...e.recommendationConfigs.filters];
453
509
  n[r] = {
454
510
  ...t,
455
- isValid: B(t)
511
+ isValid: A(t)
456
512
  }, e.recommendationConfigs.filters = n;
457
513
  }
458
514
  },
@@ -490,7 +546,7 @@ const z = () => ({
490
546
  }), e.recommendationConfigs.filters = r;
491
547
  },
492
548
  generateFilterQuery() {
493
- return k(this.recommendationConfigs.filters);
549
+ return v(this.recommendationConfigs.filters);
494
550
  },
495
551
  /**
496
552
  * Validation-only check invoked at save-CTA time. Defined as an action
@@ -498,33 +554,33 @@ const z = () => ({
498
554
  * every block's recommendationConfigs across user edits.
499
555
  */
500
556
  hasInvalidBlock() {
501
- return Object.values(this.blockStates).some((t) => !M(t.recommendationConfigs, this));
557
+ return Object.values(this.blockStates).some((t) => !O(t.recommendationConfigs, this));
502
558
  },
503
559
  // ====================================================================
504
560
  // Per-Block Product Fetching
505
561
  // ====================================================================
506
562
  async fetchRecommendationProducts() {
507
563
  if (!(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])) {
508
- if (g) {
509
- await g;
564
+ if (h) {
565
+ await h;
510
566
  return;
511
567
  }
512
- g = this._doFetchProducts();
568
+ h = this._doFetchProducts();
513
569
  try {
514
- await g;
570
+ await h;
515
571
  } finally {
516
- g = null;
572
+ h = null;
517
573
  }
518
574
  }
519
575
  },
520
576
  async _doFetchProducts() {
521
577
  var d;
522
- const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = P();
578
+ const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = k();
523
579
  if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
524
580
  await this._doFetchStrategyProducts(t);
525
581
  return;
526
582
  }
527
- const s = r.filters.filter((m) => m.isValid), i = k(s), o = ((d = b().find((m) => m.key === r.strategy)) == null ? void 0 : d.path) || "", c = parseInt(r.size) || 6, a = {
583
+ const s = r.filters.filter((u) => u.isValid), i = v(s), o = ((d = R().find((u) => u.key === r.strategy)) == null ? void 0 : d.path) || "", c = parseInt(r.size) || 6, a = {
528
584
  locale: r.language,
529
585
  currency: r.currencySettings.value,
530
586
  partnerName: n.partnerName,
@@ -532,18 +588,27 @@ const z = () => ({
532
588
  details: !0,
533
589
  campaignId: n.variationId
534
590
  };
535
- r.strategy === "manualMerchandising" ? a.productId = A(r.productIds) : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), i && (a.filter = i), r.shuffleProducts && (a.shuffle = !0), Object.assign(
591
+ r.strategy === "manualMerchandising" ? a.productId = z(r.productIds) : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), i && (a.filter = i), r.shuffleProducts && (a.shuffle = !0), Object.assign(
536
592
  a,
537
- x(n.partnerName, r.strategy)
593
+ B(n.partnerName, r.strategy)
538
594
  );
539
595
  let l;
540
596
  try {
541
- l = await u.fetchRecommendationProducts(o, a);
597
+ l = await m.fetchRecommendationProducts(o, a);
542
598
  } catch {
543
599
  l = [];
544
600
  }
545
601
  this._setBlockProducts(t, l, c);
546
602
  },
603
+ /**
604
+ * Block-scoped counterpart of `fetchRecommendationProducts`, which only ever serves the
605
+ * selected block. The legacy conversion must refresh the products of the block that
606
+ * started it even after the user selected another one.
607
+ */
608
+ async fetchStrategyProductsForBlock(t) {
609
+ var e;
610
+ (e = this.blockStates[t]) != null && e.recommendationConfigs.strategyId && await this._doFetchStrategyProducts(t);
611
+ },
547
612
  async _doFetchStrategyProducts(t) {
548
613
  const e = (p.get(t) ?? 0) + 1;
549
614
  p.set(t, e);
@@ -556,8 +621,8 @@ const z = () => ({
556
621
  );
557
622
  if (i) {
558
623
  s = parseInt(String(i.size ?? "")) || s;
559
- const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), l = a.indexOf("?"), d = l === -1 ? a : a.slice(0, l), m = (l === -1 ? "" : a.slice(l + 1)).split("&").filter((I) => I && !I.startsWith("user_id=")), y = m.length ? `${d}?${m.join("&")}` : d;
560
- y && (n = await u.fetchRecommendationProductsByUrl(y));
624
+ const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), l = a.indexOf("?"), d = l === -1 ? a : a.slice(0, l), u = (l === -1 ? "" : a.slice(l + 1)).split("&").filter((I) => I && !I.startsWith("user_id=")), b = u.length ? `${d}?${u.join("&")}` : d;
625
+ b && (n = await m.fetchRecommendationProductsByUrl(b));
561
626
  }
562
627
  } catch {
563
628
  n = [];
@@ -567,14 +632,14 @@ const z = () => ({
567
632
  _setBlockProducts(t, e, r) {
568
633
  if (!this.blockStates[t])
569
634
  return;
570
- const n = e.length > 0 ? e : R(r);
635
+ const n = e.length > 0 ? e : C(r);
571
636
  this.blockStates[t].recommendationProducts = [
572
637
  ...n.slice(0, r),
573
- ...R(Math.max(0, r - n.length))
638
+ ...C(Math.max(0, r - n.length))
574
639
  ];
575
640
  }
576
641
  }
577
642
  });
578
643
  export {
579
- Y as useRecommendationExtensionStore
644
+ et as useRecommendationExtensionStore
580
645
  };
@@ -0,0 +1,42 @@
1
+ import "../constants/selectors.js";
2
+ import { CURRENT_CONFIG_VERSION as m } from "../constants/defaultConfig.js";
3
+ import { sanitizeProductIds as p } from "./productIds.js";
4
+ const d = "manualMerchandising";
5
+ function N({ strategyId: e, nodeConfigVersion: t }) {
6
+ return !e && t < m;
7
+ }
8
+ const o = (e) => {
9
+ const t = String(e ?? "").trim();
10
+ return /^[1-9]\d*$/.test(t) ? t : null;
11
+ };
12
+ function f({ campaignId: e, templateLibraryId: t }) {
13
+ if (o(e))
14
+ return { scope: "campaign" };
15
+ const n = o(t);
16
+ return n ? { scope: "template", templateId: n } : { scope: "campaign" };
17
+ }
18
+ function y({
19
+ blockId: e,
20
+ url: t,
21
+ campaignId: n,
22
+ variationId: a,
23
+ strategy: c,
24
+ productIds: s,
25
+ target: r
26
+ }) {
27
+ const i = c === d ? p(s).split(",").filter(Boolean) : [];
28
+ return {
29
+ ...r.scope === "template" ? { templateId: Number.parseInt(r.templateId) } : {
30
+ campaignId: Number.parseInt(n) || 0,
31
+ variationId: Number.parseInt(a) || 0
32
+ },
33
+ blockId: String(e),
34
+ url: t,
35
+ ...i.length ? { productIds: i } : {}
36
+ };
37
+ }
38
+ export {
39
+ y as buildLegacyMigrationPayload,
40
+ N as isLegacyStrategyConfig,
41
+ f as resolveMigrationTarget
42
+ };
@@ -1,12 +1,12 @@
1
1
  import { ModificationDescription as f } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
2
  import { RECOMMENDATION_ID_ATTR as m } from "../constants/selectors.js";
3
- import { isPartnerManagedBlock as a, updateProductContentInPlace as d, regenerateProductRowsWithStyles as l } from "../controls/main/utils.js";
4
- import { RecommendationConfigService as s } from "../services/configService.js";
3
+ import { isPartnerManagedBlock as l, updateProductContentInPlace as a, regenerateProductRowsWithStyles as d } from "../controls/main/utils.js";
4
+ import { RecommendationConfigService as p } from "../services/configService.js";
5
5
  let e = null;
6
- function N(r) {
6
+ function M(r) {
7
7
  e = r;
8
8
  }
9
- function D(r, c, i, u) {
9
+ function N(r, c, i, u) {
10
10
  const n = e == null ? void 0 : e.getDocumentRootHtmlNode();
11
11
  if (!e || !n || !("querySelector" in n))
12
12
  return !1;
@@ -14,9 +14,9 @@ function D(r, c, i, u) {
14
14
  if (!t)
15
15
  return !1;
16
16
  const o = e.getDocumentModifier();
17
- return s.stageConfig(o, t, c), a(t) ? (o.apply(new f(u)), !0) : (d({ currentNode: t, documentModifier: o, products: i }) || l({ currentNode: t, documentModifier: o, products: i }), !0);
17
+ return p.stageConfig(o, t, c), l(t) ? (o.apply(new f(u)), !0) : (a({ currentNode: t, documentModifier: o, products: i, forceApply: !0 }) || d({ currentNode: t, documentModifier: o, products: i, forceApply: !0 }), !0);
18
18
  }
19
19
  export {
20
- D as commitBlockChangeOutsidePanel,
21
- N as registerNodeConfigWriter
20
+ N as commitBlockChangeOutsidePanel,
21
+ M as registerNodeConfigWriter
22
22
  };