@useinsider/guido 3.19.0 → 3.20.0-beta.7b31fec

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 (62) 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 +70 -68
  5. package/dist/components/organisms/base/Toaster.vue2.js +13 -12
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +13 -11
  7. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +78 -57
  8. package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js +18 -0
  9. package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue2.js +25 -0
  10. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +28 -42
  11. package/dist/components/organisms/onboarding/OnboardingWrapper.vue2.js +28 -24
  12. package/dist/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue.js +21 -0
  13. package/dist/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue2.js +46 -0
  14. package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.js +21 -0
  15. package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue2.js +47 -0
  16. package/dist/composables/useCustomInterfaceAppearance.js +65 -51
  17. package/dist/composables/useHtmlValidator.js +87 -82
  18. package/dist/composables/useLegacyStrategyConversion.js +61 -0
  19. package/dist/composables/useRecommendation.js +40 -35
  20. package/dist/composables/useStripo.js +30 -30
  21. package/dist/composables/useToaster.js +14 -20
  22. package/dist/enums/extensions/recommendationBlock.js +49 -33
  23. package/dist/extensions/Blocks/Recommendation/block.js +61 -42
  24. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +21 -20
  25. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +100 -94
  26. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +130 -55
  27. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +74 -74
  28. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +273 -92
  29. package/dist/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js +42 -0
  30. package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +26 -16
  31. package/dist/extensions/Blocks/Recommendation/utils/strategyCommit.js +24 -0
  32. package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +21 -12
  33. package/dist/guido.css +1 -1
  34. package/dist/services/recommendationApi.js +46 -37
  35. package/dist/src/@types/config/schemas.d.ts +16 -0
  36. package/dist/src/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.d.ts +2 -0
  37. package/dist/src/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue.d.ts +2 -0
  38. package/dist/src/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.d.ts +2 -0
  39. package/dist/src/composables/useConfig.d.ts +4 -0
  40. package/dist/src/composables/useLegacyStrategyConversion.d.ts +3 -0
  41. package/dist/src/enums/extensions/recommendationBlock.d.ts +7 -1
  42. package/dist/src/extensions/Blocks/Recommendation/block.d.ts +10 -0
  43. package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +1 -0
  44. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +1 -1
  45. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +2 -0
  46. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +10 -0
  47. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +7 -2
  48. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +162 -1
  49. package/dist/src/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.d.ts +32 -0
  50. package/dist/src/extensions/Blocks/Recommendation/utils/strategyCommit.d.ts +14 -0
  51. package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +4 -0
  52. package/dist/src/services/recommendationApi.d.ts +2 -1
  53. package/dist/src/stores/config.d.ts +322 -0
  54. package/dist/src/stores/onboarding.d.ts +808 -10
  55. package/dist/static/assets/icons/filled-arrow-rising.svg.js +5 -0
  56. package/dist/static/assets/icons/line-info.svg.js +5 -0
  57. package/dist/static/styles/components/recommendation-strategy.css.js +104 -9
  58. package/dist/static/styles/components/skeleton.css.js +23 -0
  59. package/dist/stores/config.js +74 -60
  60. package/dist/stores/onboarding.js +46 -36
  61. package/dist/utils/templatePreparation.js +55 -55
  62. package/package.json +1 -1
@@ -1,27 +1,27 @@
1
1
  var m = Object.defineProperty;
2
- var C = (h, l, t) => l in h ? m(h, l, { enumerable: !0, configurable: !0, writable: !0, value: t }) : h[l] = t;
3
- var n = (h, l, t) => C(h, typeof l != "symbol" ? l + "" : l, t);
2
+ var C = (g, c, t) => c in g ? m(g, c, { enumerable: !0, configurable: !0, writable: !0, value: t }) : g[c] = t;
3
+ var i = (g, c, t) => C(g, typeof c != "symbol" ? c + "" : c, t);
4
4
  import { useConfig as p } from "../../../../../composables/useConfig.js";
5
5
  import { ModificationDescription as y } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
6
6
  import { CommonControl as N } from "../../../common-control.js";
7
- import { CURRENT_CONFIG_VERSION as _, DEFAULT_NODE_CONFIG as a } from "../../constants/defaultConfig.js";
7
+ import { RRS_CONFIG_VERSION as _, DEFAULT_NODE_CONFIG as a } from "../../constants/defaultConfig.js";
8
8
  import { RECOMMENDATION_ID_ATTR as I } from "../../constants/selectors.js";
9
- import { RecommendationConfigService as c } from "../../services/configService.js";
9
+ import { RecommendationConfigService as l } from "../../services/configService.js";
10
10
  import { useRecommendationExtensionStore as R } from "../../store/recommendation.js";
11
11
  import { registerNodeConfigWriter as b } from "../../utils/nodeConfigWriter.js";
12
12
  import { AlgorithmControl as T } from "./algorithm.js";
13
- import { ALGORITHM_CONTROL_ID as ut } from "./algorithm.js";
13
+ import { ALGORITHM_CONTROL_ID as dt } from "./algorithm.js";
14
14
  import { CurrencyControl as P } from "./currency.js";
