@useinsider/guido 3.20.0-beta.af394f2 → 3.20.0-beta.d753259

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.
@@ -1,74 +1,79 @@
1
- var C = Object.defineProperty;
2
- var p = (h, u, e) => u in h ? C(h, u, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[u] = e;
3
- var r = (h, u, e) => p(h, typeof u != "symbol" ? u + "" : u, e);
4
- import { useConfig as f } from "../../../../../composables/useConfig.js";
5
- import { ModificationDescription as y } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
1
+ var p = Object.defineProperty;
2
+ var y = (h, l, e) => l in h ? p(h, l, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[l] = e;
3
+ var i = (h, l, e) => y(h, typeof l != "symbol" ? l + "" : l, e);
4
+ import { useConfig as g } from "../../../../../composables/useConfig.js";
5
+ import { ModificationDescription as _ } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
6
6
  import { CommonControl as N } from "../../../common-control.js";
7
- import { RRS_CONFIG_VERSION as _, DEFAULT_NODE_CONFIG as c } from "../../constants/defaultConfig.js";
8
- import { RECOMMENDATION_ID_ATTR as I } from "../../constants/selectors.js";
9
- import { RecommendationConfigService as d } from "../../services/configService.js";
10
- import { useRecommendationExtensionStore as R } from "../../store/recommendation.js";
11
- import { registerNodeConfigWriter as b, commitBlockChangeOutsidePanel as P } from "../../utils/nodeConfigWriter.js";
12
- import { AlgorithmControl as S } from "./algorithm.js";
13
- import { ALGORITHM_CONTROL_ID as ue } from "./algorithm.js";
14
- import { CurrencyControl as T } from "./currency.js";
15
- import { CURRENCY_CONTROL_ID as ge } from "./currency.js";
16
- import { FiltersControl as O } from "./filters.js";
17
- import { FILTERS_CONTROL_ID as me } from "./filters.js";
18
- import { LayoutOrientationControl as k } from "./layoutOrientation.js";
19
- import { LAYOUT_ORIENTATION_CONTROL_ID as pe } from "./layoutOrientation.js";
20
- import { LocaleControl as L } from "./locale.js";
21
- import { LOCALE_CONTROL_ID as Ne } from "./locale.js";
22
- import { PricePlacementControl as E } from "./pricePlacement.js";
23
- import { PRICE_PLACEMENT_CONTROL_ID as Ie } from "./pricePlacement.js";
24
- import { ProductCountControl as F } from "./productCount.js";
25
- import { PRODUCT_COUNT_CONTROL_ID as be } from "./productCount.js";
26
- import { ProductLayoutControl as D } from "./productLayout.js";
27
- import { PRODUCT_LAYOUT_CONTROL_ID as Se } from "./productLayout.js";
28
- import { ShuffleControl as w } from "./shuffle.js";
29
- import { SHUFFLE_CONTROL_ID as Oe } from "./shuffle.js";
30
- import { StrategyControl as B } from "./strategy.js";
31
- import { STRATEGY_CONTROL_ID as Le } from "./strategy.js";
32
- import { setCurrencyAttributes as U, getBlockElement as v, isPartnerManagedBlock as A, updateProductContentInPlace as x, regenerateProductRowsWithStyles as V } from "./utils.js";
33
- import { adjustProductsToSize as Fe, formatProductPrice as De, getCardComposition as we, getCurrentLayout as Be, getMainContainerTbody as Ue, regenerateMobileProductRows as ve, updatePricesInPlace as Ae, updateSingleProductContent as xe } from "./utils.js";
34
- import { useDebounceFn as m } from "../../../../../node_modules/@vueuse/shared/index.js";
35
- const W = "ui-elements-recommendation-block";
36
- class ce extends N {
7
+ import { RRS_CONFIG_VERSION as P, DEFAULT_NODE_CONFIG as a } from "../../constants/defaultConfig.js";
8
+ import { RECOMMENDATION_ID_ATTR as R } from "../../constants/selectors.js";
9
+ import { RecommendationConfigService as c } from "../../services/configService.js";
10
+ import { useRecommendationExtensionStore as I } from "../../store/recommendation.js";
11
+ import { refreshBlockOutsidePanel as b } from "../../utils/blockRefresh.js";
12
+ import { registerNodeConfigWriter as S, writeBlockConfigOutsidePanel as m, hasEditedConfigChange as k } from "../../utils/nodeConfigWriter.js";
13
+ import { AlgorithmControl as T } from "./algorithm.js";
14
+ import { ALGORITHM_CONTROL_ID as ge } from "./algorithm.js";
15
+ import { CurrencyControl as O } from "./currency.js";
16
+ import { CURRENCY_CONTROL_ID as Ce } from "./currency.js";
17
+ import { FiltersControl as L } from "./filters.js";
18
+ import { FILTERS_CONTROL_ID as ye } from "./filters.js";
19
+ import { LayoutOrientationControl as B } from "./layoutOrientation.js";
20
+ import { LAYOUT_ORIENTATION_CONTROL_ID as Ne } from "./layoutOrientation.js";
21
+ import { LocaleControl as E } from "./locale.js";
22
+ import { LOCALE_CONTROL_ID as Re } from "./locale.js";
23
+ import { PricePlacementControl as F } from "./pricePlacement.js";
24
+ import { PRICE_PLACEMENT_CONTROL_ID as be } from "./pricePlacement.js";
25
+ import { ProductCountControl as D } from "./productCount.js";
26
+ import { PRODUCT_COUNT_CONTROL_ID as ke } from "./productCount.js";
27
+ import { ProductLayoutControl as U } from "./productLayout.js";
28
+ import { PRODUCT_LAYOUT_CONTROL_ID as Oe } from "./productLayout.js";
29
+ import { ShuffleControl as v } from "./shuffle.js";
30
+ import { SHUFFLE_CONTROL_ID as Be } from "./shuffle.js";
31
+ import { StrategyControl as w } from "./strategy.js";
32
+ import { STRATEGY_CONTROL_ID as Fe } from "./strategy.js";
33
+ import { setCurrencyAttributes as A, getBlockElement as V, isPartnerManagedBlock as x, updateProductContentInPlace as W, regenerateProductRowsWithStyles as M } from "./utils.js";
34
+ import { adjustProductsToSize as Ue, formatProductPrice as ve, getCardComposition as we, getCurrentLayout as Ae, getMainContainerTbody as Ve, regenerateMobileProductRows as xe, updatePricesInPlace as We, updateSingleProductContent as Me } from "./utils.js";
35
+ import { useDebounceFn as C } from "../../../../../node_modules/@vueuse/shared/index.js";
36
+ const f = "Update recommendation filters", G = "ui-elements-recommendation-block";
37
+ class ue extends N {
37
38
  constructor() {
38
39
  super(...arguments);
39
- r(this, "store", R());
40
- r(this, "storeUnsubscription", () => {
40
+ i(this, "store", I());
41
+ i(this, "storeUnsubscription", () => {
41
42
  });
42
43
  // A config change waiting to reach the node config. Deferred so it can ride the
43
44
  // re-render's single apply() — one user action must cost one undo press.
44
- r(this, "pendingNodeConfigWrite", null);
45
- r(this, "pendingConfigFlushTimer", null);
46
- // Last configVersion the subscription handled, and whether its products still
47
- // have to reach the canvas — both read on destroy to finish that work.
48
- r(this, "seenConfigVersion", 0);
49
- r(this, "fetchedConfigVersion", 0);
50
- r(this, "hasUnappliedConfigChange", !1);
45
+ i(this, "pendingNodeConfigWrite", null);
46
+ i(this, "pendingConfigFlushTimer", null);
47
+ // What the panel still owes the block it watches — finished outside the panel on teardown
48
+ // and block switch. A new generation tells debounced work queued for the old one to stand down.
49
+ i(this, "trackedBlockId", null);
50
+ i(this, "fetchedConfigVersion", 0);
51
+ i(this, "hasUnrenderedProducts", !1);
52
+ i(this, "panelGeneration", 0);
53
+ i(this, "isPanelAlive", !0);
51
54
  // Sub-control instances for lifecycle management
52
- r(this, "algorithmControl", null);
53
- r(this, "localeControl", null);
54
- r(this, "currencyControl", null);
55
- r(this, "productCountControl", null);
56
- r(this, "productLayoutControl", null);
57
- r(this, "filtersControl", null);
58
- r(this, "shuffleControl", null);
59
- r(this, "pricePlacementControl", null);
60
- r(this, "layoutOrientationControl", null);
61
- r(this, "strategyControl", null);
62
- r(this, "rrsEnabled", !1);
55
+ i(this, "algorithmControl", null);
56
+ i(this, "localeControl", null);
57
+ i(this, "currencyControl", null);
58
+ i(this, "productCountControl", null);
59
+ i(this, "productLayoutControl", null);
60
+ i(this, "filtersControl", null);
61
+ i(this, "shuffleControl", null);
62
+ i(this, "pricePlacementControl", null);
63
+ i(this, "layoutOrientationControl", null);
64
+ i(this, "strategyControl", null);
65
+ i(this, "rrsEnabled", !1);
63
66
  /**
64
67
  * Debounced product fetch to prevent rapid API calls during config changes
65
68
  */
66
- r(this, "_debouncedFetchProducts", m(async () => {
67
- const { configVersion: e } = this.store.$state;
69
+ i(this, "_debouncedFetchProducts", C(async (e, t) => {
70
+ if (t !== this.panelGeneration)
71
+ return;
72
+ const o = this._getBlockConfigVersion(e);
68
73
  try {
69
- await this.store.fetchRecommendationProducts(), this.fetchedConfigVersion = e;
74
+ await (e === null ? this.store.fetchRecommendationProducts() : this.store.fetchRecommendationProductsForBlock(e)), t === this.panelGeneration && (this.fetchedConfigVersion = Math.max(this.fetchedConfigVersion, o));
70
75
  } finally {
71
- this._scheduleConfigFlush();
76
+ t === this.panelGeneration && this._scheduleConfigFlush();
72
77
  }
73
78
  }, 500));
74
79
  /**
@@ -82,29 +87,29 @@ class ce extends N {
82
87
  * count. The store pads products to the configured size, so in-place only
83
88
  * fails when the size actually changed.
84
89
  */
85
- r(this, "_debouncedRegenerateWithProducts", m(() => {
86
- const e = this.store.recommendationProducts;
87
- if (!this.currentNode || !this.api)
90
+ i(this, "_debouncedRegenerateWithProducts", C((e) => {
91
+ const t = this.store.recommendationProducts;
92
+ if (e !== this.panelGeneration || !this.currentNode || !this.api)
88
93
  return;
89
- this.fetchedConfigVersion === this.seenConfigVersion && (this.hasUnappliedConfigChange = !1);
90
- const t = this.api.getDocumentModifier(), o = this._stagePendingNodeConfig(t);
91
- if (A(this.currentNode)) {
92
- o && (t.apply(new y("Update recommendation configuration")), this.pendingNodeConfigWrite = null, this._clearConfigFlush());
94
+ this.hasUnrenderedProducts = !1;
95
+ const o = this.api.getDocumentModifier(), n = this._stagePendingNodeConfig(o);
96
+ if (x(this.currentNode)) {
97
+ n && (o.apply(new _("Update recommendation configuration")), this.pendingNodeConfigWrite = null, this._clearConfigFlush());
93
98
  return;
94
99
  }
95
- x({
100
+ W({
96
101
  currentNode: this.currentNode,
97
- documentModifier: t,
98
- products: e
99
- }) || V({
102
+ documentModifier: o,
103
+ products: t
104
+ }) || M({
100
105
  currentNode: this.currentNode,
101
- documentModifier: t,
102
- products: e
106
+ documentModifier: o,
107
+ products: t
103
108
  });
104
109
  }, 100));
105
110
  }
106
111
  getId() {
107
- return W;
112
+ return G;
108
113
  }
109
114
  get _subControls() {
110
115
  return [
@@ -122,10 +127,10 @@ class ce extends N {
122
127
  }
123
128
  getTemplate() {
124
129
  var e;
125
- return this.rrsEnabled = f().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((t) => {
130
+ return this.rrsEnabled = g().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((t) => {
126
131
  var o;
127
132
  return (o = t == null ? void 0 : t.onDestroy) == null ? void 0 : o.call(t);
128
- }), this.algorithmControl = new S(), this.localeControl = new L(), this.currencyControl = new T(), this.productCountControl = new F(), this.productLayoutControl = new D(), this.filtersControl = new O(), this.shuffleControl = new w(), this.pricePlacementControl = new E(), this.layoutOrientationControl = new k(), this.strategyControl = this.rrsEnabled ? new B() : null, this._subControls.forEach((t) => {
133
+ }), this.algorithmControl = new T(), this.localeControl = new E(), this.currencyControl = new O(), this.productCountControl = new D(), this.productLayoutControl = new U(), this.filtersControl = new L(), this.shuffleControl = new v(), this.pricePlacementControl = new F(), this.layoutOrientationControl = new B(), this.strategyControl = this.rrsEnabled ? new w() : null, this._subControls.forEach((t) => {
129
134
  t && (t.api = this.api);
130
135
  }), `
131
136
  <div class="recommendation-controls-container">
@@ -143,16 +148,16 @@ class ce extends N {
143
148
  `;
144
149
  }
145
150
  _showControlsForBlock(e) {
146
- var i;
147
- const t = (i = this.getContainer()) == null ? void 0 : i.querySelector(".recommendation-controls-container");
151
+ var r;
152
+ const t = (r = this.getContainer()) == null ? void 0 : r.querySelector(".recommendation-controls-container");
148
153
  if (!t)
149
154
  return;
150
- const o = this._getRecommendationIdFromNode(e) === null ? null : d.getConfig(e), n = this.rrsEnabled && !!o && (!!(o != null && o.strategyId) || ((o == null ? void 0 : o.configVersion) ?? 0) >= _), s = this.rrsEnabled && !!o && !n;
155
+ const o = this._getRecommendationIdFromNode(e) === null ? null : c.getConfig(e), n = this.rrsEnabled && !!o && (!!(o != null && o.strategyId) || ((o == null ? void 0 : o.configVersion) ?? 0) >= P), s = this.rrsEnabled && !!o && !n;
151
156
  t.classList.toggle("strategy-block", n), t.classList.toggle("legacy-strategy-block", s);
152
157
  }
153
158
  async onRender() {
154
159
  var o;
155
- b(this.api);
160
+ S(this.api);
156
161
  const e = this._getRecommendationIdFromNode(this.currentNode), t = e ?? this.store.currentRecommendationId;
157
162
  if (t !== null && this.store.setCurrentBlock(t), e !== null && this._syncNodeConfigIfChanged(e), this._listenStateUpdates(), this._showControlsForBlock(this.currentNode), e !== null && this.strategyControl && (this.strategyControl.api = this.api, this.strategyControl.currentNode = this.currentNode, this.strategyControl.onRender()), t !== null && ((o = this.store.blockStates[t]) != null && o.isInitialized)) {
158
163
  this._initializeSubControls();
@@ -172,10 +177,9 @@ class ce extends N {
172
177
  });
173
178
  }
174
179
  onDestroy() {
175
- const e = this.hasUnappliedConfigChange || this.store.$state.configVersion !== this.seenConfigVersion;
176
- this.storeUnsubscription(), e ? this._refreshProductsOutsidePanel() : this._flushPendingNodeConfig(), this._subControls.forEach((t) => {
177
- var o;
178
- return (o = t == null ? void 0 : t.onDestroy) == null ? void 0 : o.call(t);
180
+ this.panelGeneration++, this.isPanelAlive = !1, this.storeUnsubscription(), this._finishBlockOutsidePanel(), this._subControls.forEach((e) => {
181
+ var t;
182
+ return (t = e == null ? void 0 : e.onDestroy) == null ? void 0 : t.call(e);
179
183
  });
180
184
  }
181
185
  /**
@@ -213,34 +217,35 @@ class ce extends N {
213
217
  * state was rebuilt with (SD-150347).
214
218
  */
215
219
  _syncNodeConfigIfChanged(e) {
220
+ var s;
216
221
  this.pendingNodeConfigWrite && this.pendingNodeConfigWrite.blockId !== e && this._flushPendingNodeConfig();
217
222
  const t = this.store.blockStates[e];
218
223
  if (!t)
219
224
  return;
220
- const o = JSON.stringify(d.getConfig(this.currentNode)), n = t.syncedConfigFingerprint;
221
- t.syncedConfigFingerprint = o, n !== o && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
225
+ const o = JSON.stringify(c.getConfig(this.currentNode)), n = t.syncedConfigFingerprint;
226
+ t.syncedConfigFingerprint = o, n !== o && ((s = this.pendingNodeConfigWrite) == null ? void 0 : s.blockId) !== e && this._syncNodeConfigToStore();
222
227
  }
223
228
  /** Whether the deferred write would move the node's strategyId — see the caller (SD-149916). */
224
229
  _isPendingStrategyIdChange() {
225
230
  const e = this.pendingNodeConfigWrite;
226
- return e ? d.getConfig(this.currentNode).strategyId !== e.updates.strategyId : !1;
231
+ return e ? c.getConfig(this.currentNode).strategyId !== e.updates.strategyId : !1;
227
232
  }
228
- _capturePendingNodeConfigWrite(e = this.store.currentRecommendationId) {
229
- const t = e === null ? void 0 : this.store.blockStates[e];
230
- if (!this.currentNode || !this.api || e === null || !t)
231
- return;
232
- const { filters: o, strategy: n, strategyId: s, size: i, nodeConfigVersion: l } = t.recommendationConfigs, { partnerName: a } = f();
233
- this.pendingNodeConfigWrite = {
233
+ _capturePendingNodeConfigWrite() {
234
+ const e = this.store.currentRecommendationId, t = e === null ? void 0 : this.store.blockStates[e];
235
+ !this.currentNode || !this.api || e === null || !t || (this.pendingNodeConfigWrite = {
234
236
  blockId: e,
235
- node: this.currentNode,
236
- updates: {
237
- filters: o,
238
- strategy: n,
239
- strategyId: s,
240
- size: i,
241
- configVersion: l,
242
- ...a.value ? { partnerName: a.value } : {}
243
- }
237
+ updates: this._getNodeConfigUpdates(t.recommendationConfigs)
238
+ });
239
+ }
240
+ _getNodeConfigUpdates(e) {
241
+ const { filters: t, strategy: o, strategyId: n, size: s, nodeConfigVersion: r } = e, { partnerName: d } = g();
242
+ return {
243
+ filters: t,
244
+ strategy: o,
245
+ strategyId: n,
246
+ size: s,
247
+ configVersion: r,
248
+ ...d.value ? { partnerName: d.value } : {}
244
249
  };
245
250
  }
246
251
  /**
@@ -255,7 +260,7 @@ class ce extends N {
255
260
  */
256
261
  _stagePendingNodeConfig(e) {
257
262
  const t = this.pendingNodeConfigWrite;
258
- return !t || !this.currentNode ? !1 : (d.stageConfig(e, this.currentNode, t.updates), !0);
263
+ return !t || !this.currentNode ? !1 : (c.stageConfig(e, this.currentNode, t.updates), !0);
259
264
  }
260
265
  /**
261
266
  * Arms the guaranteed fallback write, once the product fetch has settled. The
@@ -272,19 +277,28 @@ class ce extends N {
272
277
  }
273
278
  /**
274
279
  * Writes the deferred change standalone when the batch it was staged into never
275
- * committed. Always targets the LIVE node — the captured one is an immutable
276
- * snapshot the intervening re-render staled, and saveConfig swallows that failure.
280
+ * committed. Always targets a LIVE node — a captured one is an immutable snapshot
281
+ * the intervening re-render staled, and saveConfig swallows that failure.
277
282
  */
278
283
  _flushPendingNodeConfig() {
279
284
  const e = this.pendingNodeConfigWrite;
280
- if (this.pendingNodeConfigWrite = null, this._clearConfigFlush(), !e || !this.api)
281
- return;
282
- const t = e.blockId === this.store.currentRecommendationId && this.currentNode ? this.currentNode : e.node, o = d.getConfig(t);
283
- JSON.stringify(o.filters) === JSON.stringify(e.updates.filters) && o.strategy === e.updates.strategy && o.strategyId === e.updates.strategyId && o.size === e.updates.size || d.updateConfig(this.api, t, e.updates, "Update recommendation filters");
285
+ if (this.pendingNodeConfigWrite = null, this._clearConfigFlush(), !(!e || !this.api)) {
286
+ if (e.blockId !== this.store.currentRecommendationId || !this.currentNode) {
287
+ const { blockId: t, updates: o } = e;
288
+ !m(t, o, f) && this.store.blockStates[t] && console.error("[recommendation] pending config write did not reach a node", { blockId: t });
289
+ return;
290
+ }
291
+ k(this.currentNode, e.updates) && c.updateConfig(
292
+ this.api,
293
+ this.currentNode,
294
+ e.updates,
295
+ f
296
+ );
297
+ }
284
298
  }
285
299
  _syncNodeConfigToStore() {
286
300
  var n;
287
- const e = d.getConfig(this.currentNode), t = this.store.currentRecommendationId, o = t !== null && ((n = this.store.blockStates[t]) == null ? void 0 : n.isInitialized);
301
+ const e = c.getConfig(this.currentNode), t = this.store.currentRecommendationId, o = t !== null && ((n = this.store.blockStates[t]) == null ? void 0 : n.isInitialized);
288
302
  this.store.patchCurrentBlockConfig({
289
303
  strategy: e.strategy,
290
304
  strategyId: e.strategyId,
@@ -324,17 +338,26 @@ class ce extends N {
324
338
  * Marks the block as initialized to prevent redundant fetches on re-selection.
325
339
  */
326
340
  async _fetchBlockData(e) {
327
- e !== null && this.store.markBlockInitialized(e), (await Promise.allSettled([
341
+ if (e !== null && this.store.markBlockInitialized(e), (await Promise.allSettled([
328
342
  this.store.fetchRecommendationCreateData(),
329
343
  this.store.fetchRecommendationFilters()
330
- ])).forEach((o, n) => {
331
- o.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][n]} failed`, o.reason);
332
- }), this._applySmartDefaults();
344
+ ])).forEach((n, s) => {
345
+ n.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][s]} failed`, n.reason);
346
+ }), e !== null && this.store.currentRecommendationId !== e) {
347
+ this._refreshOutsidePanel(e, !0);
348
+ return;
349
+ }
350
+ this._applySmartDefaults();
351
+ const o = this._getBlockConfigVersion(e);
333
352
  try {
334
353
  await this.store.fetchRecommendationProducts();
335
- } catch (o) {
336
- console.warn("Recommendation block: fetchRecommendationProducts failed", o);
354
+ } catch (n) {
355
+ console.warn("Recommendation block: fetchRecommendationProducts failed", n);
337
356
  }
357
+ e !== null && !this._isPanelOn(e) && this._refreshOutsidePanel(e, this._getBlockConfigVersion(e) !== o);
358
+ }
359
+ _isPanelOn(e) {
360
+ return this.isPanelAlive && this.store.currentRecommendationId === e;
338
361
  }
339
362
  /**
340
363
  * Applies smart defaults for newly dropped blocks.
@@ -349,36 +372,36 @@ class ce extends N {
349
372
  _applySmartDefaults() {
350
373
  if (!this.currentNode || !this.api)
351
374
  return;
352
- const e = d.getConfig(this.currentNode), t = {};
375
+ const e = c.getConfig(this.currentNode), t = {};
353
376
  let o = null, n = null, s = null;
354
- if (e.currency.code === c.currency.code) {
355
- const { currencyList: i } = this.store;
356
- i.length > 0 && (i.some(
357
- (a) => a.value === `price.${c.currency.code}`
358
- ) || (o = i[0].value.replace("price.", ""), t.currency = {
359
- ...c.currency,
377
+ if (e.currency.code === a.currency.code) {
378
+ const { currencyList: r } = this.store;
379
+ r.length > 0 && (r.some(
380
+ (u) => u.value === `price.${a.currency.code}`
381
+ ) || (o = r[0].value.replace("price.", ""), t.currency = {
382
+ ...a.currency,
360
383
  code: o,
361
384
  symbol: o
362
385
  }));
363
386
  }
364
- if (e.strategy === c.strategy) {
365
- const i = this.store.getActivePredictiveAlgorithms;
366
- i.length > 0 && (i.some(
367
- (a) => a.value === c.strategy
368
- ) || (n = i[0].value, t.strategy = n));
387
+ if (e.strategy === a.strategy) {
388
+ const r = this.store.getActivePredictiveAlgorithms;
389
+ r.length > 0 && (r.some(
390
+ (u) => u.value === a.strategy
391
+ ) || (n = r[0].value, t.strategy = n));
369
392
  }
370
- if (e.language === c.language) {
371
- const i = this.store.getLanguages;
372
- i.length > 0 && (i.some(
373
- (a) => a.value === c.language
374
- ) || (s = i[0].value, t.language = s));
393
+ if (e.language === a.language) {
394
+ const r = this.store.getLanguages;
395
+ r.length > 0 && (r.some(
396
+ (u) => u.value === a.language
397
+ ) || (s = r[0].value, t.language = s));
375
398
  }
376
- !o && !n && !s || (d.updateConfig(
399
+ !o && !n && !s || (c.updateConfig(
377
400
  this.api,
378
401
  this.currentNode,
379
402
  t,
380
403
  "Applied smart defaults"
381
- ), o && t.currency && U({
404
+ ), o && t.currency && A({
382
405
  currentNode: this.currentNode,
383
406
  documentModifier: this.api.getDocumentModifier(),
384
407
  currency: t.currency
@@ -388,10 +411,10 @@ class ce extends N {
388
411
  name: o,
389
412
  value: o,
390
413
  symbol: o,
391
- alignment: c.currency.alignment === "before" ? "0" : "1",
392
- decimalCount: c.currency.decimalCount.toString(),
393
- decimalSeparator: c.currency.decimalSeparator,
394
- thousandSeparator: c.currency.thousandSeparator
414
+ alignment: a.currency.alignment === "before" ? "0" : "1",
415
+ decimalCount: a.currency.decimalCount.toString(),
416
+ decimalSeparator: a.currency.decimalSeparator,
417
+ thousandSeparator: a.currency.thousandSeparator
395
418
  }
396
419
  } : {},
397
420
  ...n ? { strategy: n } : {},
@@ -402,54 +425,57 @@ class ce extends N {
402
425
  * Reads the recommendation-id attribute from the block element within the node
403
426
  */
404
427
  _getRecommendationIdFromNode(e) {
405
- const t = v(e);
428
+ const t = V(e);
406
429
  if (!t || !("getAttribute" in t))
407
430
  return null;
408
- const o = t.getAttribute(I);
431
+ const o = t.getAttribute(R);
409
432
  if (!o)
410
433
  return null;
411
434
  const n = parseInt(o);
412
435
  return Number.isNaN(n) ? null : n;
413
436
  }
414
437
  /**
415
- * Fetches and renders the block's products without the panel, carrying the
416
- * deferred config write so both still land as one undo entry.
438
+ * Lands what the panel still owes its block before it stops watching it: the config now, the
439
+ * products through a block-scoped refresh. Never throws — it runs from Stripo's teardown.
417
440
  */
418
- async _refreshProductsOutsidePanel() {
419
- var a;
420
- const e = this.store.currentRecommendationId, t = this._getRecommendationIdFromNode(this.currentNode), o = t !== null && t !== e ? t : e;
421
- if (((a = this.pendingNodeConfigWrite) == null ? void 0 : a.blockId) !== o && this._flushPendingNodeConfig(), o === null)
422
- return;
423
- if (this._capturePendingNodeConfigWrite(o), o !== e) {
424
- this._flushPendingNodeConfig();
425
- return;
426
- }
427
- const n = this.pendingNodeConfigWrite;
428
- try {
429
- await this.store.fetchRecommendationProducts();
430
- } catch (g) {
431
- console.warn("Recommendation block: fetchRecommendationProducts failed", g);
432
- }
433
- const s = this.pendingNodeConfigWrite === n, i = s ? (n == null ? void 0 : n.updates) ?? {} : {}, l = this.store.blockStates[e];
441
+ _finishBlockOutsidePanel() {
442
+ const e = this.trackedBlockId;
434
443
  try {
435
- if (l && P(
436
- e,
437
- i,
438
- l.recommendationProducts,
439
- "Update recommendation configuration"
440
- )) {
441
- s && (this.pendingNodeConfigWrite = null, this._clearConfigFlush());
444
+ this._flushPendingNodeConfig();
445
+ const t = e === null ? void 0 : this.store.blockStates[e];
446
+ if (e === null || !t)
442
447
  return;
443
- }
444
- s && this._flushPendingNodeConfig();
445
- } catch (g) {
446
- console.error("Recommendation block: refresh outside the panel failed", g);
448
+ const o = this.fetchedConfigVersion !== t.configVersion;
449
+ o && !m(
450
+ e,
451
+ this._getNodeConfigUpdates(t.recommendationConfigs),
452
+ f
453
+ ) && console.error("[recommendation] config write outside the panel did not reach a node", { blockId: e }), (o || this.hasUnrenderedProducts) && this._refreshOutsidePanel(e, o);
454
+ } catch (t) {
455
+ console.error("[recommendation] finishing the block outside the panel failed", t);
456
+ } finally {
457
+ this.hasUnrenderedProducts = !1;
447
458
  }
448
459
  }
460
+ _refreshOutsidePanel(e, t) {
461
+ b(e, {
462
+ pickUpdates: (o) => this._getNodeConfigUpdates(o),
463
+ description: "Update recommendation configuration",
464
+ fetch: t
465
+ }).then((o) => {
466
+ !o && this.store.blockStates[e] && console.error("[recommendation] refresh outside the panel did not reach a node", { blockId: e });
467
+ }).catch((o) => {
468
+ console.error("[recommendation] refresh outside the panel failed", o);
469
+ });
470
+ }
471
+ _getBlockConfigVersion(e) {
472
+ var t;
473
+ return e === null ? 0 : ((t = this.store.blockStates[e]) == null ? void 0 : t.configVersion) ?? 0;
474
+ }
449
475
  /**
450
476
  * Listen to store changes that require product refresh or regeneration.
451
477
  *
452
- * Uses configVersion counter (incremented only by patchCurrentBlockConfig)
478
+ * Uses the block's configVersion counter (bumped by patchCurrentBlockConfig and legacy conversion)
453
479
  * to distinguish user-initiated config changes from internal mutations
454
480
  * (e.g., fetchRecommendationCreateData setting preferred currency).
455
481
  *
@@ -461,54 +487,54 @@ class ce extends N {
461
487
  */
462
488
  _listenStateUpdates() {
463
489
  const { store: e } = this;
464
- let t = e.recommendationProducts, o = e.currentRecommendationId;
465
- this.seenConfigVersion = e.$state.configVersion, this.hasUnappliedConfigChange = !1, this.storeUnsubscription = e.$subscribe(() => {
490
+ let t = e.recommendationProducts, o = this._getBlockConfigVersion(e.currentRecommendationId);
491
+ this.panelGeneration++, this.isPanelAlive = !0, this.trackedBlockId = e.currentRecommendationId, this.fetchedConfigVersion = o, this.hasUnrenderedProducts = !1, this.storeUnsubscription = e.$subscribe(() => {
466
492
  const n = e.currentRecommendationId;
467
- if (n !== o) {
468
- o = n, t = e.recommendationProducts, this.seenConfigVersion = e.$state.configVersion, this.hasUnappliedConfigChange = !1;
493
+ if (n !== this.trackedBlockId) {
494
+ this._finishBlockOutsidePanel(), this.panelGeneration++, this.trackedBlockId = n, t = e.recommendationProducts, o = this._getBlockConfigVersion(n), this.fetchedConfigVersion = o;
469
495
  return;
470
496
  }
471
- const s = e.$state.configVersion;
472
- s !== this.seenConfigVersion && (this.seenConfigVersion = s, this.hasUnappliedConfigChange = !0, this._capturePendingNodeConfigWrite(), this._isPendingStrategyIdChange() && this._flushPendingNodeConfig(), this._debouncedFetchProducts());
473
- const i = e.recommendationProducts, l = i !== t, a = Array.isArray(i) && i.length > 0;
474
- l && a && (t = i, this._debouncedRegenerateWithProducts());
497
+ const s = this._getBlockConfigVersion(n);
498
+ s !== o && (o = s, this._capturePendingNodeConfigWrite(), this._isPendingStrategyIdChange() && this._flushPendingNodeConfig(), this._debouncedFetchProducts(n, this.panelGeneration));
499
+ const r = e.recommendationProducts, d = r !== t, u = Array.isArray(r) && r.length > 0;
500
+ d && u && (t = r, this.hasUnrenderedProducts = !0, this._debouncedRegenerateWithProducts(this.panelGeneration));
475
501
  });
476
502
  }
477
503
  }
478
504
  export {
479
- ue as ALGORITHM_CONTROL_ID,
480
- S as AlgorithmControl,
481
- W as CONTROL_BLOCK_ID,
482
- ge as CURRENCY_CONTROL_ID,
483
- T as CurrencyControl,
484
- me as FILTERS_CONTROL_ID,
485
- O as FiltersControl,
486
- pe as LAYOUT_ORIENTATION_CONTROL_ID,
487
- Ne as LOCALE_CONTROL_ID,
488
- k as LayoutOrientationControl,
489
- L as LocaleControl,
490
- Ie as PRICE_PLACEMENT_CONTROL_ID,
491
- be as PRODUCT_COUNT_CONTROL_ID,
492
- Se as PRODUCT_LAYOUT_CONTROL_ID,
493
- E as PricePlacementControl,
494
- F as ProductCountControl,
495
- D as ProductLayoutControl,
496
- ce as RecommendationBlockControl,
497
- Oe as SHUFFLE_CONTROL_ID,
498
- Le as STRATEGY_CONTROL_ID,
499
- w as ShuffleControl,
500
- B as StrategyControl,
501
- Fe as adjustProductsToSize,
502
- De as formatProductPrice,
503
- v as getBlockElement,
505
+ ge as ALGORITHM_CONTROL_ID,
506
+ T as AlgorithmControl,
507
+ G as CONTROL_BLOCK_ID,
508
+ Ce as CURRENCY_CONTROL_ID,
509
+ O as CurrencyControl,
510
+ ye as FILTERS_CONTROL_ID,
511
+ L as FiltersControl,
512
+ Ne as LAYOUT_ORIENTATION_CONTROL_ID,
513
+ Re as LOCALE_CONTROL_ID,
514
+ B as LayoutOrientationControl,
515
+ E as LocaleControl,
516
+ be as PRICE_PLACEMENT_CONTROL_ID,
517
+ ke as PRODUCT_COUNT_CONTROL_ID,
518
+ Oe as PRODUCT_LAYOUT_CONTROL_ID,
519
+ F as PricePlacementControl,
520
+ D as ProductCountControl,
521
+ U as ProductLayoutControl,
522
+ ue as RecommendationBlockControl,
523
+ Be as SHUFFLE_CONTROL_ID,
524
+ Fe as STRATEGY_CONTROL_ID,
525
+ v as ShuffleControl,
526
+ w as StrategyControl,
527
+ Ue as adjustProductsToSize,
528
+ ve as formatProductPrice,
529
+ V as getBlockElement,
504
530
  we as getCardComposition,
505
- Be as getCurrentLayout,
506
- Ue as getMainContainerTbody,
507
- A as isPartnerManagedBlock,
508
- ve as regenerateMobileProductRows,
509
- V as regenerateProductRowsWithStyles,
510
- U as setCurrencyAttributes,
511
- Ae as updatePricesInPlace,
512
- x as updateProductContentInPlace,
513
- xe as updateSingleProductContent
531
+ Ae as getCurrentLayout,
532
+ Ve as getMainContainerTbody,
533
+ x as isPartnerManagedBlock,
534
+ xe as regenerateMobileProductRows,
535
+ M as regenerateProductRowsWithStyles,
536
+ A as setCurrencyAttributes,
537
+ We as updatePricesInPlace,
538
+ W as updateProductContentInPlace,
539
+ Me as updateSingleProductContent
514
540
  };