@useinsider/guido 3.17.0-beta.668ca65 → 3.17.0-beta.6cedc6c
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.
- package/README.md +5 -5
- package/dist/components/Guido.vue.js +7 -7
- package/dist/components/Guido.vue2.js +59 -57
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +5 -5
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +31 -30
- package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue.js +17 -0
- package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +52 -0
- package/dist/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue2.js +36 -35
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +198 -135
- package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +1 -1
- package/dist/extensions/Blocks/Recommendation/services/configService.js +34 -16
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +47 -37
- package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +22 -0
- package/dist/guido.css +1 -1
- package/dist/services/recommendationApi.js +1 -1
- package/dist/src/components/organisms/extensions/recommendation/RemoveStrategyModal.vue.d.ts +2 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +38 -8
- package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +12 -1
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +26 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/nodeConfigWriter.d.ts +31 -0
- package/dist/src/utils/genericUtil.d.ts +5 -0
- package/dist/utils/genericUtil.js +28 -27
- package/package.json +2 -2
|
@@ -1,59 +1,70 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
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
4
|
import { useConfig as p } from "../../../../../composables/useConfig.js";
|
|
5
|
-
import {
|
|
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";
|
|
6
7
|
import { CURRENT_CONFIG_VERSION as _, DEFAULT_NODE_CONFIG as a } from "../../constants/defaultConfig.js";
|
|
7
|
-
import { RecommendationConfigService as
|
|
8
|
-
import { useRecommendationExtensionStore as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
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, regenerateMobileProductRows as wt, updatePricesInPlace as At, updateSingleProductContent as vt } 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 {
|
|
34
36
|
constructor() {
|
|
35
37
|
super(...arguments);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
r(this, "store", I());
|
|
39
|
+
r(this, "storeUnsubscription", () => {
|
|
38
40
|
});
|
|
39
|
-
|
|
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);
|
|
40
47
|
// Sub-control instances for lifecycle management
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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);
|
|
52
59
|
/**
|
|
53
60
|
* Debounced product fetch to prevent rapid API calls during config changes
|
|
54
61
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
r(this, "_debouncedFetchProducts", f(async () => {
|
|
63
|
+
try {
|
|
64
|
+
await this.store.fetchRecommendationProducts();
|
|
65
|
+
} finally {
|
|
66
|
+
this._scheduleConfigFlush();
|
|
67
|
+
}
|
|
57
68
|
}, 500));
|
|
58
69
|
/**
|
|
59
70
|
* Debounced content update when products arrive from API.
|
|
@@ -66,16 +77,20 @@ class ot extends y {
|
|
|
66
77
|
* count. The store pads products to the configured size, so in-place only
|
|
67
78
|
* fails when the size actually changed.
|
|
68
79
|
*/
|
|
69
|
-
|
|
80
|
+
r(this, "_debouncedRegenerateWithProducts", f(() => {
|
|
70
81
|
const t = this.store.recommendationProducts;
|
|
71
|
-
if (!this.currentNode || !this.api
|
|
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());
|
|
72
87
|
return;
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
}
|
|
89
|
+
x({
|
|
75
90
|
currentNode: this.currentNode,
|
|
76
91
|
documentModifier: e,
|
|
77
92
|
products: t
|
|
78
|
-
}) ||
|
|
93
|
+
}) || B({
|
|
79
94
|
currentNode: this.currentNode,
|
|
80
95
|
documentModifier: e,
|
|
81
96
|
products: t
|
|
@@ -83,7 +98,7 @@ class ot extends y {
|
|
|
83
98
|
}, 100));
|
|
84
99
|
}
|
|
85
100
|
getId() {
|
|
86
|
-
return
|
|
101
|
+
return $;
|
|
87
102
|
}
|
|
88
103
|
get _subControls() {
|
|
89
104
|
return [
|
|
@@ -104,7 +119,7 @@ class ot extends y {
|
|
|
104
119
|
return this.rrsEnabled = p().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((e) => {
|
|
105
120
|
var o;
|
|
106
121
|
return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
|
|
107
|
-
}), this.algorithmControl = new
|
|
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) => {
|
|
108
123
|
e && (e.api = this.api);
|
|
109
124
|
}), `
|
|
110
125
|
<div class="recommendation-controls-container">
|
|
@@ -126,13 +141,14 @@ class ot extends y {
|
|
|
126
141
|
const e = (i = this.getContainer()) == null ? void 0 : i.querySelector(".recommendation-controls-container");
|
|
127
142
|
if (!e)
|
|
128
143
|
return;
|
|
129
|
-
const o = this._getRecommendationIdFromNode(t) === null ? null :
|
|
130
|
-
e.classList.toggle("strategy-block",
|
|
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);
|
|
131
146
|
}
|
|
132
147
|
async onRender() {
|
|
133
148
|
var o;
|
|
149
|
+
R(this.api);
|
|
134
150
|
const t = this._getRecommendationIdFromNode(this.currentNode), e = t ?? this.store.currentRecommendationId;
|
|
135
|
-
if (e !== null && this.store.setCurrentBlock(e), t !== null &&
|
|
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)) {
|
|
136
152
|
this._initializeSubControls();
|
|
137
153
|
return;
|
|
138
154
|
}
|
|
@@ -142,15 +158,15 @@ class ot extends y {
|
|
|
142
158
|
var o;
|
|
143
159
|
super.onTemplateNodeUpdated(t);
|
|
144
160
|
const e = this._getRecommendationIdFromNode(t);
|
|
145
|
-
e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null &&
|
|
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(() => {
|
|
146
162
|
this._initializeSubControls();
|
|
147
|
-
}), this._subControls.forEach((
|
|
163
|
+
}), this._subControls.forEach((n) => {
|
|
148
164
|
var i;
|
|
149
|
-
|
|
165
|
+
n != null && n.api && (n.currentNode = t, (i = n.onTemplateNodeUpdated) == null || i.call(n, t));
|
|
150
166
|
});
|
|
151
167
|
}
|
|
152
168
|
onDestroy() {
|
|
153
|
-
this.storeUnsubscription(), this._subControls.forEach((t) => {
|
|
169
|
+
this.storeUnsubscription(), this._flushPendingNodeConfig(), this._subControls.forEach((t) => {
|
|
154
170
|
var e;
|
|
155
171
|
return (e = t == null ? void 0 : t.onDestroy) == null ? void 0 : e.call(t);
|
|
156
172
|
});
|
|
@@ -175,9 +191,73 @@ class ot extends y {
|
|
|
175
191
|
* Uses triggerRefetch: false because the fetch hasn't happened yet —
|
|
176
192
|
* values are being prepared for the upcoming initial fetch.
|
|
177
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
|
+
}
|
|
178
258
|
_syncNodeConfigToStore() {
|
|
179
|
-
var
|
|
180
|
-
const t =
|
|
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);
|
|
181
261
|
this.store.patchCurrentBlockConfig({
|
|
182
262
|
strategy: t.strategy,
|
|
183
263
|
strategyId: t.strategyId,
|
|
@@ -219,8 +299,8 @@ class ot extends y {
|
|
|
219
299
|
t !== null && this.store.markBlockInitialized(t), (await Promise.allSettled([
|
|
220
300
|
this.store.fetchRecommendationCreateData(),
|
|
221
301
|
this.store.fetchRecommendationFilters()
|
|
222
|
-
])).forEach((o,
|
|
223
|
-
o.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][
|
|
302
|
+
])).forEach((o, n) => {
|
|
303
|
+
o.status === "rejected" && console.warn(`Recommendation block: ${["fetchRecommendationCreateData", "fetchRecommendationFilters"][n]} failed`, o.reason);
|
|
224
304
|
}), this._applySmartDefaults();
|
|
225
305
|
try {
|
|
226
306
|
await this.store.fetchRecommendationProducts();
|
|
@@ -241,12 +321,12 @@ class ot extends y {
|
|
|
241
321
|
_applySmartDefaults() {
|
|
242
322
|
if (!this.currentNode || !this.api)
|
|
243
323
|
return;
|
|
244
|
-
const t =
|
|
245
|
-
let o = null,
|
|
324
|
+
const t = c.getConfig(this.currentNode), e = {};
|
|
325
|
+
let o = null, n = null, i = null;
|
|
246
326
|
if (t.currency.code === a.currency.code) {
|
|
247
327
|
const { currencyList: s } = this.store;
|
|
248
328
|
s.length > 0 && (s.some(
|
|
249
|
-
(
|
|
329
|
+
(d) => d.value === `price.${a.currency.code}`
|
|
250
330
|
) || (o = s[0].value.replace("price.", ""), e.currency = {
|
|
251
331
|
...a.currency,
|
|
252
332
|
code: o,
|
|
@@ -256,21 +336,21 @@ class ot extends y {
|
|
|
256
336
|
if (t.strategy === a.strategy) {
|
|
257
337
|
const s = this.store.getActivePredictiveAlgorithms;
|
|
258
338
|
s.length > 0 && (s.some(
|
|
259
|
-
(
|
|
260
|
-
) || (
|
|
339
|
+
(d) => d.value === a.strategy
|
|
340
|
+
) || (n = s[0].value, e.strategy = n));
|
|
261
341
|
}
|
|
262
342
|
if (t.language === a.language) {
|
|
263
343
|
const s = this.store.getLanguages;
|
|
264
344
|
s.length > 0 && (s.some(
|
|
265
|
-
(
|
|
345
|
+
(d) => d.value === a.language
|
|
266
346
|
) || (i = s[0].value, e.language = i));
|
|
267
347
|
}
|
|
268
|
-
!o && !
|
|
348
|
+
!o && !n && !i || (c.updateConfig(
|
|
269
349
|
this.api,
|
|
270
350
|
this.currentNode,
|
|
271
351
|
e,
|
|
272
352
|
"Applied smart defaults"
|
|
273
|
-
), o && e.currency &&
|
|
353
|
+
), o && e.currency && w({
|
|
274
354
|
currentNode: this.currentNode,
|
|
275
355
|
documentModifier: this.api.getDocumentModifier(),
|
|
276
356
|
currency: e.currency
|
|
@@ -286,7 +366,7 @@ class ot extends y {
|
|
|
286
366
|
thousandSeparator: a.currency.thousandSeparator
|
|
287
367
|
}
|
|
288
368
|
} : {},
|
|
289
|
-
...
|
|
369
|
+
...n ? { strategy: n } : {},
|
|
290
370
|
...i ? { language: i } : {}
|
|
291
371
|
}, { triggerRefetch: !1 }));
|
|
292
372
|
}
|
|
@@ -294,14 +374,14 @@ class ot extends y {
|
|
|
294
374
|
* Reads the recommendation-id attribute from the block element within the node
|
|
295
375
|
*/
|
|
296
376
|
_getRecommendationIdFromNode(t) {
|
|
297
|
-
const e =
|
|
377
|
+
const e = A(t);
|
|
298
378
|
if (!e || !("getAttribute" in e))
|
|
299
379
|
return null;
|
|
300
|
-
const o = e.getAttribute(
|
|
380
|
+
const o = e.getAttribute(U);
|
|
301
381
|
if (!o)
|
|
302
382
|
return null;
|
|
303
|
-
const
|
|
304
|
-
return Number.isNaN(
|
|
383
|
+
const n = parseInt(o);
|
|
384
|
+
return Number.isNaN(n) ? null : n;
|
|
305
385
|
}
|
|
306
386
|
/**
|
|
307
387
|
* Listen to store changes that require product refresh or regeneration.
|
|
@@ -318,70 +398,53 @@ class ot extends y {
|
|
|
318
398
|
*/
|
|
319
399
|
_listenStateUpdates() {
|
|
320
400
|
const { store: t } = this;
|
|
321
|
-
let e = t.recommendationProducts, o = t.$state.configVersion,
|
|
401
|
+
let e = t.recommendationProducts, o = t.$state.configVersion, n = t.currentRecommendationId;
|
|
322
402
|
this.storeUnsubscription = t.$subscribe(() => {
|
|
323
403
|
const i = t.currentRecommendationId;
|
|
324
|
-
if (i !==
|
|
325
|
-
|
|
404
|
+
if (i !== n) {
|
|
405
|
+
n = i, e = t.recommendationProducts, o = t.$state.configVersion;
|
|
326
406
|
return;
|
|
327
407
|
}
|
|
328
408
|
const s = t.$state.configVersion;
|
|
329
|
-
s !== o && (o = s, this.
|
|
330
|
-
const
|
|
331
|
-
|
|
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());
|
|
332
412
|
});
|
|
333
413
|
}
|
|
334
|
-
/**
|
|
335
|
-
* Persists filter + strategy state to the Stripo node config so it survives
|
|
336
|
-
* save/reload (strategyId must reach esd-ext-config before any save).
|
|
337
|
-
* `size` rides along: assigning a strategy writes it to the store only, and a
|
|
338
|
-
* stale node config would rebuild the block against the old slot count.
|
|
339
|
-
*/
|
|
340
|
-
_persistFiltersToNodeConfig() {
|
|
341
|
-
if (!this.currentNode || !this.api)
|
|
342
|
-
return;
|
|
343
|
-
const { filters: t, strategyId: e, size: o } = this.store.recommendationConfigs, r = m.getConfig(this.currentNode);
|
|
344
|
-
JSON.stringify(r.filters) === JSON.stringify(t) && r.strategyId === e && r.size === o || m.updateConfig(
|
|
345
|
-
this.api,
|
|
346
|
-
this.currentNode,
|
|
347
|
-
{ filters: t, strategyId: e, size: o },
|
|
348
|
-
"Update recommendation filters"
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
414
|
}
|
|
352
415
|
export {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
+
v as isPartnerManagedBlock,
|
|
444
|
+
wt as regenerateMobileProductRows,
|
|
445
|
+
B as regenerateProductRowsWithStyles,
|
|
446
|
+
w as setCurrencyAttributes,
|
|
447
|
+
At as updatePricesInPlace,
|
|
448
|
+
x as updateProductContentInPlace,
|
|
449
|
+
vt as updateSingleProductContent
|
|
387
450
|
};
|
|
@@ -104,7 +104,7 @@ class f extends h {
|
|
|
104
104
|
const i = t.querySelector(a);
|
|
105
105
|
i && (i.addEventListener("click", n), this.listeners.push({ element: i, handler: n }));
|
|
106
106
|
};
|
|
107
|
-
e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.
|
|
107
|
+
e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.openRemoveStrategyModal());
|
|
108
108
|
}
|
|
109
109
|
_renderState() {
|
|
110
110
|
var l;
|
|
@@ -2,13 +2,13 @@ import { ModificationDescription as h } from "../../../../node_modules/@stripoin
|
|
|
2
2
|
import { PRE_RRS_CONFIG_VERSION as C, DEFAULT_NODE_CONFIG as c } from "../constants/defaultConfig.js";
|
|
3
3
|
import { setCurrencyAttributes as D } from "../controls/main/utils.js";
|
|
4
4
|
import { hasMinimalConfig as S } from "../types/nodeConfig.js";
|
|
5
|
-
function A(
|
|
6
|
-
return
|
|
5
|
+
function A(r) {
|
|
6
|
+
return r === "." || r === "," || r === " ";
|
|
7
7
|
}
|
|
8
|
-
function N(
|
|
9
|
-
return
|
|
8
|
+
function N(r) {
|
|
9
|
+
return r === "." || r === "," || r === " " || r === "";
|
|
10
10
|
}
|
|
11
|
-
class
|
|
11
|
+
class M {
|
|
12
12
|
// ========================================================================
|
|
13
13
|
// Read Operations
|
|
14
14
|
// ========================================================================
|
|
@@ -83,9 +83,27 @@ class F {
|
|
|
83
83
|
* @returns The new complete configuration
|
|
84
84
|
*/
|
|
85
85
|
static updateConfig(i, t, o, e) {
|
|
86
|
-
const
|
|
86
|
+
const n = this.getConfig(t), u = this.deepMerge(n, o);
|
|
87
87
|
return this.saveConfig(i, t, u, e), u;
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Accumulate a config update into an existing modifier batch, WITHOUT applying.
|
|
91
|
+
*
|
|
92
|
+
* The caller owns the apply(), so the write shares one undo entry with the rest
|
|
93
|
+
* of that batch — a change whose visible result only lands after an async product
|
|
94
|
+
* fetch would otherwise cost the user two undo presses (SD-149105).
|
|
95
|
+
* @param documentModifier - The batch to accumulate into (caller applies)
|
|
96
|
+
* @param node - The immutable HTML node to write to
|
|
97
|
+
* @param updates - Partial config with values to update
|
|
98
|
+
*/
|
|
99
|
+
static stageConfig(i, t, o) {
|
|
100
|
+
const e = this.deepMerge(this.getConfig(t), o);
|
|
101
|
+
try {
|
|
102
|
+
i.modifyHtml(t).setNodeConfig(e);
|
|
103
|
+
} catch (n) {
|
|
104
|
+
console.warn("[RecommendationConfigService] Failed to stage config:", n);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
89
107
|
/**
|
|
90
108
|
* Initialize configuration for a new block
|
|
91
109
|
*
|
|
@@ -126,8 +144,8 @@ class F {
|
|
|
126
144
|
static saveConfig(i, t, o, e) {
|
|
127
145
|
try {
|
|
128
146
|
i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new h(e));
|
|
129
|
-
} catch (
|
|
130
|
-
console.warn("[RecommendationConfigService] Failed to save config:",
|
|
147
|
+
} catch (n) {
|
|
148
|
+
console.warn("[RecommendationConfigService] Failed to save config:", n);
|
|
131
149
|
}
|
|
132
150
|
}
|
|
133
151
|
// ========================================================================
|
|
@@ -164,20 +182,20 @@ class F {
|
|
|
164
182
|
s && typeof s == "object" && Object.assign(o, s);
|
|
165
183
|
} catch {
|
|
166
184
|
}
|
|
167
|
-
const
|
|
168
|
-
|
|
185
|
+
const n = t.getAttribute("data-layout");
|
|
186
|
+
n === "list" || n === "horizontal" ? o.layout = "list" : (n === "grid" || n === "vertical") && (o.layout = "grid");
|
|
169
187
|
const u = t.getAttribute("data-card-composition");
|
|
170
188
|
u && (o.composition = u.split(",").filter(Boolean));
|
|
171
189
|
const l = t.getAttribute("data-column-spacing");
|
|
172
190
|
l && (o.columnSpacing = parseInt(l) || c.columnSpacing);
|
|
173
|
-
const
|
|
174
|
-
if (
|
|
175
|
-
const s = t.getAttribute("currency"),
|
|
176
|
-
if (s ||
|
|
191
|
+
const p = t.getAttribute("data-row-spacing");
|
|
192
|
+
if (p && (o.rowSpacing = parseInt(p) || c.rowSpacing), !o.currency) {
|
|
193
|
+
const s = t.getAttribute("currency"), b = t.getAttribute("currency-symbol"), y = t.getAttribute("currency-alignment"), f = t.getAttribute("currency-thousand-separator"), g = t.getAttribute("currency-decimal-separator"), m = t.getAttribute("currency-decimal-count");
|
|
194
|
+
if (s || b || y || f || g || m) {
|
|
177
195
|
const a = c.currency, d = m ? parseInt(m) : NaN;
|
|
178
196
|
o.currency = {
|
|
179
197
|
code: s ?? a.code,
|
|
180
|
-
symbol:
|
|
198
|
+
symbol: b ?? a.symbol,
|
|
181
199
|
alignment: y === "0" ? "before" : "after",
|
|
182
200
|
decimalCount: Number.isFinite(d) ? d : a.decimalCount,
|
|
183
201
|
decimalSeparator: A(g) ? g : a.decimalSeparator,
|
|
@@ -279,5 +297,5 @@ class F {
|
|
|
279
297
|
}
|
|
280
298
|
}
|
|
281
299
|
export {
|
|
282
|
-
|
|
300
|
+
M as RecommendationConfigService
|
|
283
301
|
};
|