15
- import { CURRENCY_CONTROL_ID as ht } from "./currency.js";
15
+ import { CURRENCY_CONTROL_ID as gt } from "./currency.js";
16
16
  import { FiltersControl as S } from "./filters.js";
17
- import { FILTERS_CONTROL_ID as gt } from "./filters.js";
17
+ import { FILTERS_CONTROL_ID as ft } from "./filters.js";
18
18
  import { LayoutOrientationControl as O } from "./layoutOrientation.js";
19
19
  import { LAYOUT_ORIENTATION_CONTROL_ID as Ct } from "./layoutOrientation.js";
20
20
  import { LocaleControl as L } from "./locale.js";
21
21
  import { LOCALE_CONTROL_ID as yt } from "./locale.js";
22
- import { PricePlacementControl as E } from "./pricePlacement.js";
22
+ import { PricePlacementControl as k } from "./pricePlacement.js";
23
23
  import { PRICE_PLACEMENT_CONTROL_ID as _t } from "./pricePlacement.js";
24
- import { ProductCountControl as k } from "./productCount.js";
24
+ import { ProductCountControl as E } from "./productCount.js";
25
25
  import { PRODUCT_COUNT_CONTROL_ID as Rt } from "./productCount.js";
26
26
  import { ProductLayoutControl as F } from "./productLayout.js";
27
27
  import { PRODUCT_LAYOUT_CONTROL_ID as Tt } from "./productLayout.js";
@@ -29,36 +29,36 @@ import { ShuffleControl as D } from "./shuffle.js";
29
29
  import { SHUFFLE_CONTROL_ID as St } from "./shuffle.js";
30
30
  import { StrategyControl as w } from "./strategy.js";
31
31
  import { STRATEGY_CONTROL_ID as Lt } from "./strategy.js";
