@useinsider/guido 3.17.0-beta.3ff6ea0 → 3.17.0-beta.6255bfc

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 (76) hide show
  1. package/README.md +1 -0
  2. package/dist/@types/config/schemas.js +12 -6
  3. package/dist/components/Guido.vue.js +2 -2
  4. package/dist/components/Guido.vue2.js +31 -30
  5. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +18 -0
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +66 -0
  7. package/dist/composables/useCustomInterfaceAppearance.js +52 -38
  8. package/dist/composables/useRecommendation.js +52 -44
  9. package/dist/composables/useStripo.js +14 -14
  10. package/dist/config/migrator/index.js +8 -9
  11. package/dist/config/migrator/recommendation/compositionMapper.js +20 -20
  12. package/dist/config/migrator/recommendation/extractors.js +24 -29
  13. package/dist/config/migrator/recommendation/htmlBuilder.js +130 -116
  14. package/dist/config/migrator/recommendation/settingsMapper.js +19 -17
  15. package/dist/config/migrator/recommendationMigrator.js +15 -16
  16. package/dist/enums/academy.js +2 -1
  17. package/dist/enums/date.js +4 -3
  18. package/dist/enums/extensions/recommendationBlock.js +4 -1
  19. package/dist/extensions/Blocks/Recommendation/block.js +26 -21
  20. package/dist/extensions/Blocks/Recommendation/constants/blockIds.js +1 -1
  21. package/dist/extensions/Blocks/Recommendation/constants/controlIds.js +1 -1
  22. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +26 -25
  23. package/dist/extensions/Blocks/Recommendation/constants/selectors.js +28 -34
  24. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +256 -323
  25. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +178 -165
  26. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +142 -0
  27. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +0 -1
  28. package/dist/extensions/Blocks/Recommendation/extension.js +29 -31
  29. package/dist/extensions/Blocks/Recommendation/services/configService.js +35 -35
  30. package/dist/extensions/Blocks/Recommendation/settingsPanel.js +4 -23
  31. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +251 -110
  32. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +3 -3
  33. package/dist/extensions/Blocks/Recommendation/templates/utils.js +107 -85
  34. package/dist/extensions/Blocks/common-control.js +22 -19
  35. package/dist/guido.css +1 -1
  36. package/dist/services/recommendationApi.js +75 -30
  37. package/dist/src/@types/config/schemas.d.ts +12 -0
  38. package/dist/src/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.d.ts +3 -0
  39. package/dist/src/components/wrappers/WpModal.vue.d.ts +1 -1
  40. package/dist/src/composables/useConfig.d.ts +2 -0
  41. package/dist/src/composables/useRecommendation.d.ts +1 -0
  42. package/dist/src/config/migrator/recommendation/extractors.d.ts +0 -8
  43. package/dist/src/enums/academy.d.ts +1 -0
  44. package/dist/src/enums/extensions/recommendationBlock.d.ts +2 -0
  45. package/dist/src/extensions/Blocks/Recommendation/constants/blockIds.d.ts +1 -2
  46. package/dist/src/extensions/Blocks/Recommendation/constants/controlIds.d.ts +0 -7
  47. package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +7 -7
  48. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +2 -2
  49. package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +0 -10
  50. package/dist/src/extensions/Blocks/Recommendation/controls/cardComposition/index.d.ts +0 -10
  51. package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +0 -1
  52. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +15 -3
  53. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +30 -0
  54. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +0 -1
  55. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +206 -10
  56. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +6 -0
  57. package/dist/src/extensions/Blocks/common-control.d.ts +4 -1
  58. package/dist/src/mock/api/recommendation-strategies.d.ts +63 -0
  59. package/dist/src/services/recommendationApi.d.ts +4 -1
  60. package/dist/src/stores/config.d.ts +18 -0
  61. package/dist/src/utils/strategyInfoBox.d.ts +22 -0
  62. package/dist/static/assets/icons/line-change.svg.js +5 -0
  63. package/dist/static/assets/icons/line-delete.svg.js +5 -0
  64. package/dist/static/assets/icons/line-plus.svg.js +5 -0
  65. package/dist/static/styles/components/recommendation-strategy.css.js +188 -0
  66. package/dist/static/styles/customEditorStyle.css.js +1 -3
  67. package/dist/utils/dateUtil.js +29 -10
  68. package/dist/utils/strategyInfoBox.js +37 -0
  69. package/dist/utils/templatePreparation.js +37 -34
  70. package/package.json +2 -1
  71. package/dist/config/migrator/recommendationTitleMigrator.js +0 -119
  72. package/dist/extensions/Blocks/Recommendation/controls/title/index.js +0 -44
  73. package/dist/extensions/Blocks/Recommendation/templates/titleRows.js +0 -33
  74. package/dist/src/config/migrator/recommendationTitleMigrator.d.ts +0 -5
  75. package/dist/src/extensions/Blocks/Recommendation/controls/title/index.d.ts +0 -86
  76. package/dist/src/extensions/Blocks/Recommendation/templates/titleRows.d.ts +0 -13
