@useinsider/guido 3.17.0-beta.978ff7e → 3.17.0-beta.a0d17c2

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 (60) hide show
  1. package/README.md +1 -0
  2. package/dist/@types/config/schemas.js +7 -6
  3. package/dist/components/Guido.vue.js +10 -10
  4. package/dist/components/Guido.vue2.js +82 -76
  5. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +21 -0
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +106 -0
  7. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue.js +17 -0
  8. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +57 -0
  9. package/dist/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue.js +19 -0
  10. package/dist/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue2.js +63 -0
  11. package/dist/composables/useCustomInterfaceAppearance.js +52 -38
  12. package/dist/composables/useRecommendation.js +41 -34
  13. package/dist/config/i18n/en/labels.json.js +1 -1
  14. package/dist/config/migrator/recommendation/settingsMapper.js +17 -17
  15. package/dist/config/migrator/recommendationMigrator.js +5 -4
  16. package/dist/enums/academy.js +2 -1
  17. package/dist/enums/date.js +5 -3
  18. package/dist/enums/extensions/recommendationBlock.js +3 -1
  19. package/dist/extensions/Blocks/Recommendation/block.js +26 -21
  20. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +30 -30
  21. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +60 -59
  22. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +246 -187
  23. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +124 -0
  24. package/dist/extensions/Blocks/Recommendation/services/configService.js +54 -36
  25. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +175 -79
  26. package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +22 -0
  27. package/dist/extensions/Blocks/common-control.js +22 -19
  28. package/dist/guido.css +1 -1
  29. package/dist/services/recommendationApi.js +69 -30
  30. package/dist/src/@types/config/schemas.d.ts +2 -0
  31. package/dist/src/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.d.ts +3 -0
  32. package/dist/src/components/organisms/extensions/recommendation/RemoveStrategyModal.vue.d.ts +2 -0
  33. package/dist/src/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue.d.ts +15 -0
  34. package/dist/src/composables/useConfig.d.ts +2 -0
  35. package/dist/src/composables/useRecommendation.d.ts +1 -0
  36. package/dist/src/enums/academy.d.ts +1 -0
  37. package/dist/src/enums/date.d.ts +1 -0
  38. package/dist/src/enums/extensions/recommendationBlock.d.ts +2 -0
  39. package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +2 -6
  40. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +1 -1
  41. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +44 -8
  42. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +16 -0
  43. package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +12 -1
  44. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +176 -10
  45. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +1 -0
  46. package/dist/src/extensions/Blocks/Recommendation/utils/nodeConfigWriter.d.ts +31 -0
  47. package/dist/src/extensions/Blocks/common-control.d.ts +4 -1
  48. package/dist/src/mock/api/recommendation-strategies.d.ts +2 -0
  49. package/dist/src/services/recommendationApi.d.ts +4 -1
  50. package/dist/src/stores/config.d.ts +18 -0
  51. package/dist/src/stores/save-as-template.d.ts +4 -3
  52. package/dist/src/utils/genericUtil.d.ts +5 -0
  53. package/dist/static/assets/icons/line-change.svg.js +5 -0
  54. package/dist/static/assets/icons/line-delete.svg.js +5 -0
  55. package/dist/static/assets/icons/line-plus.svg.js +5 -0
  56. package/dist/static/styles/components/recommendation-strategy.css.js +155 -0
  57. package/dist/utils/dateUtil.js +23 -10
  58. package/dist/utils/genericUtil.js +28 -27
  59. package/dist/utils/templatePreparation.js +35 -34
  60. package/package.json +2 -1