32
- import { setCurrencyAttributes as A, getBlockElement as v, isPartnerManagedBlock as x, updateProductContentInPlace as B, regenerateProductRowsWithStyles as U } from "./utils.js";
33
- import { adjustProductsToSize as kt, formatProductPrice as Ft, getCardComposition as Dt, getCurrentLayout as wt, getMainContainerTbody as At, regenerateMobileProductRows as vt, updatePricesInPlace as xt, updateSingleProductContent as Bt } from "./utils.js";
34
- import { useDebounceFn as f } from "../../../../../node_modules/@vueuse/shared/index.js";
35
- const $ = "ui-elements-recommendation-block";
32
+ import { setCurrencyAttributes as A, getBlockElement as B, isPartnerManagedBlock as v, updateProductContentInPlace as x, regenerateProductRowsWithStyles as U } from "./utils.js";
33
+ import { adjustProductsToSize as Et, formatProductPrice as Ft, getCardComposition as Dt, getCurrentLayout as wt, getMainContainerTbody as At, regenerateMobileProductRows as Bt, updatePricesInPlace as vt, updateSingleProductContent as xt } from "./utils.js";
34
+ import { useDebounceFn as h } from "../../../../../node_modules/@vueuse/shared/index.js";
35
+ const W = "ui-elements-recommendation-block";
36
36
  class at extends N {
37
37
  constructor() {
38
38
  super(...arguments);
39
- n(this, "store", R());
40
- n(this, "storeUnsubscription", () => {
39
+ i(this, "store", R());
40
+ i(this, "storeUnsubscription", () => {
41
41
  });
42
42
  // A config change waiting to reach the node config. Deferred so it can ride the
43
43
  // re-render's single apply() — one user action must cost one undo press.
44
- n(this, "pendingNodeConfigWrite", null);
45
- n(this, "pendingConfigFlushTimer", null);
44
+ i(this, "pendingNodeConfigWrite", null);
45
+ i(this, "pendingConfigFlushTimer", null);
46
46
  // Sub-control instances for lifecycle management
47
- n(this, "algorithmControl", null);
48
- n(this, "localeControl", null);
49
- n(this, "currencyControl", null);
50
- n(this, "productCountControl", null);
51
- n(this, "productLayoutControl", null);
52
- n(this, "filtersControl", null);
53
- n(this, "shuffleControl", null);
54
- n(this, "pricePlacementControl", null);
55
- n(this, "layoutOrientationControl", null);
56
- n(this, "strategyControl", null);
57
- n(this, "rrsEnabled", !1);
47
+ i(this, "algorithmControl", null);
48
+ i(this, "localeControl", null);
49
+ i(this, "currencyControl", null);
50
+ i(this, "productCountControl", null);
51
+ i(this, "productLayoutControl", null);
52
+ i(this, "filtersControl", null);
53
+ i(this, "shuffleControl", null);
54
+ i(this, "pricePlacementControl", null);
55
+ i(this, "layoutOrientationControl", null);
56
+ i(this, "strategyControl", null);
57
+ i(this, "rrsEnabled", !1);
58
58
  /**
59
59
  * Debounced product fetch to prevent rapid API calls during config changes
60
60
  */
61
- n(this, "_debouncedFetchProducts", f(async () => {
61
+ i(this, "_debouncedFetchProducts", h(async () => {
62
62
  try {
63
63
  await this.store.fetchRecommendationProducts();
64
64
  } finally {
@@ -76,16 +76,16 @@ class at extends N {
76
76
  * count. The store pads products to the configured size, so in-place only
77
77
  * fails when the size actually changed.
78
78
  */
79
- n(this, "_debouncedRegenerateWithProducts", f(() => {
79
+ i(this, "_debouncedRegenerateWithProducts", h(() => {
80
80
  const t = this.store.recommendationProducts;
81
81
  if (!this.currentNode || !this.api)
82
82
  return;
83
83
  const e = this.api.getDocumentModifier(), o = this._stagePendingNodeConfig(e);
84
- if (x(this.currentNode)) {
84
+ if (v(this.currentNode)) {
85
85
  o && (e.apply(new y("Update recommendation configuration")), this.pendingNodeConfigWrite = null, this._clearConfigFlush());
86
86
  return;
87
87
  }
88
- B({
88
+ x({
89
89
  currentNode: this.currentNode,
90
90
  documentModifier: e,
91
91
  products: t
@@ -97,7 +97,7 @@ class at extends N {
97
97
  }, 100));
98
98
  }
99
99
  getId() {
100
- return $;
100
+ return W;
101
101
  }
102
102
  get _subControls() {
103
103
  return [
@@ -118,7 +118,7 @@ class at extends N {
118
118
  return this.rrsEnabled = p().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((e) => {
119
119
  var o;
120
120
  return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
121
- }), this.algorithmControl = new T(), this.localeControl = new L(), this.currencyControl = new P(), this.productCountControl = new k(), this.productLayoutControl = new F(), this.filtersControl = new S(), this.shuffleControl = new D(), this.pricePlacementControl = new E(), this.layoutOrientationControl = new O(), this.strategyControl = this.rrsEnabled ? new w() : null, this._subControls.forEach((e) => {
121
+ }), this.algorithmControl = new T(), this.localeControl = new L(), this.currencyControl = new P(), this.productCountControl = new E(), this.productLayoutControl = new F(), this.filtersControl = new S(), this.shuffleControl = new D(), this.pricePlacementControl = new k(), this.layoutOrientationControl = new O(), this.strategyControl = this.rrsEnabled ? new w() : null, this._subControls.forEach((e) => {
122
122
  e && (e.api = this.api);
123
123
  }), `
124
124
  <div class="recommendation-controls-container">
@@ -136,18 +136,18 @@ class at extends N {
136
136
  `;
137
137
  }
138
138
  _showControlsForBlock(t) {
139
- var i;
140
- const e = (i = this.getContainer()) == null ? void 0 : i.querySelector(".recommendation-controls-container");
139
+ var r;
140
+ const e = (r = this.getContainer()) == null ? void 0 : r.querySelector(".recommendation-controls-container");
141
141
  if (!e)
142
142
  return;
143
- const o = this._getRecommendationIdFromNode(t) === null ? null : c.getConfig(t), r = this.rrsEnabled && !!o && (!!(o != null && o.strategyId) || ((o == null ? void 0 : o.configVersion) ?? 0) >= _);
144
- e.classList.toggle("strategy-block", r);
143
+ const o = this._getRecommendationIdFromNode(t) === null ? null : l.getConfig(t), n = this.rrsEnabled && !!o && (!!(o != null && o.strategyId) || ((o == null ? void 0 : o.configVersion) ?? 0) >= _), s = this.rrsEnabled && !!o && !n;
144
+ e.classList.toggle("strategy-block", n), e.classList.toggle("legacy-strategy-block", s);
145
145
  }
146
146
  async onRender() {
147
147
  var o;
148
148
  b(this.api);
149
149
  const t = this._getRecommendationIdFromNode(this.currentNode), e = t ?? this.store.currentRecommendationId;
150
- if (e !== null && this.store.setCurrentBlock(e), t !== null && this._syncNodeConfigIfChanged(t), this._listenStateUpdates(), this._showControlsForBlock(this.currentNode), e !== null && ((o = this.store.blockStates[e]) != null && o.isInitialized)) {
150
+ if (e !== null && this.store.setCurrentBlock(e), t !== null && this._syncNodeConfigIfChanged(t), this._listenStateUpdates(), this._showControlsForBlock(this.currentNode), t !== null && this.strategyControl && (this.strategyControl.api = this.api, this.strategyControl.currentNode = this.currentNode, this.strategyControl.onRender()), e !== null && ((o = this.store.blockStates[e]) != null && o.isInitialized)) {
151
151
  this._initializeSubControls();
152
152
  return;
153
153
  }
@@ -159,9 +159,9 @@ class at extends N {
159
159
  const e = this._getRecommendationIdFromNode(t);
160
160
  e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null && this._syncNodeConfigIfChanged(e), this._showControlsForBlock(t), e !== null && !((o = this.store.blockStates[e]) != null && o.isInitialized) && this._fetchBlockData(e).then(() => {
161
161
  this._initializeSubControls();
162
- }), this._subControls.forEach((r) => {
163
- var i;
164
- r != null && r.api && (r.currentNode = t, (i = r.onTemplateNodeUpdated) == null || i.call(r, t));
162
+ }), this._subControls.forEach((n) => {
163
+ var s;
164
+ n != null && n.api && (n.currentNode = t, (s = n.onTemplateNodeUpdated) == null || s.call(n, t));
165
165
  });
166
166
  }
167
167
  onDestroy() {
@@ -209,18 +209,23 @@ class at extends N {
209
209
  const e = this.store.blockStates[t];
210
210
  if (!e)
211
211
  return;
212
- const o = JSON.stringify(c.getConfig(this.currentNode)), r = e.syncedConfigFingerprint;
213
- e.syncedConfigFingerprint = o, r !== o && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
212
+ const o = JSON.stringify(l.getConfig(this.currentNode)), n = e.syncedConfigFingerprint;
213
+ e.syncedConfigFingerprint = o, n !== o && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
214
+ }
215
+ /** Whether the deferred write would move the node's strategyId — see the caller (SD-149916). */
216
+ _isPendingStrategyIdChange() {
217
+ const t = this.pendingNodeConfigWrite;
218
+ return t ? l.getConfig(this.currentNode).strategyId !== t.updates.strategyId : !1;
214
219
  }
215
220
  _capturePendingNodeConfigWrite() {
216
221
  const t = this.store.currentRecommendationId;
217
222
  if (!this.currentNode || !this.api || t === null)
218
223
  return;
219
- const { filters: e, strategyId: o, size: r } = this.store.recommendationConfigs;
224
+ const { filters: e, strategy: o, strategyId: n, size: s, nodeConfigVersion: r } = this.store.recommendationConfigs;
220
225
  this.pendingNodeConfigWrite = {
221
226
  blockId: t,
222
227
  node: this.currentNode,
223
- updates: { filters: e, strategyId: o, size: r }
228
+ updates: { filters: e, strategy: o, strategyId: n, size: s, configVersion: r }
224
229
  };
225
230
  }
226
231
  /**
@@ -235,7 +240,7 @@ class at extends N {
235
240
  */
236
241
  _stagePendingNodeConfig(t) {
237
242
  const e = this.pendingNodeConfigWrite;
238
- return !e || !this.currentNode ? !1 : (c.stageConfig(t, this.currentNode, e.updates), !0);
243
+ return !e || !this.currentNode ? !1 : (l.stageConfig(t, this.currentNode, e.updates), !0);
239
244
  }
240
245
  /**
241
246
  * Arms the guaranteed fallback write, once the product fetch has settled. The
@@ -259,15 +264,16 @@ class at extends N {
259
264
  const t = this.pendingNodeConfigWrite;
260
265
  if (this.pendingNodeConfigWrite = null, this._clearConfigFlush(), !t || !this.api)
261
266
  return;
262
- const e = t.blockId === this.store.currentRecommendationId && this.currentNode ? this.currentNode : t.node, o = c.getConfig(e);
263
- JSON.stringify(o.filters) === JSON.stringify(t.updates.filters) && o.strategyId === t.updates.strategyId && o.size === t.updates.size || c.updateConfig(this.api, e, t.updates, "Update recommendation filters");
267
+ const e = t.blockId === this.store.currentRecommendationId && this.currentNode ? this.currentNode : t.node, o = l.getConfig(e);
268
+ JSON.stringify(o.filters) === JSON.stringify(t.updates.filters) && o.strategy === t.updates.strategy && o.strategyId === t.updates.strategyId && o.size === t.updates.size || l.updateConfig(this.api, e, t.updates, "Update recommendation filters");
264
269
  }
265
270
  _syncNodeConfigToStore() {
266
- var r;
267
- const t = c.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((r = this.store.blockStates[e]) == null ? void 0 : r.isInitialized);
271
+ var n;
272
+ const t = l.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((n = this.store.blockStates[e]) == null ? void 0 : n.isInitialized);
268
273
  this.store.patchCurrentBlockConfig({
269
274
  strategy: t.strategy,
270
275
  strategyId: t.strategyId,
276
+ nodeConfigVersion: t.configVersion,
271
277
  language: t.language,
272
278
  size: t.size,
273
279
  productIds: t.productIds,
@@ -306,8 +312,8 @@ class at extends N {
306
312
  t !== null && this.store.markBlockInitialized(t), (await Promise.allSettled([
307
313
  this.store.fetchRecommendationCreateData(),
308
314
  this.store.fetchRecommendationFilters()
309
- ])).forEach((o, r) => {
310
- o.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][r]} failed`, o.reason);
315
+ ])).forEach((o, n) => {
316
+ o.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][n]} failed`, o.reason);
311
317
  }), this._applySmartDefaults();
312
318
  try {
313
319
  await this.store.fetchRecommendationProducts();
@@ -328,31 +334,31 @@ class at extends N {
328
334
  _applySmartDefaults() {
329
335
  if (!this.currentNode || !this.api)
330
336
  return;
331
- const t = c.getConfig(this.currentNode), e = {};
332
- let o = null, r = null, i = null;
337
+ const t = l.getConfig(this.currentNode), e = {};
338
+ let o = null, n = null, s = null;
333
339
  if (t.currency.code === a.currency.code) {
334
- const { currencyList: s } = this.store;
335
- s.length > 0 && (s.some(
336
- (d) => d.value === `price.${a.currency.code}`
337
- ) || (o = s[0].value.replace("price.", ""), e.currency = {
340
+ const { currencyList: r } = this.store;
341
+ r.length > 0 && (r.some(
342
+ (u) => u.value === `price.${a.currency.code}`
343
+ ) || (o = r[0].value.replace("price.", ""), e.currency = {
338
344
  ...a.currency,
339
345
  code: o,
340
346
  symbol: o
341
347
  }));
342
348
  }
343
349
  if (t.strategy === a.strategy) {
344
- const s = this.store.getActivePredictiveAlgorithms;
345
- s.length > 0 && (s.some(
346
- (d) => d.value === a.strategy
347
- ) || (r = s[0].value, e.strategy = r));
350
+ const r = this.store.getActivePredictiveAlgorithms;
351
+ r.length > 0 && (r.some(
352
+ (u) => u.value === a.strategy
353
+ ) || (n = r[0].value, e.strategy = n));
348
354
  }
349
355
  if (t.language === a.language) {
350
- const s = this.store.getLanguages;
351
- s.length > 0 && (s.some(
352
- (d) => d.value === a.language
353
- ) || (i = s[0].value, e.language = i));
356
+ const r = this.store.getLanguages;
357
+ r.length > 0 && (r.some(
358
+ (u) => u.value === a.language
359
+ ) || (s = r[0].value, e.language = s));
354
360
  }
355
- !o && !r && !i || (c.updateConfig(
361
+ !o && !n && !s || (l.updateConfig(
356
362
  this.api,
357
363
  this.currentNode,
358
364
  e,
@@ -373,22 +379,22 @@ class at extends N {
373
379
  thousandSeparator: a.currency.thousandSeparator
374
380
  }
375
381
  } : {},
376
- ...r ? { strategy: r } : {},
377
- ...i ? { language: i } : {}
382
+ ...n ? { strategy: n } : {},
383
+ ...s ? { language: s } : {}
378
384
  }, { triggerRefetch: !1 }));
379
385
  }
380
386
  /**
381
387
  * Reads the recommendation-id attribute from the block element within the node
382
388
  */
383
389
  _getRecommendationIdFromNode(t) {
384
- const e = v(t);
390
+ const e = B(t);
385
391
  if (!e || !("getAttribute" in e))
386
392
  return null;
387
393
  const o = e.getAttribute(I);
388
394
  if (!o)
389
395
  return null;
390
- const r = parseInt(o);
391
- return Number.isNaN(r) ? null : r;
396
+ const n = parseInt(o);
397
+ return Number.isNaN(n) ? null : n;
392
398
  }
393
399
  /**
394
400
  * Listen to store changes that require product refresh or regeneration.
@@ -405,27 +411,27 @@ class at extends N {
405
411
  */
406
412
  _listenStateUpdates() {
407
413
  const { store: t } = this;
408
- let e = t.recommendationProducts, o = t.$state.configVersion, r = t.currentRecommendationId;
414
+ let e = t.recommendationProducts, o = t.$state.configVersion, n = t.currentRecommendationId;
409
415
  this.storeUnsubscription = t.$subscribe(() => {
410
- const i = t.currentRecommendationId;
411
- if (i !== r) {
412
- r = i, e = t.recommendationProducts, o = t.$state.configVersion;
416
+ const s = t.currentRecommendationId;
417
+ if (s !== n) {
418
+ n = s, e = t.recommendationProducts, o = t.$state.configVersion;
413
419
  return;
414
420
  }
415
- const s = t.$state.configVersion;
416
- s !== o && (o = s, this._capturePendingNodeConfigWrite(), this._debouncedFetchProducts());
417
- const u = t.recommendationProducts, d = u !== e, g = Array.isArray(u) && u.length > 0;
418
- d && g && (e = u, this._debouncedRegenerateWithProducts());
421
+ const r = t.$state.configVersion;
422
+ r !== o && (o = r, this._capturePendingNodeConfigWrite(), this._isPendingStrategyIdChange() && this._flushPendingNodeConfig(), this._debouncedFetchProducts());
423
+ const d = t.recommendationProducts, u = d !== e, f = Array.isArray(d) && d.length > 0;
424
+ u && f && (e = d, this._debouncedRegenerateWithProducts());
419
425
  });
420
426
  }
421
427
  }
422
428
  export {
423
- ut as ALGORITHM_CONTROL_ID,
429
+ dt as ALGORITHM_CONTROL_ID,
424
430
  T as AlgorithmControl,
425
- $ as CONTROL_BLOCK_ID,
426
- ht as CURRENCY_CONTROL_ID,
431
+ W as CONTROL_BLOCK_ID,
432
+ gt as CURRENCY_CONTROL_ID,
427
433
  P as CurrencyControl,
428
- gt as FILTERS_CONTROL_ID,
434
+ ft as FILTERS_CONTROL_ID,
429
435
  S as FiltersControl,
430
436
  Ct as LAYOUT_ORIENTATION_CONTROL_ID,
431
437
  yt as LOCALE_CONTROL_ID,
@@ -434,25 +440,25 @@ export {
434
440
  _t as PRICE_PLACEMENT_CONTROL_ID,
435
441
  Rt as PRODUCT_COUNT_CONTROL_ID,
436
442
  Tt as PRODUCT_LAYOUT_CONTROL_ID,
437
- E as PricePlacementControl,
438
- k as ProductCountControl,
443
+ k as PricePlacementControl,
444
+ E as ProductCountControl,
439
445
  F as ProductLayoutControl,
440
446
  at as RecommendationBlockControl,
441
447
  St as SHUFFLE_CONTROL_ID,
442
448
  Lt as STRATEGY_CONTROL_ID,
443
449
  D as ShuffleControl,
444
450
  w as StrategyControl,
445
- kt as adjustProductsToSize,
451
+ Et as adjustProductsToSize,
446
452
  Ft as formatProductPrice,
447
- v as getBlockElement,
453
+ B as getBlockElement,
448
454
  Dt as getCardComposition,
449
455
  wt as getCurrentLayout,
450
456
  At as getMainContainerTbody,
451
- x as isPartnerManagedBlock,
452
- vt as regenerateMobileProductRows,
457
+ v as isPartnerManagedBlock,
458
+ Bt as regenerateMobileProductRows,
453
459
  U as regenerateProductRowsWithStyles,
454
460
  A as setCurrencyAttributes,
455
- xt as updatePricesInPlace,
456
- B as updateProductContentInPlace,
457
- Bt as updateSingleProductContent
461
+ vt as updatePricesInPlace,
462
+ x as updateProductContentInPlace,
463
+ xt as updateSingleProductContent
458
464
  };
@@ -1,43 +1,64 @@
1
- var d = Object.defineProperty;
2
- var y = (r, s, t) => s in r ? d(r, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[s] = t;
3
- var o = (r, s, t) => y(r, typeof s != "symbol" ? s + "" : s, t);
4
- import { ACADEMY_LINKS as m } from "../../../../../enums/academy.js";
5
- import { CommonControl as h } from "../../../common-control.js";
6
- import { useRecommendationExtensionStore as u } from "../../store/recommendation.js";
7
- const p = "recommendation-strategy-control";
8
- class f extends h {
1
+ var C = Object.defineProperty;
2
+ var $ = (c, n, t) => n in c ? C(c, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[n] = t;
3
+ var i = (c, n, t) => $(c, typeof n != "symbol" ? n + "" : n, t);
4
+ import { useLegacyStrategyConversion as k } from "../../../../../composables/useLegacyStrategyConversion.js";
5
+ import { ACADEMY_LINKS as L } from "../../../../../enums/academy.js";
6
+ import { useOnboardingStore as w } from "../../../../../stores/onboarding.js";
7
+ import { CommonControl as A } from "../../../common-control.js";
8
+ import { RRS_CONFIG_VERSION as N } from "../../constants/defaultConfig.js";
9
+ import { RecommendationConfigService as b } from "../../services/configService.js";
10
+ import { useRecommendationExtensionStore as R } from "../../store/recommendation.js";
11
+ const E = "recommendation-strategy-control";
12
+ class M extends A {
9
13
  constructor() {
10
14
  super(...arguments);
11
- o(this, "store", u());
12
- o(this, "storeUnsubscription", () => {
15
+ i(this, "store", R());
16
+ i(this, "onboardingStore", w());
17
+ i(this, "legacyConversion", k());
18
+ i(this, "storeUnsubscription", () => {
13
19
  });
14
- o(this, "listeners", []);
15
- o(this, "lastPaintedState", null);
20
+ i(this, "listeners", []);
21
+ i(this, "lastPaintedState", null);
16
22
  }
17
23
  getId() {
18
- return p;
24
+ return E;
19
25
  }
20
26
  getTemplate() {
21
27
  const t = this.api.translate(
22
28
  "You can assign a recommendation strategy by selecting an existing one or creating a new one to show specific content."
23
- ), e = this.api.translate("For more information, you can"), a = this.api.translate("visit Academy");
29
+ ), e = this.api.translate("For more information, you can"), s = this.api.translate("visit Academy"), o = this.api.translate("Legacy Strategy"), a = this.api.translate(
30
+ "Note that this is an older version of the Recommendation Strategy. We recommend you update it to the new Recommendation Strategy for an improved experience."
31
+ );
24
32
  return `
25
33
  <div class="strategy-control-container">
26
- <div class="strategy-control-header">
27
- <h3 class="strategy-control-title">${this.api.translate("Recommendation Strategy")}</h3>
28
- </div>
29
- <div class="strategy-control-description-row">
30
- <p class="strategy-control-description">
31
- ${t}
32
- ${e}
33
- <a
34
- href="${m.EMAIL_RECOMMENDATION_BLOCK}"
35
- target="_blank"
36
- rel="noopener noreferrer">${a}</a>.
37
- </p>
34
+ <div data-strategy-loading-state>
35
+ <div class="strategy-control-header">
36
+ <span class="guido-skeleton guido-skeleton--strategy-title"></span>
37
+ </div>
38
+ <div class="strategy-control-description-row">
39
+ <span class="guido-skeleton guido-skeleton--strategy-description"></span>
40
+ </div>
41
+ <div class="strategy-control-skeleton-row">
42
+ <span class="guido-skeleton guido-skeleton--strategy-cta"></span>
43
+ <span class="guido-skeleton guido-skeleton--strategy-cta"></span>
44
+ </div>
38
45
  </div>
39
- <div data-strategy-empty-state>
40
- ${this._GuTwoColumns([
46
+ <div data-strategy-content style="display: none;">
47
+ <div class="strategy-control-header">
48
+ <h3 class="strategy-control-title">${this.api.translate("Recommendation Strategy")}</h3>
49
+ </div>
50
+ <div class="strategy-control-description-row">
51
+ <p class="strategy-control-description">
52
+ ${t}
53
+ ${e}
54
+ <a
55
+ href="${L.EMAIL_RECOMMENDATION_BLOCK}"
56
+ target="_blank"
57
+ rel="noopener noreferrer">${s}</a>.
58
+ </p>
59
+ </div>
60
+ <div data-strategy-empty-state style="display: none;">
61
+ ${this._GuTwoColumns([
41
62
  this._GuButton({
42
63
  name: "assignStrategy",
43
64
  label: this.api.translate("Assign Strategy"),
@@ -48,77 +69,131 @@ class f extends h {
48
69
  name: "createStrategy",
49
70
  label: this.api.translate("Create New Strategy"),
50
71
  id: "guido__btn-create-strategy",
51
- className: "strategy-control-cta primary",
52
- disabled: !0
72
+ className: "strategy-control-cta primary"
53
73
  })
54
74
  ], "strategy-control-cta-row")}
55
- </div>
56
- <div data-strategy-assigned-state style="display: none;">
57
- <div class="strategy-control-name-band">
58
- <span class="strategy-control-name" data-strategy-name></span>
59
75
  </div>
60
- <div class="strategy-control-actions">
61
- ${this._strategyAction({
76
+ <div data-strategy-legacy-state style="display: none;">
77
+ <div class="strategy-control-notice-row">
78
+ <div class="strategy-control-notice">
79
+ <p class="strategy-control-notice-text">${a}</p>
80
+ </div>
81
+ </div>
82
+ <div class="strategy-control-name-band">
83
+ <span class="strategy-control-name">${o}</span>
84
+ ${this._strategyAction({
85
+ id: "guido__btn-update-legacy-strategy",
86
+ label: this.api.translate("Update"),
87
+ modifier: "update"
88
+ })}
89
+ </div>
90
+ <div class="strategy-control-actions">
91
+ ${this._strategyAction({
92
+ id: "guido__btn-change-legacy-strategy",
93
+ label: this.api.translate("Change"),
94
+ modifier: "change"
95
+ })}
96
+ ${this._strategyAction({
97
+ id: "guido__btn-remove-legacy-strategy",
98
+ label: this.api.translate("Remove"),
99
+ modifier: "remove"
100
+ })}
101
+ </div>
102
+ </div>
103
+ <div data-strategy-assigned-state style="display: none;">
104
+ <div class="strategy-control-name-band">
105
+ <span class="strategy-control-name" data-strategy-name></span>
106
+ <span
107
+ class="guido-skeleton guido-skeleton--strategy-name" data-strategy-name-skeleton></span>
108
+ </div>
109
+ <div class="strategy-control-actions">
110
+ ${this._strategyAction({
62
111
  id: "guido__btn-change-strategy",
63
112
  label: this.api.translate("Change"),
64
113
  modifier: "change"
65
114
  })}
66
- ${this._strategyAction({
115
+ ${this._strategyAction({
67
116
  id: "guido__btn-remove-strategy",
68
117
  label: this.api.translate("Remove"),
69
118
  modifier: "remove"
70
119
  })}
120
+ </div>
71
121
  </div>
72
122
  </div>
73
123
  </div>
74
124
  `;
75
125
  }
76
- _strategyAction({ id: t, label: e, modifier: a }) {
126
+ _strategyAction({ id: t, label: e, modifier: s }) {
77
127
  return `
78
128
  <button
79
129
  id="${t}"
80
130
  type="button"
81
- class="strategy-control-action strategy-control-action--${a}">
131
+ class="strategy-control-action strategy-control-action--${s}">
82
132
  <span>${e}</span>
83
133
  </button>
84
134
  `;
85
135
  }
86
136
  onRender() {
87
- this._teardown(), this._setupButtonListeners(), this._renderState(), this.storeUnsubscription = this.store.$subscribe(() => {
137
+ this._teardown(), this.store.strategyPanelOpen = !0, this._setupButtonListeners(), this._renderState(), this.storeUnsubscription = this.store.$subscribe(() => {
88
138
  this._renderState();
89
- }), this.store.recommendationConfigs.strategyId && !this.store.strategies.length && this.store.fetchStrategies().catch(() => {
139
+ }), this.store.recommendationConfigs.strategyId && !this.store.strategiesFetched && this.store.fetchStrategies().catch(() => {
90
140
  });
91
141
  }
142
+ /**
143
+ * Whether the document itself says this block has no strategy.
144
+ *
145
+ * Read the node, not the store: when the main control cannot resolve the block id off the
146
+ * node it never syncs the persisted config, so the store still holds defaults (empty
147
+ * strategyId) for an assigned block.
148
+ */
149
+ _isNodeUnassigned() {
150
+ if (!b.hasConfig(this.currentNode))
151
+ return !1;
152
+ const t = b.getConfig(this.currentNode);
153
+ return !t.strategyId && (t.configVersion ?? 0) >= N;
154
+ }
92
155
  onDestroy() {
93
156
  this._teardown();
94
157
  }
95
158
  _teardown() {
96
- this.storeUnsubscription(), this.storeUnsubscription = () => {
159
+ this.store.strategyPanelOpen = !1, this.storeUnsubscription(), this.storeUnsubscription = () => {
97
160
  }, this.lastPaintedState = null, this.listeners.forEach(({ element: t, handler: e }) => t.removeEventListener("click", e)), this.listeners = [];
98
161
  }
99
162
  _setupButtonListeners() {
100
163
  const t = this.getContainer();
101
164
  if (!t)
102
165
  return;
103
- const e = (a, n) => {
104
- const i = t.querySelector(a);
105
- i && (i.addEventListener("click", n), this.listeners.push({ element: i, handler: n }));
166
+ const e = (s, o) => {
167
+ const a = t.querySelector(s);
168
+ a && (a.addEventListener("click", o), this.listeners.push({ element: a, handler: o }));
106
169
  };
107
- e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.openRemoveStrategyModal());
170
+ e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-create-strategy", () => this.store.openStrategyCreation()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-change-legacy-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.openRemoveStrategyModal()), e("#guido__btn-remove-legacy-strategy", () => this.store.openRemoveStrategyModal()), e("#guido__btn-update-legacy-strategy", () => {
171
+ this.legacyConversion.convertLegacyStrategy();
172
+ });
108
173
  }
109
174
  _renderState() {
110
- var l;
111
- const { strategyId: t } = this.store.recommendationConfigs, e = t ? ((l = this.store.assignedStrategy) == null ? void 0 : l.name) ?? "" : "", a = `${t}\0${e}`;
112
- if (a === this.lastPaintedState)
175
+ var _;
176
+ const { strategyId: t } = this.store.recommendationConfigs, e = t ? ((_ = this.store.assignedStrategy) == null ? void 0 : _.name) ?? "" : "", s = !!t && !e && (this.store.strategiesLoading || !this.store.strategiesSettled), o = this.store.legacyConversionLoading, a = this.store.isLegacyStrategyBlock, h = `${t}\0${e}\0${s}\0${o}\0${a}`;
177
+ if (h === this.lastPaintedState)
178
+ return;
179
+ const r = this.getContainer();
180
+ if (!r)
113
181
  return;
114
- const n = this.getContainer();
115
- if (!n)
182
+ const d = r.querySelector("[data-strategy-empty-state]"), y = r.querySelector("[data-strategy-assigned-state]"), g = r.querySelector("[data-strategy-legacy-state]"), p = r.querySelector("[data-strategy-loading-state]"), u = r.querySelector("[data-strategy-content]"), m = r.querySelector("[data-strategy-name]"), v = r.querySelector("[data-strategy-name-skeleton]");
183
+ if (!d || !y || !g)
116
184
  return;
117
- const i = n.querySelector("[data-strategy-empty-state]"), c = n.querySelector("[data-strategy-assigned-state]"), g = n.querySelector("[data-strategy-name]");
118
- !i || !c || (i.style.display = t ? "none" : "", c.style.display = t ? "" : "none", g && t && (g.textContent = e || `#${t}`), this.lastPaintedState = a);
185
+ p && (p.style.display = "none"), u && (u.style.display = "");
186
+ const f = t ? y : a ? g : d;
187
+ [d, y, g].forEach((l) => {
188
+ l.style.display = l === f ? "" : "none";
189
+ }), g.querySelectorAll("button").forEach((l) => {
190
+ l.disabled = o;
191
+ }), g.classList.toggle("is-converting", o), !t && this._isNodeUnassigned() && this.onboardingStore.startOnboarding("recommendationStrategyOnboarding");
192
+ const S = this.store.currentRecommendationId;
193
+ a && S !== null && this.store.blockStates[S] && this.onboardingStore.startOnboarding("recommendationLegacyStrategyOnboarding"), m && (m.style.display = s ? "none" : "", t && !s && (m.textContent = e || `#${t}`)), v && (v.style.display = s ? "block" : "none"), this.lastPaintedState = h;
119
194
  }
120
195
  }
121
196
  export {
122
- p as STRATEGY_CONTROL_ID,
123
- f as StrategyControl
197
+ E as STRATEGY_CONTROL_ID,
198
+ M as StrategyControl
124
199
  };