@@ -1,53 +1,57 @@
1
- var f = Object.defineProperty;
2
- var p = (d, l, t) => l in d ? f(d, l, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[l] = t;
3
- var s = (d, l, t) => p(d, typeof l != "symbol" ? l + "" : l, t);
4
- import { CommonControl as g } from "../../../common-control.js";
5
- import { DEFAULT_NODE_CONFIG as c } from "../../constants/defaultConfig.js";
6
- import { RecommendationConfigService as h } from "../../services/configService.js";
7
- import { useRecommendationExtensionStore as y } from "../../store/recommendation.js";
8
- import { AlgorithmControl as N } from "./algorithm.js";
9
- import { ALGORITHM_CONTROL_ID as tt } from "./algorithm.js";
1
+ var C = Object.defineProperty;
2
+ var g = (d, c, t) => c in d ? C(d, c, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[c] = t;
3
+ var n = (d, c, t) => g(d, typeof c != "symbol" ? c + "" : c, t);
4
+ import { useConfig as p } from "../../../../../composables/useConfig.js";
5
+ import { CommonControl as y } from "../../../common-control.js";
6
+ import { CURRENT_CONFIG_VERSION as _, DEFAULT_NODE_CONFIG as a } from "../../constants/defaultConfig.js";
7
+ import { RecommendationConfigService as m } from "../../services/configService.js";
8
+ import { useRecommendationExtensionStore as N } from "../../store/recommendation.js";
9
+ import { AlgorithmControl as I } from "./algorithm.js";
10
+ import { ALGORITHM_CONTROL_ID as it } from "./algorithm.js";
10
11
  import { CurrencyControl as R } from "./currency.js";
11
- import { CURRENCY_CONTROL_ID as ot } from "./currency.js";
12
- import { FiltersControl as I } from "./filters.js";
13
- import { FILTERS_CONTROL_ID as nt } from "./filters.js";
12
+ import { CURRENCY_CONTROL_ID as at } from "./currency.js";
13
+ import { FiltersControl as T } from "./filters.js";
14
+ import { FILTERS_CONTROL_ID as lt } from "./filters.js";
14
15
  import { LayoutOrientationControl as b } from "./layoutOrientation.js";
15
- import { LAYOUT_ORIENTATION_CONTROL_ID as st } from "./layoutOrientation.js";
16
- import { LocaleControl as _ } from "./locale.js";
17
- import { LOCALE_CONTROL_ID as lt } from "./locale.js";
18
- import { PricePlacementControl as T } from "./pricePlacement.js";
19
- import { PRICE_PLACEMENT_CONTROL_ID as ut } from "./pricePlacement.js";
20
- import { ProductCountControl as O } from "./productCount.js";
21
- import { PRODUCT_COUNT_CONTROL_ID as ht } from "./productCount.js";
22
- import { ProductLayoutControl as P } from "./productLayout.js";
23
- import { PRODUCT_LAYOUT_CONTROL_ID as Ct } from "./productLayout.js";
24
- import { ShuffleControl as S } from "./shuffle.js";
25
- import { SHUFFLE_CONTROL_ID as pt } from "./shuffle.js";
26
- import { setCurrencyAttributes as L, getBlockElement as k, isPartnerManagedBlock as D, updateProductContentInPlace as E, regenerateProductRowsWithStyles as A } from "./utils.js";
27
- import { adjustProductsToSize as yt, formatProductPrice as Nt, getCardComposition as Rt, getCurrentLayout as It, getMainContainerTbody as bt, regenerateMobileProductRows as _t, updatePricesInPlace as Tt, updateSingleProductContent as Ot } from "./utils.js";
28
- import { useDebounceFn as m } from "../../../../../node_modules/@vueuse/shared/index.js";
29
- const v = "recommendation-id", w = "ui-elements-recommendation-block";
30
- class Q extends g {
16
+ import { LAYOUT_ORIENTATION_CONTROL_ID as dt } from "./layoutOrientation.js";
17
+ import { LocaleControl as S } from "./locale.js";
18
+ import { LOCALE_CONTROL_ID as ht } from "./locale.js";
19
+ import { PricePlacementControl as O } from "./pricePlacement.js";
20
+ import { PRICE_PLACEMENT_CONTROL_ID as Ct } from "./pricePlacement.js";
21
+ import { ProductCountControl as P } from "./productCount.js";
22
+ import { PRODUCT_COUNT_CONTROL_ID as pt } from "./productCount.js";
23
+ import { ProductLayoutControl as L } from "./productLayout.js";
24
+ import { PRODUCT_LAYOUT_CONTROL_ID as _t } from "./productLayout.js";
25
+ import { ShuffleControl as k } from "./shuffle.js";
26
+ import { SHUFFLE_CONTROL_ID as It } from "./shuffle.js";
27
+ import { StrategyControl as E } from "./strategy.js";
28
+ import { STRATEGY_CONTROL_ID as Tt } from "./strategy.js";
29
+ import { setCurrencyAttributes as D, getBlockElement as w, isPartnerManagedBlock as B, updateProductContentInPlace as v, regenerateProductRowsWithStyles as $ } from "./utils.js";
30
+ import { adjustProductsToSize as St, formatProductPrice as Ot, getCardComposition as Pt, getCurrentLayout as Lt, regenerateMobileProductRows as kt, updatePricesInPlace as Et, updateSingleProductContent as Dt } from "./utils.js";
31
+ import { useDebounceFn as h } from "../../../../../node_modules/@vueuse/shared/index.js";
32
+ const A = "recommendation-id", x = "ui-elements-recommendation-block";
33
+ class ot extends y {
31
34
  constructor() {
32
35
  super(...arguments);
33
- s(this, "store", y());
34
- s(this, "storeUnsubscription", () => {
36
+ n(this, "store", N());
37
+ n(this, "storeUnsubscription", () => {
35
38
  });
36
- s(this, "syncedBlockIds", /* @__PURE__ */ new Set());
39
+ n(this, "syncedBlockIds", /* @__PURE__ */ new Set());
37
40
  // Sub-control instances for lifecycle management
38
- s(this, "algorithmControl", null);
39
- s(this, "localeControl", null);
40
- s(this, "currencyControl", null);
41
- s(this, "productCountControl", null);
42
- s(this, "productLayoutControl", null);
43
- s(this, "filtersControl", null);
44
- s(this, "shuffleControl", null);
45
- s(this, "pricePlacementControl", null);
46
- s(this, "layoutOrientationControl", null);
41
+ n(this, "algorithmControl", null);
42
+ n(this, "localeControl", null);
43
+ n(this, "currencyControl", null);
44
+ n(this, "productCountControl", null);
45
+ n(this, "productLayoutControl", null);
46
+ n(this, "filtersControl", null);
47
+ n(this, "shuffleControl", null);
48
+ n(this, "pricePlacementControl", null);
49
+ n(this, "layoutOrientationControl", null);
50
+ n(this, "strategyControl", null);
47
51
  /**
48
52
  * Debounced product fetch to prevent rapid API calls during config changes
49
53
  */
50
- s(this, "_debouncedFetchProducts", m(() => {
54
+ n(this, "_debouncedFetchProducts", h(() => {
51
55
  this.store.fetchRecommendationProducts();
52
56
  }, 500));
53
57
  /**
@@ -61,16 +65,16 @@ class Q extends g {
61
65
  * count. The store pads products to the configured size, so in-place only
62
66
  * fails when the size actually changed.
63
67
  */
64
- s(this, "_debouncedRegenerateWithProducts", m(() => {
68
+ n(this, "_debouncedRegenerateWithProducts", h(() => {
65
69
  const t = this.store.recommendationProducts;
66
- if (!this.currentNode || !this.api || D(this.currentNode))
70
+ if (!this.currentNode || !this.api || B(this.currentNode))
67
71
  return;
68
72
  const e = this.api.getDocumentModifier();
69
- E({
73
+ v({
70
74
  currentNode: this.currentNode,
71
75
  documentModifier: e,
72
76
  products: t
73
- }) || A({
77
+ }) || $({
74
78
  currentNode: this.currentNode,
75
79
  documentModifier: e,
76
80
  products: t
@@ -78,22 +82,44 @@ class Q extends g {
78
82
  }, 100));
79
83
  }
80
84
  getId() {
81
- return w;
85
+ return x;
82
86
  }
83
- getTemplate() {
84
- return this.algorithmControl = new N(), this.localeControl = new _(), this.currencyControl = new R(), this.productCountControl = new O(), this.productLayoutControl = new P(), this.filtersControl = new I(), this.shuffleControl = new S(), this.pricePlacementControl = new T(), this.layoutOrientationControl = new b(), [
87
+ /** Every sub-control the coordinator owns, in panel order. */
88
+ get _subControls() {
89
+ return [
90
+ this.layoutOrientationControl,
91
+ this.productCountControl,
85
92
  this.algorithmControl,
86
93
  this.localeControl,
87
94
  this.currencyControl,
88
- this.productCountControl,
89
95
  this.productLayoutControl,
90
96
  this.filtersControl,
91
97
  this.shuffleControl,
92
98
  this.pricePlacementControl,
93
- this.layoutOrientationControl
94
- ].forEach((e) => {
95
- e.api = this.api;
96
- }), `
99
+ this.strategyControl
100
+ ];
101
+ }
102
+ getTemplate() {
103
+ const t = p().isFeatureEnabled("reusableRecommendationStrategy");
104
+ return this._subControls.forEach((e) => {
105
+ var o;
106
+ return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
107
+ }), this.algorithmControl = new I(), this.localeControl = new S(), this.currencyControl = new R(), this.productCountControl = new P(), this.productLayoutControl = new L(), this.filtersControl = new T(), this.shuffleControl = new k(), this.pricePlacementControl = new O(), this.layoutOrientationControl = new b(), this.strategyControl = t ? new E() : null, this._subControls.forEach((e) => {
108
+ e && (e.api = this.api);
109
+ }), t ? `
110
+ <div class="recommendation-controls-container">
111
+ ${this.strategyControl.getTemplate()}
112
+ ${this.layoutOrientationControl.getTemplate()}
113
+ ${this.productCountControl.getTemplate()}
114
+ ${this.productLayoutControl.getTemplate()}
115
+ ${this.algorithmControl.getTemplate()}
116
+ ${this.localeControl.getTemplate()}
117
+ ${this.pricePlacementControl.getTemplate()}
118
+ ${this.currencyControl.getTemplate()}
119
+ ${this.filtersControl.getTemplate()}
120
+ ${this.shuffleControl.getTemplate()}
121
+ </div>
122
+ ` : `
97
123
  <div class="recommendation-controls-container">
98
124
  ${this.layoutOrientationControl.getTemplate()}
99
125
  ${this.productCountControl.getTemplate()}
@@ -107,50 +133,43 @@ class Q extends g {
107
133
  </div>
108
134
  `;
109
135
  }
136
+ /**
137
+ * Shows the selected block's own set of controls. A block is strategy-backed
138
+ * when a flag-on session stamped its config version, or when it already
139
+ * carries a strategy — an assignment must stay editable however it arrived.
140
+ */
141
+ _showControlsForBlock(t) {
142
+ var i;
143
+ const e = (i = this.getContainer()) == null ? void 0 : i.querySelector(".recommendation-controls-container");
144
+ if (!e || this._getRecommendationIdFromNode(t) === null)
145
+ return;
146
+ const o = m.getConfig(t), r = (o.configVersion ?? 0) >= _ || !!o.strategyId;
147
+ e.classList.toggle("strategy-block", r);
148
+ }
110
149
  async onRender() {
111
150
  var o;
112
151
  const t = this._getRecommendationIdFromNode(this.currentNode), e = t ?? this.store.currentRecommendationId;
113
- if (e !== null && this.store.setCurrentBlock(e), t !== null && !this.syncedBlockIds.has(t) && (this.syncedBlockIds.add(t), this._syncNodeConfigToStore()), this._listenStateUpdates(), e !== null && ((o = this.store.blockStates[e]) != null && o.isInitialized)) {
152
+ if (e !== null && this.store.setCurrentBlock(e), t !== null && !this.syncedBlockIds.has(t) && (this.syncedBlockIds.add(t), this._syncNodeConfigToStore()), this._listenStateUpdates(), this._showControlsForBlock(this.currentNode), e !== null && ((o = this.store.blockStates[e]) != null && o.isInitialized)) {
114
153
  this._initializeSubControls();
115
154
  return;
116
155
  }
117
156
  await this._fetchBlockData(e), this._initializeSubControls();
118
157
  }
119
158
  onTemplateNodeUpdated(t) {
120
- var r;
159
+ var o;
121
160
  super.onTemplateNodeUpdated(t);
122
161
  const e = this._getRecommendationIdFromNode(t);
123
- e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null && !this.syncedBlockIds.has(e) && (this.syncedBlockIds.add(e), this._syncNodeConfigToStore()), e !== null && !((r = this.store.blockStates[e]) != null && r.isInitialized) && this._fetchBlockData(e).then(() => {
162
+ e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null && !this.syncedBlockIds.has(e) && (this.syncedBlockIds.add(e), this._syncNodeConfigToStore()), this._showControlsForBlock(t), e !== null && !((o = this.store.blockStates[e]) != null && o.isInitialized) && this._fetchBlockData(e).then(() => {
124
163
  this._initializeSubControls();
125
- }), [
126
- this.layoutOrientationControl,
127
- this.productCountControl,
128
- this.algorithmControl,
129
- this.localeControl,
130
- this.currencyControl,
131
- this.productLayoutControl,
132
- this.filtersControl,
133
- this.shuffleControl,
134
- this.pricePlacementControl
135
- ].forEach((n) => {
164
+ }), this._subControls.forEach((r) => {
136
165
  var i;
137
- n != null && n.api && (n.currentNode = t, (i = n.onTemplateNodeUpdated) == null || i.call(n, t));
166
+ r != null && r.api && (r.currentNode = t, (i = r.onTemplateNodeUpdated) == null || i.call(r, t));
138
167
  });
139
168
  }
140
169
  onDestroy() {
141
- this.storeUnsubscription(), [
142
- this.layoutOrientationControl,
143
- this.productCountControl,
144
- this.algorithmControl,
145
- this.localeControl,
146
- this.currencyControl,
147
- this.productLayoutControl,
148
- this.filtersControl,
149
- this.shuffleControl,
150
- this.pricePlacementControl
151
- ].forEach((e) => {
152
- var o;
153
- return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
170
+ this.storeUnsubscription(), this._subControls.forEach((t) => {
171
+ var e;
172
+ return (e = t == null ? void 0 : t.onDestroy) == null ? void 0 : e.call(t);
154
173
  });
155
174
  }
156
175
  /**
@@ -158,19 +177,9 @@ class Q extends g {
158
177
  * Each sub-control manages its own form values and event listeners
159
178
  */
160
179
  _initializeSubControls() {
161
- [
162
- this.layoutOrientationControl,
163
- this.productCountControl,
164
- this.algorithmControl,
165
- this.localeControl,
166
- this.currencyControl,
167
- this.productLayoutControl,
168
- this.filtersControl,
169
- this.shuffleControl,
170
- this.pricePlacementControl
171
- ].forEach((e) => {
172
- var o;
173
- e && (e.api = this.api, e.currentNode = this.currentNode, (o = e.onRender) == null || o.call(e));
180
+ this._subControls.forEach((t) => {
181
+ var e;
182
+ t && (t.api = this.api, t.currentNode = this.currentNode, (e = t.onRender) == null || e.call(t));
174
183
  });
175
184
  }
176
185
  /**
@@ -186,9 +195,10 @@ class Q extends g {
186
195
  */
187
196
  _syncNodeConfigToStore() {
188
197
  var r;
189
- const t = h.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((r = this.store.blockStates[e]) == null ? void 0 : r.isInitialized);
198
+ const t = m.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((r = this.store.blockStates[e]) == null ? void 0 : r.isInitialized);
190
199
  this.store.patchCurrentBlockConfig({
191
200
  strategy: t.strategy,
201
+ strategyId: t.strategyId,
192
202
  language: t.language,
193
203
  size: t.size,
194
204
  productIds: t.productIds,
@@ -249,36 +259,36 @@ class Q extends g {
249
259
  _applySmartDefaults() {
250
260
  if (!this.currentNode || !this.api)
251
261
  return;
252
- const t = h.getConfig(this.currentNode), e = {};
253
- let o = null, r = null, n = null;
254
- if (t.currency.code === c.currency.code) {
255
- const { currencyList: i } = this.store;
256
- i.length > 0 && (i.some(
257
- (u) => u.value === `price.${c.currency.code}`
258
- ) || (o = i[0].value.replace("price.", ""), e.currency = {
259
- ...c.currency,
262
+ const t = m.getConfig(this.currentNode), e = {};
263
+ let o = null, r = null, i = null;
264
+ if (t.currency.code === a.currency.code) {
265
+ const { currencyList: s } = this.store;
266
+ s.length > 0 && (s.some(
267
+ (u) => u.value === `price.${a.currency.code}`
268
+ ) || (o = s[0].value.replace("price.", ""), e.currency = {
269
+ ...a.currency,
260
270
  code: o,
261
271
  symbol: o
262
272
  }));
263
273
  }
264
- if (t.strategy === c.strategy) {
265
- const i = this.store.getActivePredictiveAlgorithms;
266
- i.length > 0 && (i.some(
267
- (u) => u.value === c.strategy
268
- ) || (r = i[0].value, e.strategy = r));
274
+ if (t.strategy === a.strategy) {
275
+ const s = this.store.getActivePredictiveAlgorithms;
276
+ s.length > 0 && (s.some(
277
+ (u) => u.value === a.strategy
278
+ ) || (r = s[0].value, e.strategy = r));
269
279
  }
270
- if (t.language === c.language) {
271
- const i = this.store.getLanguages;
272
- i.length > 0 && (i.some(
273
- (u) => u.value === c.language
274
- ) || (n = i[0].value, e.language = n));
280
+ if (t.language === a.language) {
281
+ const s = this.store.getLanguages;
282
+ s.length > 0 && (s.some(
283
+ (u) => u.value === a.language
284
+ ) || (i = s[0].value, e.language = i));
275
285
  }
276
- !o && !r && !n || (h.updateConfig(
286
+ !o && !r && !i || (m.updateConfig(
277
287
  this.api,
278
288
  this.currentNode,
279
289
  e,
280
290
  "Applied smart defaults"
281
- ), o && e.currency && L({
291
+ ), o && e.currency && D({
282
292
  currentNode: this.currentNode,
283
293
  documentModifier: this.api.getDocumentModifier(),
284
294
  currency: e.currency
@@ -288,24 +298,24 @@ class Q extends g {
288
298
  name: o,
289
299
  value: o,
290
300
  symbol: o,
291
- alignment: c.currency.alignment === "before" ? "0" : "1",
292
- decimalCount: c.currency.decimalCount.toString(),
293
- decimalSeparator: c.currency.decimalSeparator,
294
- thousandSeparator: c.currency.thousandSeparator
301
+ alignment: a.currency.alignment === "before" ? "0" : "1",
302
+ decimalCount: a.currency.decimalCount.toString(),
303
+ decimalSeparator: a.currency.decimalSeparator,
304
+ thousandSeparator: a.currency.thousandSeparator
295
305
  }
296
306
  } : {},
297
307
  ...r ? { strategy: r } : {},
298
- ...n ? { language: n } : {}
308
+ ...i ? { language: i } : {}
299
309
  }, { triggerRefetch: !1 }));
300
310
  }
301
311
  /**
302
312
  * Reads the recommendation-id attribute from the block element within the node
303
313
  */
304
314
  _getRecommendationIdFromNode(t) {
305
- const e = k(t);
315
+ const e = w(t);
306
316
  if (!e || !("getAttribute" in e))
307
317
  return null;
308
- const o = e.getAttribute(v);
318
+ const o = e.getAttribute(A);
309
319
  if (!o)
310
320
  return null;
311
321
  const r = parseInt(o);
@@ -328,65 +338,68 @@ class Q extends g {
328
338
  const { store: t } = this;
329
339
  let e = t.recommendationProducts, o = t.$state.configVersion, r = t.currentRecommendationId;
330
340
  this.storeUnsubscription = t.$subscribe(() => {
331
- const n = t.currentRecommendationId;
332
- if (n !== r) {
333
- r = n, e = t.recommendationProducts, o = t.$state.configVersion;
341
+ const i = t.currentRecommendationId;
342
+ if (i !== r) {
343
+ r = i, e = t.recommendationProducts, o = t.$state.configVersion;
334
344
  return;
335
345
  }
336
- const i = t.$state.configVersion;
337
- i !== o && (o = i, this._persistFiltersToNodeConfig(), this._debouncedFetchProducts());
338
- const a = t.recommendationProducts, u = a !== e, C = Array.isArray(a) && a.length > 0;
339
- u && C && (e = a, this._debouncedRegenerateWithProducts());
346
+ const s = t.$state.configVersion;
347
+ s !== o && (o = s, this._persistFiltersToNodeConfig(), this._debouncedFetchProducts());
348
+ const l = t.recommendationProducts, u = l !== e, f = Array.isArray(l) && l.length > 0;
349
+ u && f && (e = l, this._debouncedRegenerateWithProducts());
340
350
  });
341
351
  }
342
352
  /**
343
- * Persists the current filter state from Pinia store to the Stripo node config.
344
- * This ensures filters survive template save/reload cycles.
353
+ * Persists filter + strategy state to the Stripo node config so it survives
354
+ * save/reload (strategyId must reach esd-ext-config before any save).
355
+ * `size` rides along: assigning a strategy writes it to the store only, and a
356
+ * stale node config would rebuild the block against the old slot count.
345
357
  */
346
358
  _persistFiltersToNodeConfig() {
347
359
  if (!this.currentNode || !this.api)
348
360
  return;
349
- const { filters: t } = this.store.recommendationConfigs, e = h.getConfig(this.currentNode).filters;
350
- JSON.stringify(e) !== JSON.stringify(t) && h.updateConfig(
361
+ const { filters: t, strategyId: e, size: o } = this.store.recommendationConfigs, r = m.getConfig(this.currentNode);
362
+ JSON.stringify(r.filters) === JSON.stringify(t) && r.strategyId === e && r.size === o || m.updateConfig(
351
363
  this.api,
352
364
  this.currentNode,
353
- { filters: t },
365
+ { filters: t, strategyId: e, size: o },
354
366
  "Update recommendation filters"
355
367
  );
356
368
  }
357
369
  }
358
370
  export {
359
- tt as ALGORITHM_CONTROL_ID,
360
- N as AlgorithmControl,
361
- w as CONTROL_BLOCK_ID,
362
- ot as CURRENCY_CONTROL_ID,
371
+ it as ALGORITHM_CONTROL_ID,
372
+ I as AlgorithmControl,
373
+ x as CONTROL_BLOCK_ID,
374
+ at as CURRENCY_CONTROL_ID,
363
375
  R as CurrencyControl,
364
- nt as FILTERS_CONTROL_ID,
365
- I as FiltersControl,
366
- st as LAYOUT_ORIENTATION_CONTROL_ID,
367
- lt as LOCALE_CONTROL_ID,
376
+ lt as FILTERS_CONTROL_ID,
377
+ T as FiltersControl,
378
+ dt as LAYOUT_ORIENTATION_CONTROL_ID,
379
+ ht as LOCALE_CONTROL_ID,
368
380
  b as LayoutOrientationControl,
369
- _ as LocaleControl,
370
- ut as PRICE_PLACEMENT_CONTROL_ID,
371
- ht as PRODUCT_COUNT_CONTROL_ID,
372
- Ct as PRODUCT_LAYOUT_CONTROL_ID,
373
- T as PricePlacementControl,
374
- O as ProductCountControl,
375
- P as ProductLayoutControl,
376
- Q as RecommendationBlockControl,
377
- pt as SHUFFLE_CONTROL_ID,
378
- S as ShuffleControl,
379
- yt as adjustProductsToSize,
380
- Nt as formatProductPrice,
381
- k as getBlockElement,
382
- Rt as getCardComposition,
383
- It as getCurrentLayout,
384
- bt as getMainContainerTbody,
385
- D as isPartnerManagedBlock,
386
- _t as regenerateMobileProductRows,
387
- A as regenerateProductRowsWithStyles,
388
- L as setCurrencyAttributes,
389
- Tt as updatePricesInPlace,
390
- E as updateProductContentInPlace,
391
- Ot as updateSingleProductContent
381
+ S as LocaleControl,
382
+ Ct as PRICE_PLACEMENT_CONTROL_ID,
383
+ pt as PRODUCT_COUNT_CONTROL_ID,
384
+ _t as PRODUCT_LAYOUT_CONTROL_ID,
385
+ O as PricePlacementControl,
386
+ P as ProductCountControl,
387
+ L as ProductLayoutControl,
388
+ ot as RecommendationBlockControl,
389
+ It as SHUFFLE_CONTROL_ID,
390
+ Tt as STRATEGY_CONTROL_ID,
391
+ k as ShuffleControl,
392
+ E as StrategyControl,
393
+ St as adjustProductsToSize,
394
+ Ot as formatProductPrice,
395
+ w as getBlockElement,
396
+ Pt as getCardComposition,
397
+ Lt as getCurrentLayout,
398
+ B as isPartnerManagedBlock,
399
+ kt as regenerateMobileProductRows,
400
+ $ as regenerateProductRowsWithStyles,
401
+ D as setCurrencyAttributes,
402
+ Et as updatePricesInPlace,
403
+ v as updateProductContentInPlace,
404
+ Dt as updateSingleProductContent
392
405
  };
@@ -0,0 +1,142 @@
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 {
9
+ constructor() {
10
+ super(...arguments);
11
+ o(this, "store", u());
12
+ o(this, "storeUnsubscription", () => {
13
+ });
14
+ o(this, "listeners", []);
15
+ // The store subscription fires on EVERY mutation of a store six controls
16
+ // share, so the last painted state is kept to skip the DOM work.
17
+ o(this, "lastPaintedState", null);
18
+ }
19
+ getId() {
20
+ return p;
21
+ }
22
+ getTemplate() {
23
+ const t = this.api.translate(
24
+ "You can assign a recommendation strategy by selecting an existing one or creating a new one to show specific content."
25
+ ), e = this.api.translate("For more information, you can"), a = this.api.translate("visit Academy");
26
+ return `
27
+ <div class="strategy-control-container">
28
+ <div class="strategy-control-header">
29
+ <h3 class="strategy-control-title">${this.api.translate("Recommendation Strategy")}</h3>
30
+ </div>
31
+ <div class="strategy-control-description-row">
32
+ <p class="strategy-control-description">
33
+ ${t}
34
+ ${e}
35
+ <a
36
+ href="${m.EMAIL_RECOMMENDATION_BLOCK}"
37
+ target="_blank"
38
+ rel="noopener noreferrer">${a}</a>.
39
+ </p>
40
+ </div>
41
+ <div data-strategy-empty-state>
42
+ ${this._GuTwoColumns([
43
+ this._GuButton({
44
+ name: "assignStrategy",
45
+ label: this.api.translate("Assign Strategy"),
46
+ id: "guido__btn-assign-strategy",
47
+ className: "strategy-control-cta on"
48
+ }),
49
+ // Create round-trip ships with SD-149916; until then the CTA
50
+ // stays inert at full contrast, as the design draws it.
51
+ this._GuButton({
52
+ name: "createStrategy",
53
+ label: this.api.translate("Create New Strategy"),
54
+ id: "guido__btn-create-strategy",
55
+ className: "strategy-control-cta primary",
56
+ disabled: !0
57
+ })
58
+ ], "strategy-control-cta-row")}
59
+ </div>
60
+ <div data-strategy-assigned-state style="display: none;">
61
+ <div class="strategy-control-name-band">
62
+ <span class="strategy-control-name" data-strategy-name></span>
63
+ </div>
64
+ <div class="strategy-control-actions">
65
+ ${this._strategyAction({
66
+ id: "guido__btn-change-strategy",
67
+ label: this.api.translate("Change"),
68
+ modifier: "change"
69
+ })}
70
+ ${this._strategyAction({
71
+ id: "guido__btn-remove-strategy",
72
+ label: this.api.translate("Remove"),
73
+ modifier: "remove"
74
+ })}
75
+ </div>
76
+ </div>
77
+ </div>
78
+ `;
79
+ }
80
+ /**
81
+ * Change / Remove are icon+text actions in the design, not buttons — and
82
+ * `ue-button` cannot pair a caption with an arbitrary icon, so these are
83
+ * plain elements. Click wiring is by id, which works on any element.
84
+ *
85
+ * The icon is a CSS mask, not inline SVG: Stripo re-creates the control's
86
+ * markup through Angular, which rebuilds `<svg>` outside the SVG namespace
87
+ * (the view-box attribute comes back lowercased) and it never paints.
88
+ */
89
+ _strategyAction({ id: t, label: e, modifier: a }) {
90
+ return `
91
+ <button
92
+ id="${t}"
93
+ type="button"
94
+ class="strategy-control-action strategy-control-action--${a}">
95
+ <span>${e}</span>
96
+ </button>
97
+ `;
98
+ }
99
+ onRender() {
100
+ this._teardown(), this._setupButtonListeners(), this._renderState(), this.storeUnsubscription = this.store.$subscribe(() => {
101
+ this._renderState();
102
+ }), this.store.recommendationConfigs.strategyId && !this.store.strategies.length && this.store.fetchStrategies().catch(() => {
103
+ });
104
+ }
105
+ onDestroy() {
106
+ this._teardown();
107
+ }
108
+ _teardown() {
109
+ this.storeUnsubscription(), this.storeUnsubscription = () => {
110
+ }, this.lastPaintedState = null, this.listeners.forEach(({ element: t, handler: e }) => t.removeEventListener("click", e)), this.listeners = [];
111
+ }
112
+ _setupButtonListeners() {
113
+ const t = this.getContainer();
114
+ if (!t)
115
+ return;
116
+ const e = (a, n) => {
117
+ const i = t.querySelector(a);
118
+ i && (i.addEventListener("click", n), this.listeners.push({ element: i, handler: n }));
119
+ };
120
+ e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.removeStrategy());
121
+ }
122
+ /**
123
+ * Toggles empty vs assigned state from the store's current block config.
124
+ * Display name comes from the listing; falls back to the raw id while the
125
+ * listing loads (or when the strategy is no longer listed).
126
+ */
127
+ _renderState() {
128
+ var l;
129
+ const { strategyId: t } = this.store.recommendationConfigs, e = t ? ((l = this.store.assignedStrategy) == null ? void 0 : l.name) ?? "" : "", a = `${t}\0${e}`;
130
+ if (a === this.lastPaintedState)
131
+ return;
132
+ const n = this.getContainer();
133
+ if (!n)
134
+ return;
135
+ const i = n.querySelector("[data-strategy-empty-state]"), c = n.querySelector("[data-strategy-assigned-state]"), g = n.querySelector("[data-strategy-name]");
136
+ !i || !c || (i.style.display = t ? "none" : "", c.style.display = t ? "" : "none", g && t && (g.textContent = e || `#${t}`), this.lastPaintedState = a);
137
+ }
138
+ }
139
+ export {
140
+ p as STRATEGY_CONTROL_ID,
141
+ f as StrategyControl
142
+ };
@@ -438,7 +438,6 @@ export {
438
438
  C as getBlockElement,
439
439
  U as getCardComposition,
440
440
  P as getCurrentLayout,
441
- oe as getMainContainerTbody,
442
441
  ee as isPartnerManagedBlock,
443
442
  Pe as regenerateMobileProductRows,
444
443
  Te as regenerateProductRowsWithStyles,