@@ -1,54 +1,70 @@
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";
10
- 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";
14
- 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 {
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 r = (h, l, t) => C(h, typeof l != "symbol" ? l + "" : l, t);
4
+ import { useConfig as p } from "../../../../../composables/useConfig.js";
5
+ import { ModificationDescription as y } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
6
+ import { CommonControl as N } from "../../../common-control.js";
7
+ import { CURRENT_CONFIG_VERSION as _, DEFAULT_NODE_CONFIG as a } from "../../constants/defaultConfig.js";
8
+ import { RecommendationConfigService as c } from "../../services/configService.js";
9
+ import { useRecommendationExtensionStore as I } from "../../store/recommendation.js";
10
+ import { registerNodeConfigWriter as R } from "../../utils/nodeConfigWriter.js";
11
+ import { AlgorithmControl as b } from "./algorithm.js";
12
+ import { ALGORITHM_CONTROL_ID as ct } from "./algorithm.js";
13
+ import { CurrencyControl as T } from "./currency.js";
14
+ import { CURRENCY_CONTROL_ID as dt } from "./currency.js";
15
+ import { FiltersControl as P } from "./filters.js";
16
+ import { FILTERS_CONTROL_ID as ft } from "./filters.js";
17
+ import { LayoutOrientationControl as S } from "./layoutOrientation.js";
18
+ import { LAYOUT_ORIENTATION_CONTROL_ID as mt } from "./layoutOrientation.js";
19
+ import { LocaleControl as O } from "./locale.js";
20
+ import { LOCALE_CONTROL_ID as pt } from "./locale.js";
21
+ import { PricePlacementControl as L } from "./pricePlacement.js";
22
+ import { PRICE_PLACEMENT_CONTROL_ID as Nt } from "./pricePlacement.js";
23
+ import { ProductCountControl as E } from "./productCount.js";
24
+ import { PRODUCT_COUNT_CONTROL_ID as It } from "./productCount.js";
25
+ import { ProductLayoutControl as k } from "./productLayout.js";
26
+ import { PRODUCT_LAYOUT_CONTROL_ID as bt } from "./productLayout.js";
27
+ import { ShuffleControl as D } from "./shuffle.js";
28
+ import { SHUFFLE_CONTROL_ID as Pt } from "./shuffle.js";
29
+ import { StrategyControl as F } from "./strategy.js";
30
+ import { STRATEGY_CONTROL_ID as Ot } from "./strategy.js";
31
+ import { setCurrencyAttributes as w, getBlockElement as A, isPartnerManagedBlock as v, updateProductContentInPlace as x, regenerateProductRowsWithStyles as B } from "./utils.js";
32
+ import { adjustProductsToSize as Et, formatProductPrice as kt, getCardComposition as Dt, getCurrentLayout as Ft, getMainContainerTbody as wt, regenerateMobileProductRows as At, updatePricesInPlace as vt, updateSingleProductContent as xt } from "./utils.js";
33
+ import { useDebounceFn as f } from "../../../../../node_modules/@vueuse/shared/index.js";
34
+ const U = "recommendation-id", $ = "ui-elements-recommendation-block";
35
+ class st extends N {
31
36
  constructor() {
32
37
  super(...arguments);
33
- s(this, "store", y());
34
- s(this, "storeUnsubscription", () => {
38
+ r(this, "store", I());
39
+ r(this, "storeUnsubscription", () => {
35
40
  });
36
- s(this, "syncedBlockIds", /* @__PURE__ */ new Set());
41
+ // blockId -> fingerprint of the node config as it looked at the last sync.
42
+ r(this, "syncedConfigs", /* @__PURE__ */ new Map());
43
+ // A config change waiting to reach the node config. Deferred so it can ride the
44
+ // re-render's single apply() — one user action must cost one undo press.
45
+ r(this, "pendingNodeConfigWrite", null);
46
+ r(this, "pendingConfigFlushTimer", null);
37
47
  // 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);
48
+ r(this, "algorithmControl", null);
49
+ r(this, "localeControl", null);
50
+ r(this, "currencyControl", null);
51
+ r(this, "productCountControl", null);
52
+ r(this, "productLayoutControl", null);
53
+ r(this, "filtersControl", null);
54
+ r(this, "shuffleControl", null);
55
+ r(this, "pricePlacementControl", null);
56
+ r(this, "layoutOrientationControl", null);
57
+ r(this, "strategyControl", null);
58
+ r(this, "rrsEnabled", !1);
47
59
  /**
48
60
  * Debounced product fetch to prevent rapid API calls during config changes
49
61
  */
50
- s(this, "_debouncedFetchProducts", m(() => {
51
- this.store.fetchRecommendationProducts();
62
+ r(this, "_debouncedFetchProducts", f(async () => {
63
+ try {
64
+ await this.store.fetchRecommendationProducts();
65
+ } finally {
66
+ this._scheduleConfigFlush();
67
+ }
52
68
  }, 500));
53
69
  /**
54
70
  * Debounced content update when products arrive from API.
@@ -61,16 +77,20 @@ class Q extends g {
61
77
  * count. The store pads products to the configured size, so in-place only
62
78
  * fails when the size actually changed.
63
79
  */
64
- s(this, "_debouncedRegenerateWithProducts", m(() => {
80
+ r(this, "_debouncedRegenerateWithProducts", f(() => {
65
81
  const t = this.store.recommendationProducts;
66
- if (!this.currentNode || !this.api || D(this.currentNode))
82
+ if (!this.currentNode || !this.api)
83
+ return;
84
+ const e = this.api.getDocumentModifier(), o = this._stagePendingNodeConfig(e);
85
+ if (v(this.currentNode)) {
86
+ o && (e.apply(new y("Update recommendation configuration")), this.pendingNodeConfigWrite = null, this._clearConfigFlush());
67
87
  return;
68
- const e = this.api.getDocumentModifier();
69
- E({
88
+ }
89
+ x({
70
90
  currentNode: this.currentNode,
71
91
  documentModifier: e,
72
92
  products: t
73
- }) || A({
93
+ }) || B({
74
94
  currentNode: this.currentNode,
75
95
  documentModifier: e,
76
96
  products: t
@@ -78,23 +98,32 @@ class Q extends g {
78
98
  }, 100));
79
99
  }
80
100
  getId() {
81
- return w;
101
+ return $;
82
102
  }
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(), [
103
+ get _subControls() {
104
+ return [
105
+ this.layoutOrientationControl,
106
+ this.productCountControl,
85
107
  this.algorithmControl,
86
108
  this.localeControl,
87
109
  this.currencyControl,
88
- this.productCountControl,
89
110
  this.productLayoutControl,
90
111
  this.filtersControl,
91
112
  this.shuffleControl,
92
113
  this.pricePlacementControl,
93
- this.layoutOrientationControl
94
- ].forEach((e) => {
95
- e.api = this.api;
114
+ this.strategyControl
115
+ ];
116
+ }
117
+ getTemplate() {
118
+ var t;
119
+ return this.rrsEnabled = p().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((e) => {
120
+ var o;
121
+ return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
122
+ }), this.algorithmControl = new b(), this.localeControl = new O(), this.currencyControl = new T(), this.productCountControl = new E(), this.productLayoutControl = new k(), this.filtersControl = new P(), this.shuffleControl = new D(), this.pricePlacementControl = new L(), this.layoutOrientationControl = new S(), this.strategyControl = this.rrsEnabled ? new F() : null, this._subControls.forEach((e) => {
123
+ e && (e.api = this.api);
96
124
  }), `
97
125
  <div class="recommendation-controls-container">
126
+ ${((t = this.strategyControl) == null ? void 0 : t.getTemplate()) ?? ""}
98
127
  ${this.layoutOrientationControl.getTemplate()}
99
128
  ${this.productCountControl.getTemplate()}
100
129
  ${this.productLayoutControl.getTemplate()}
@@ -107,50 +136,39 @@ class Q extends g {
107
136
  </div>
108
137
  `;
109
138
  }
139
+ _showControlsForBlock(t) {
140
+ var i;
141
+ const e = (i = this.getContainer()) == null ? void 0 : i.querySelector(".recommendation-controls-container");
142
+ if (!e)
143
+ return;
144
+ const o = this._getRecommendationIdFromNode(t) === null ? null : c.getConfig(t), n = this.rrsEnabled && !!o && (!!(o != null && o.strategyId) || ((o == null ? void 0 : o.configVersion) ?? 0) >= _);
145
+ e.classList.toggle("strategy-block", n);
146
+ }
110
147
  async onRender() {
111
148
  var o;
149
+ R(this.api);
112
150
  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)) {
151
+ 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)) {
114
152
  this._initializeSubControls();
115
153
  return;
116
154
  }
117
155
  await this._fetchBlockData(e), this._initializeSubControls();
118
156
  }
119
157
  onTemplateNodeUpdated(t) {
120
- var r;
158
+ var o;
121
159
  super.onTemplateNodeUpdated(t);
122
160
  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(() => {
161
+ 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(() => {
124
162
  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) => {
163
+ }), this._subControls.forEach((n) => {
136
164
  var i;
137
165
  n != null && n.api && (n.currentNode = t, (i = n.onTemplateNodeUpdated) == null || i.call(n, t));
138
166
  });
139
167
  }
140
168
  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);
169
+ this.storeUnsubscription(), this._flushPendingNodeConfig(), this._subControls.forEach((t) => {
170
+ var e;
171
+ return (e = t == null ? void 0 : t.onDestroy) == null ? void 0 : e.call(t);
154
172
  });
155
173
  }
156
174
  /**
@@ -158,25 +176,14 @@ class Q extends g {
158
176
  * Each sub-control manages its own form values and event listeners
159
177
  */
160
178
  _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));
179
+ this._subControls.forEach((t) => {
180
+ var e;
181
+ t && (t.api = this.api, t.currentNode = this.currentNode, (e = t.onRender) == null || e.call(t));
174
182
  });
175
183
  }
176
184
  /**
177
185
  * Syncs persisted node config into the Pinia store's block state.
178
186
  *
179
- * setCurrentBlock() creates a default entry (USD, en_US, mostPopular).
180
187
  * For saved templates, the real config lives in the node (e.g., TRY, tr_TR).
181
188
  * This method reads it and patches the store so fetchRecommendationProducts()
182
189
  * uses the correct values.
@@ -184,11 +191,76 @@ class Q extends g {
184
191
  * Uses triggerRefetch: false because the fetch hasn't happened yet —
185
192
  * values are being prepared for the upcoming initial fetch.
186
193
  */
194
+ /**
195
+ * Re-syncs the store when the node config moved since we last read it.
196
+ *
197
+ * Undo/redo, the code editor and version-history restore rewrite the node
198
+ * config behind the store's back — Stripo exposes no undo signal, so a
199
+ * fingerprint diff on this hook is the only way to notice (SD-149105).
200
+ * An unchanged fingerprint means the move came from us, so runtime store
201
+ * edits are never clobbered (SD-141049).
202
+ */
203
+ _syncNodeConfigIfChanged(t) {
204
+ this.pendingNodeConfigWrite && this.pendingNodeConfigWrite.blockId !== t && this._flushPendingNodeConfig();
205
+ const e = JSON.stringify(c.getConfig(this.currentNode)), o = this.syncedConfigs.get(t);
206
+ this.syncedConfigs.set(t, e), o !== e && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
207
+ }
208
+ _capturePendingNodeConfigWrite() {
209
+ const t = this.store.currentRecommendationId;
210
+ if (!this.currentNode || !this.api || t === null)
211
+ return;
212
+ const { filters: e, strategyId: o, size: n } = this.store.recommendationConfigs;
213
+ this.pendingNodeConfigWrite = {
214
+ blockId: t,
215
+ node: this.currentNode,
216
+ updates: { filters: e, strategyId: o, size: n }
217
+ };
218
+ }
219
+ /**
220
+ * Accumulates the pending write into `documentModifier` without applying, so the
221
+ * caller's apply() commits config and re-render as ONE undo entry.
222
+ *
223
+ * Deliberately does not consume the pending record: the product helpers call
224
+ * apply() only when they actually changed something, so this batch may never be
225
+ * committed and the flush has to stay able to write it standalone.
226
+ * @param documentModifier - The batch to accumulate into
227
+ * @returns Whether anything was staged
228
+ */
229
+ _stagePendingNodeConfig(t) {
230
+ const e = this.pendingNodeConfigWrite;
231
+ return !e || !this.currentNode ? !1 : (c.stageConfig(t, this.currentNode, e.updates), !0);
232
+ }
233
+ /**
234
+ * Arms the guaranteed fallback write, once the product fetch has settled. The
235
+ * delay only has to outlast the re-render debounce that fetch triggers — firing
236
+ * earlier writes the config on its own and the undo entry splits in two again.
237
+ */
238
+ _scheduleConfigFlush() {
239
+ this._clearConfigFlush(), this.pendingConfigFlushTimer = setTimeout(() => {
240
+ this.pendingConfigFlushTimer = null, this._flushPendingNodeConfig();
241
+ }, 800);
242
+ }
243
+ _clearConfigFlush() {
244
+ this.pendingConfigFlushTimer !== null && (clearTimeout(this.pendingConfigFlushTimer), this.pendingConfigFlushTimer = null);
245
+ }
246
+ /**
247
+ * Writes the deferred change standalone when the batch it was staged into never
248
+ * committed. Always targets the LIVE node — the captured one is an immutable
249
+ * snapshot the intervening re-render staled, and saveConfig swallows that failure.
250
+ */
251
+ _flushPendingNodeConfig() {
252
+ const t = this.pendingNodeConfigWrite;
253
+ if (this.pendingNodeConfigWrite = null, this._clearConfigFlush(), !t || !this.api)
254
+ return;
255
+ const e = t.blockId === this.store.currentRecommendationId && this.currentNode ? this.currentNode : t.node, o = c.getConfig(e);
256
+ 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");
257
+ }
187
258
  _syncNodeConfigToStore() {
188
- 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);
259
+ var n;
260
+ const t = c.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((n = this.store.blockStates[e]) == null ? void 0 : n.isInitialized);
190
261
  this.store.patchCurrentBlockConfig({
191
262
  strategy: t.strategy,
263
+ strategyId: t.strategyId,
192
264
  language: t.language,
193
265
  size: t.size,
194
266
  productIds: t.productIds,
@@ -227,8 +299,8 @@ class Q extends g {
227
299
  t !== null && this.store.markBlockInitialized(t), (await Promise.allSettled([
228
300
  this.store.fetchRecommendationCreateData(),
229
301
  this.store.fetchRecommendationFilters()
230
- ])).forEach((o, r) => {
231
- o.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][r]} failed`, o.reason);
302
+ ])).forEach((o, n) => {
303
+ o.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][n]} failed`, o.reason);
232
304
  }), this._applySmartDefaults();
233
305
  try {
234
306
  await this.store.fetchRecommendationProducts();
@@ -249,36 +321,36 @@ class Q extends g {
249
321
  _applySmartDefaults() {
250
322
  if (!this.currentNode || !this.api)
251
323
  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,
324
+ const t = c.getConfig(this.currentNode), e = {};
325
+ let o = null, n = null, i = null;
326
+ if (t.currency.code === a.currency.code) {
327
+ const { currencyList: s } = this.store;
328
+ s.length > 0 && (s.some(
329
+ (d) => d.value === `price.${a.currency.code}`
330
+ ) || (o = s[0].value.replace("price.", ""), e.currency = {
331
+ ...a.currency,
260
332
  code: o,
261
333
  symbol: o
262
334
  }));
263
335
  }
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));
336
+ if (t.strategy === a.strategy) {
337
+ const s = this.store.getActivePredictiveAlgorithms;
338
+ s.length > 0 && (s.some(
339
+ (d) => d.value === a.strategy
340
+ ) || (n = s[0].value, e.strategy = n));
269
341
  }
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));
342
+ if (t.language === a.language) {
343
+ const s = this.store.getLanguages;
344
+ s.length > 0 && (s.some(
345
+ (d) => d.value === a.language
346
+ ) || (i = s[0].value, e.language = i));
275
347
  }
276
- !o && !r && !n || (h.updateConfig(
348
+ !o && !n && !i || (c.updateConfig(
277
349
  this.api,
278
350
  this.currentNode,
279
351
  e,
280
352
  "Applied smart defaults"
281
- ), o && e.currency && L({
353
+ ), o && e.currency && w({
282
354
  currentNode: this.currentNode,
283
355
  documentModifier: this.api.getDocumentModifier(),
284
356
  currency: e.currency
@@ -288,28 +360,28 @@ class Q extends g {
288
360
  name: o,
289
361
  value: o,
290
362
  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
363
+ alignment: a.currency.alignment === "before" ? "0" : "1",
364
+ decimalCount: a.currency.decimalCount.toString(),
365
+ decimalSeparator: a.currency.decimalSeparator,
366
+ thousandSeparator: a.currency.thousandSeparator
295
367
  }
296
368
  } : {},
297
- ...r ? { strategy: r } : {},
298
- ...n ? { language: n } : {}
369
+ ...n ? { strategy: n } : {},
370
+ ...i ? { language: i } : {}
299
371
  }, { triggerRefetch: !1 }));
300
372
  }
301
373
  /**
302
374
  * Reads the recommendation-id attribute from the block element within the node
303
375
  */
304
376
  _getRecommendationIdFromNode(t) {
305
- const e = k(t);
377
+ const e = A(t);
306
378
  if (!e || !("getAttribute" in e))
307
379
  return null;
308
- const o = e.getAttribute(v);
380
+ const o = e.getAttribute(U);
309
381
  if (!o)
310
382
  return null;
311
- const r = parseInt(o);
312
- return Number.isNaN(r) ? null : r;
383
+ const n = parseInt(o);
384
+ return Number.isNaN(n) ? null : n;
313
385
  }
314
386
  /**
315
387
  * Listen to store changes that require product refresh or regeneration.
@@ -326,67 +398,54 @@ class Q extends g {
326
398
  */
327
399
  _listenStateUpdates() {
328
400
  const { store: t } = this;
329
- let e = t.recommendationProducts, o = t.$state.configVersion, r = t.currentRecommendationId;
401
+ let e = t.recommendationProducts, o = t.$state.configVersion, n = t.currentRecommendationId;
330
402
  this.storeUnsubscription = t.$subscribe(() => {
331
- const n = t.currentRecommendationId;
332
- if (n !== r) {
333
- r = n, e = t.recommendationProducts, o = t.$state.configVersion;
403
+ const i = t.currentRecommendationId;
404
+ if (i !== n) {
405
+ n = i, e = t.recommendationProducts, o = t.$state.configVersion;
334
406
  return;
335
407
  }
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());
408
+ const s = t.$state.configVersion;
409
+ s !== o && (o = s, this._capturePendingNodeConfigWrite(), this._debouncedFetchProducts());
410
+ const u = t.recommendationProducts, d = u !== e, g = Array.isArray(u) && u.length > 0;
411
+ d && g && (e = u, this._debouncedRegenerateWithProducts());
340
412
  });
341
413
  }
342
- /**
343
- * Persists the current filter state from Pinia store to the Stripo node config.
344
- * This ensures filters survive template save/reload cycles.
345
- */
346
- _persistFiltersToNodeConfig() {
347
- if (!this.currentNode || !this.api)
348
- return;
349
- const { filters: t } = this.store.recommendationConfigs, e = h.getConfig(this.currentNode).filters;
350
- JSON.stringify(e) !== JSON.stringify(t) && h.updateConfig(
351
- this.api,
352
- this.currentNode,
353
- { filters: t },
354
- "Update recommendation filters"
355
- );
356
- }
357
414
  }
358
415
  export {
359
- tt as ALGORITHM_CONTROL_ID,
360
- N as AlgorithmControl,
361
- w as CONTROL_BLOCK_ID,
362
- ot as CURRENCY_CONTROL_ID,
363
- 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,
368
- 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
416
+ ct as ALGORITHM_CONTROL_ID,
417
+ b as AlgorithmControl,
418
+ $ as CONTROL_BLOCK_ID,
419
+ dt as CURRENCY_CONTROL_ID,
420
+ T as CurrencyControl,
421
+ ft as FILTERS_CONTROL_ID,
422
+ P as FiltersControl,
423
+ mt as LAYOUT_ORIENTATION_CONTROL_ID,
424
+ pt as LOCALE_CONTROL_ID,
425
+ S as LayoutOrientationControl,
426
+ O as LocaleControl,
427
+ Nt as PRICE_PLACEMENT_CONTROL_ID,
428
+ It as PRODUCT_COUNT_CONTROL_ID,
429
+ bt as PRODUCT_LAYOUT_CONTROL_ID,
430
+ L as PricePlacementControl,
431
+ E as ProductCountControl,
432
+ k as ProductLayoutControl,
433
+ st as RecommendationBlockControl,
434
+ Pt as SHUFFLE_CONTROL_ID,
435
+ Ot as STRATEGY_CONTROL_ID,
436
+ D as ShuffleControl,
437
+ F as StrategyControl,
438
+ Et as adjustProductsToSize,
439
+ kt as formatProductPrice,
440
+ A as getBlockElement,
441
+ Dt as getCardComposition,
442
+ Ft as getCurrentLayout,
443
+ wt as getMainContainerTbody,
444
+ v as isPartnerManagedBlock,
445
+ At as regenerateMobileProductRows,
446
+ B as regenerateProductRowsWithStyles,
447
+ w as setCurrencyAttributes,
448
+ vt as updatePricesInPlace,
449
+ x as updateProductContentInPlace,
450
+ xt as updateSingleProductContent
392
451
  };