@useinsider/guido 3.18.0-beta.fda7e92 → 3.18.1-beta.0725bd5
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/dist/components/Guido.vue.js +1 -1
- package/dist/components/Guido.vue2.js +86 -82
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +13 -11
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +65 -53
- package/dist/components/organisms/header/EditorActions.vue.js +1 -1
- package/dist/components/organisms/header/EditorActions.vue2.js +54 -41
- package/dist/components/organisms/onboarding/OnboardingWrapper.vue2.js +20 -18
- package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.js +21 -0
- package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue2.js +47 -0
- package/dist/composables/useActionsApi.js +82 -67
- package/dist/composables/useAutoSave.js +31 -26
- package/dist/composables/useCustomInterfaceAppearance.js +46 -41
- package/dist/composables/useEditorLock.js +20 -0
- package/dist/composables/useGuidoStateBridge.js +37 -31
- package/dist/composables/useHtmlValidator.js +84 -79
- package/dist/composables/useRecommendation.js +21 -18
- package/dist/composables/useSave.js +42 -39
- package/dist/composables/useStripo.js +7 -7
- package/dist/enums/extensions/recommendationBlock.js +38 -31
- package/dist/extensions/Blocks/Recommendation/block.js +43 -39
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +62 -57
- package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +84 -52
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +210 -130
- package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +21 -12
- package/dist/guido.css +1 -1
- package/dist/src/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.d.ts +2 -0
- package/dist/src/composables/useEditorLock.d.ts +10 -0
- package/dist/src/enums/extensions/recommendationBlock.d.ts +2 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +2 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +9 -0
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +74 -0
- package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +4 -0
- package/dist/src/stores/onboarding.d.ts +377 -0
- package/dist/static/styles/components/recommendation-strategy.css.js +51 -4
- package/dist/stores/onboarding.js +41 -36
- package/dist/utils/templatePreparation.js +50 -50
- package/package.json +1 -1
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as
|
|
2
|
-
import { useRecommendationApi as
|
|
3
|
-
import { useConfigStore as
|
|
4
|
-
import { defineStore as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as k, strategyEditPath as G, URLS as D, getOperatorOptions as _, PriceAttributes as L } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { useRecommendationApi as E } from "../../../../services/recommendationApi.js";
|
|
3
|
+
import { useConfigStore as F } from "../../../../stores/config.js";
|
|
4
|
+
import { defineStore as N } from "pinia";
|
|
5
5
|
import "../constants/selectors.js";
|
|
6
|
-
import { DEFAULT_MOBILE_CARDS_IN_ROW as
|
|
7
|
-
import { DEFAULT_NODE_CONFIG as
|
|
8
|
-
import { getDefaultProducts as
|
|
9
|
-
import { generateCompleteFilterQuery as
|
|
10
|
-
import { getPartnerRecommendationParams as
|
|
11
|
-
import { sanitizeProductIds as
|
|
12
|
-
import { isFilterValid as
|
|
13
|
-
import { isConfigValid as
|
|
14
|
-
const
|
|
15
|
-
let
|
|
16
|
-
const
|
|
17
|
-
|
|
6
|
+
import { DEFAULT_MOBILE_CARDS_IN_ROW as U, DEFAULT_CARDS_IN_ROW as A } from "../constants/layout.js";
|
|
7
|
+
import { DEFAULT_NODE_CONFIG as x, EXCLUDED_ALGORITHM_IDS as B } from "../constants/defaultConfig.js";
|
|
8
|
+
import { getDefaultProducts as C } from "../templates/utils.js";
|
|
9
|
+
import { generateCompleteFilterQuery as v } from "../utils/filterUtil.js";
|
|
10
|
+
import { getPartnerRecommendationParams as M } from "../utils/partnerCustomizations.js";
|
|
11
|
+
import { sanitizeProductIds as O } from "../utils/productIds.js";
|
|
12
|
+
import { isFilterValid as T } from "../validation/filterSchema.js";
|
|
13
|
+
import { getInvalidFields as z, isConfigValid as V } from "../validation/requiredFields.js";
|
|
14
|
+
const d = E();
|
|
15
|
+
let h = null, g = null, S = null, p = null, y = 0;
|
|
16
|
+
const b = /* @__PURE__ */ new Map();
|
|
17
|
+
let l = null;
|
|
18
|
+
function P() {
|
|
18
19
|
return {
|
|
19
|
-
cardsInRow:
|
|
20
|
+
cardsInRow: A,
|
|
20
21
|
currencySettings: {
|
|
21
22
|
name: "USD",
|
|
22
23
|
value: "USD",
|
|
@@ -30,13 +31,17 @@ function w() {
|
|
|
30
31
|
productIds: [],
|
|
31
32
|
id: 1,
|
|
32
33
|
language: "en_US",
|
|
33
|
-
mobileCardsInRow:
|
|
34
|
+
mobileCardsInRow: U,
|
|
34
35
|
mobileLayoutEnabled: !1,
|
|
35
36
|
orientation: "grid",
|
|
36
37
|
recommendedProducts: [],
|
|
37
38
|
sendProductRequestFlag: !1,
|
|
38
39
|
shuffleProducts: !1,
|
|
39
|
-
|
|
40
|
+
// With RRS on, a block that has not been synced yet must not claim an algorithm:
|
|
41
|
+
// that default is what reached buildCampaignUrl and baked a most-popular feed URL
|
|
42
|
+
// for a block the user never configured (SD-149916). Legacy blocks still get their real
|
|
43
|
+
// algorithm from the node-config sync or the save-time seed.
|
|
44
|
+
strategy: F().isFeatureEnabled("reusableRecommendationStrategy") ? "" : "mostPopular",
|
|
40
45
|
strategyId: "",
|
|
41
46
|
textTrimming: !0,
|
|
42
47
|
unresponsive: !1,
|
|
@@ -46,9 +51,9 @@ function w() {
|
|
|
46
51
|
priceHideIfSameAsDiscounted: !1
|
|
47
52
|
};
|
|
48
53
|
}
|
|
49
|
-
function
|
|
54
|
+
function w() {
|
|
50
55
|
return {
|
|
51
|
-
recommendationConfigs:
|
|
56
|
+
recommendationConfigs: P(),
|
|
52
57
|
recommendationProducts: [],
|
|
53
58
|
filterStatus: !1,
|
|
54
59
|
filterSelectionDrawerStatus: !1,
|
|
@@ -59,7 +64,7 @@ function C() {
|
|
|
59
64
|
filterSnapshot: null
|
|
60
65
|
};
|
|
61
66
|
}
|
|
62
|
-
const
|
|
67
|
+
const j = () => ({
|
|
63
68
|
recommendationCampaignUrls: {},
|
|
64
69
|
activePredictiveAlgorithms: [],
|
|
65
70
|
languages: {},
|
|
@@ -68,11 +73,14 @@ const z = () => ({
|
|
|
68
73
|
strategies: [],
|
|
69
74
|
strategiesLoading: !1,
|
|
70
75
|
strategyUrlTemplates: {},
|
|
76
|
+
strategiesFetched: !1,
|
|
77
|
+
strategiesSettled: !1,
|
|
71
78
|
blockStates: {},
|
|
72
79
|
currentRecommendationId: null,
|
|
80
|
+
strategyPanelOpen: !1,
|
|
73
81
|
configVersion: 0
|
|
74
|
-
}),
|
|
75
|
-
state: () =>
|
|
82
|
+
}), it = N("guidoRecommendationExtension", {
|
|
83
|
+
state: () => j(),
|
|
76
84
|
getters: {
|
|
77
85
|
// ====================================================================
|
|
78
86
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -82,7 +90,7 @@ const z = () => ({
|
|
|
82
90
|
* This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
|
|
83
91
|
*/
|
|
84
92
|
recommendationConfigs(t) {
|
|
85
|
-
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs :
|
|
93
|
+
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : P();
|
|
86
94
|
},
|
|
87
95
|
/**
|
|
88
96
|
* Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
|
|
@@ -137,12 +145,12 @@ const z = () => ({
|
|
|
137
145
|
return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
|
|
138
146
|
},
|
|
139
147
|
getActivePredictiveAlgorithms: (t) => {
|
|
140
|
-
const e =
|
|
141
|
-
return t.activePredictiveAlgorithms.filter((
|
|
142
|
-
r.push(...e.filter((s) => s.id ===
|
|
143
|
-
}), r.map((
|
|
144
|
-
text:
|
|
145
|
-
value:
|
|
148
|
+
const e = k(), r = [];
|
|
149
|
+
return t.activePredictiveAlgorithms.filter((i) => !B.includes(i)).forEach((i) => {
|
|
150
|
+
r.push(...e.filter((s) => s.id === i));
|
|
151
|
+
}), r.map((i) => ({
|
|
152
|
+
text: i.name,
|
|
153
|
+
value: i.key
|
|
146
154
|
}));
|
|
147
155
|
},
|
|
148
156
|
getLanguages: (t) => Object.entries(t.languages).map(([e, r]) => ({
|
|
@@ -156,7 +164,7 @@ const z = () => ({
|
|
|
156
164
|
getFilterList() {
|
|
157
165
|
return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
|
|
158
166
|
let e;
|
|
159
|
-
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` :
|
|
167
|
+
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : L.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
|
|
160
168
|
text: t.displayName,
|
|
161
169
|
value: e,
|
|
162
170
|
type: t.attributeType
|
|
@@ -178,7 +186,7 @@ const z = () => ({
|
|
|
178
186
|
setCurrentBlock(t) {
|
|
179
187
|
this.blockStates[t] || (this.blockStates = {
|
|
180
188
|
...this.blockStates,
|
|
181
|
-
[t]:
|
|
189
|
+
[t]: w()
|
|
182
190
|
}), this.currentRecommendationId = t;
|
|
183
191
|
},
|
|
184
192
|
/**
|
|
@@ -188,13 +196,13 @@ const z = () => ({
|
|
|
188
196
|
removeBlockState(t) {
|
|
189
197
|
const e = t.toString();
|
|
190
198
|
if (this.recommendationCampaignUrls[e]) {
|
|
191
|
-
const
|
|
192
|
-
delete
|
|
199
|
+
const i = { ...this.recommendationCampaignUrls };
|
|
200
|
+
delete i[e], this.recommendationCampaignUrls = i;
|
|
193
201
|
}
|
|
194
202
|
const r = { ...this.blockStates };
|
|
195
203
|
if (delete r[t], this.blockStates = r, this.currentRecommendationId === t) {
|
|
196
|
-
const
|
|
197
|
-
this.currentRecommendationId =
|
|
204
|
+
const i = Object.keys(this.blockStates).map(Number);
|
|
205
|
+
this.currentRecommendationId = i.length > 0 ? i[0] : null;
|
|
198
206
|
}
|
|
199
207
|
},
|
|
200
208
|
/**
|
|
@@ -210,10 +218,10 @@ const z = () => ({
|
|
|
210
218
|
[e]: o
|
|
211
219
|
};
|
|
212
220
|
}
|
|
213
|
-
const
|
|
214
|
-
|
|
221
|
+
const i = t.toString(), s = e.toString(), n = this.recommendationCampaignUrls[i];
|
|
222
|
+
n && (this.recommendationCampaignUrls = {
|
|
215
223
|
...this.recommendationCampaignUrls,
|
|
216
|
-
[s]:
|
|
224
|
+
[s]: n
|
|
217
225
|
});
|
|
218
226
|
},
|
|
219
227
|
/**
|
|
@@ -238,7 +246,7 @@ const z = () => ({
|
|
|
238
246
|
* `isInitialized`) alone.
|
|
239
247
|
*/
|
|
240
248
|
seedBlockUrlConfig(t, e) {
|
|
241
|
-
const r = (o, c) => o === "." || o === "," || o === " " ? o : c,
|
|
249
|
+
const r = (o, c) => o === "." || o === "," || o === " " ? o : c, i = {
|
|
242
250
|
name: e.currencyCode,
|
|
243
251
|
value: e.currencyCode,
|
|
244
252
|
symbol: e.currencyCode,
|
|
@@ -246,9 +254,9 @@ const z = () => ({
|
|
|
246
254
|
decimalCount: String(e.currencyDecimalCount),
|
|
247
255
|
decimalSeparator: r(e.currencyDecimalSeparator, ","),
|
|
248
256
|
thousandSeparator: r(e.currencyThousandSeparator, ".")
|
|
249
|
-
}, s = !this.blockStates[t],
|
|
250
|
-
|
|
251
|
-
...
|
|
257
|
+
}, s = !this.blockStates[t], n = s ? w() : this.blockStates[t];
|
|
258
|
+
n.recommendationConfigs = {
|
|
259
|
+
...n.recommendationConfigs,
|
|
252
260
|
strategy: e.strategy,
|
|
253
261
|
strategyId: e.strategyId,
|
|
254
262
|
language: e.language,
|
|
@@ -256,10 +264,10 @@ const z = () => ({
|
|
|
256
264
|
productIds: e.productIds,
|
|
257
265
|
filters: e.filters,
|
|
258
266
|
shuffleProducts: e.shuffleProducts,
|
|
259
|
-
currencySettings:
|
|
267
|
+
currencySettings: i
|
|
260
268
|
}, s && (this.blockStates = {
|
|
261
269
|
...this.blockStates,
|
|
262
|
-
[t]:
|
|
270
|
+
[t]: n
|
|
263
271
|
});
|
|
264
272
|
},
|
|
265
273
|
/**
|
|
@@ -278,18 +286,18 @@ const z = () => ({
|
|
|
278
286
|
...t.currencySettings || {}
|
|
279
287
|
}
|
|
280
288
|
};
|
|
281
|
-
const { triggerRefetch:
|
|
282
|
-
|
|
289
|
+
const { triggerRefetch: i = !0 } = e;
|
|
290
|
+
i && this.configVersion++;
|
|
283
291
|
},
|
|
284
292
|
/**
|
|
285
293
|
* Creates a filter with the first available attribute and operator pre-selected.
|
|
286
294
|
*/
|
|
287
295
|
createDefaultFilter(t, e) {
|
|
288
|
-
const [r] = this.getFilterList, [
|
|
296
|
+
const [r] = this.getFilterList, [i] = _(r == null ? void 0 : r.type);
|
|
289
297
|
return {
|
|
290
298
|
type: "standardFilter",
|
|
291
299
|
attribute: (r == null ? void 0 : r.value) ?? "",
|
|
292
|
-
operator: (
|
|
300
|
+
operator: (i == null ? void 0 : i.value) ?? "",
|
|
293
301
|
innerGroupOperator: "*",
|
|
294
302
|
outerGroupOperator: "*",
|
|
295
303
|
filterNumber: e,
|
|
@@ -345,33 +353,93 @@ const z = () => ({
|
|
|
345
353
|
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !1);
|
|
346
354
|
},
|
|
347
355
|
async fetchStrategies() {
|
|
348
|
-
if (
|
|
349
|
-
await S;
|
|
356
|
+
if (p && await p, this.strategiesFetched)
|
|
350
357
|
return;
|
|
351
|
-
|
|
352
|
-
|
|
358
|
+
const t = y;
|
|
359
|
+
p = (async () => {
|
|
353
360
|
this.strategiesLoading = !0;
|
|
354
361
|
try {
|
|
355
|
-
|
|
362
|
+
const e = await d.fetchRecommendationStrategies();
|
|
363
|
+
if (t !== y)
|
|
364
|
+
return;
|
|
365
|
+
this.strategies = e, this.strategiesFetched = !0;
|
|
356
366
|
} finally {
|
|
357
|
-
this.strategiesLoading = !1;
|
|
367
|
+
this.strategiesLoading = !1, t === y && (this.strategiesSettled = !0);
|
|
358
368
|
}
|
|
359
369
|
})();
|
|
360
370
|
try {
|
|
361
|
-
await
|
|
371
|
+
await p;
|
|
362
372
|
} finally {
|
|
363
|
-
|
|
373
|
+
p = null;
|
|
364
374
|
}
|
|
365
375
|
},
|
|
376
|
+
invalidateStrategies() {
|
|
377
|
+
this.strategiesFetched = !1, this.strategiesSettled = !1, y += 1;
|
|
378
|
+
},
|
|
379
|
+
/**
|
|
380
|
+
* Opens a Smart Recommender strategy page in a new tab and refreshes the list every time
|
|
381
|
+
* the user comes back. `visibilitychange` covers the tab case; `focus` covers the page
|
|
382
|
+
* landing in a separate window, where this document never goes hidden.
|
|
383
|
+
*
|
|
384
|
+
* Deliberately NOT one-shot: the strategy tab stays open, so a user can create a second
|
|
385
|
+
* strategy in it and come back again — a listener that disarmed on the first return would
|
|
386
|
+
* leave that one missing from the list. It disarms on the first return AFTER that tab is
|
|
387
|
+
* closed instead, so an ordinary alt-tab later in the session costs nothing. Armed only
|
|
388
|
+
* once the user actually opens a strategy page, so anyone who never does pays nothing.
|
|
389
|
+
*/
|
|
390
|
+
_armStrategyPageReturn(t) {
|
|
391
|
+
const e = window.open(t, "_blank");
|
|
392
|
+
e && (e.opener = null), l == null || l();
|
|
393
|
+
let r = !1;
|
|
394
|
+
const i = () => {
|
|
395
|
+
document.hidden || r || (e != null && e.closed && (l == null || l()), r = !0, this.invalidateStrategies(), this.fetchStrategies().then(() => this._refreshAssignedStrategyProducts()).catch(() => {
|
|
396
|
+
}).finally(() => {
|
|
397
|
+
r = !1;
|
|
398
|
+
}));
|
|
399
|
+
};
|
|
400
|
+
document.addEventListener("visibilitychange", i), window.addEventListener("focus", i), l = () => {
|
|
401
|
+
document.removeEventListener("visibilitychange", i), window.removeEventListener("focus", i), l = null;
|
|
402
|
+
};
|
|
403
|
+
},
|
|
404
|
+
/**
|
|
405
|
+
* Reloads the products of the block the user is on, so an edit made in the strategy tab
|
|
406
|
+
* lands on the canvas instead of waiting for the assign drawer to be reopened.
|
|
407
|
+
*
|
|
408
|
+
* Only the selected block: the canvas regeneration is driven off the active block's
|
|
409
|
+
* product array, so refreshing an unselected block would fetch without redrawing it.
|
|
410
|
+
*/
|
|
411
|
+
async _refreshAssignedStrategyProducts() {
|
|
412
|
+
var e;
|
|
413
|
+
const t = this.currentRecommendationId;
|
|
414
|
+
t === null || !((e = this.blockStates[t]) != null && e.recommendationConfigs.strategyId) || await this.fetchRecommendationProducts();
|
|
415
|
+
},
|
|
416
|
+
/** Lets the editor tear the return listeners down when it unmounts. */
|
|
417
|
+
disposeStrategyPageReturn() {
|
|
418
|
+
l == null || l();
|
|
419
|
+
},
|
|
420
|
+
/**
|
|
421
|
+
* Opens Smart Recommender's strategy creation page. Every return refreshes the list so the
|
|
422
|
+
* new strategy is offered; the user picks it themselves.
|
|
423
|
+
*/
|
|
424
|
+
openStrategyCreation() {
|
|
425
|
+
this._armStrategyPageReturn(D.RECOMMENDATION_STRATEGY_CREATE_PATH);
|
|
426
|
+
},
|
|
427
|
+
/**
|
|
428
|
+
* Opens the strategy's edit page. Every return refreshes the list so the block reflects the
|
|
429
|
+
* edited configuration.
|
|
430
|
+
*/
|
|
431
|
+
openStrategyEdit(t) {
|
|
432
|
+
this._armStrategyPageReturn(G(t));
|
|
433
|
+
},
|
|
366
434
|
async resolveStrategyUrlTemplate(t, e) {
|
|
367
|
-
const r = typeof t.updated_at == "string" ? t.updated_at : "",
|
|
435
|
+
const r = typeof t.updated_at == "string" ? t.updated_at : "", i = r ? `${t.strategy_id}:${r}:${e}` : "", s = i ? this.strategyUrlTemplates[i] : void 0;
|
|
368
436
|
if (s)
|
|
369
437
|
return s;
|
|
370
|
-
const { full_path:
|
|
371
|
-
return
|
|
438
|
+
const { full_path: n = "" } = await d.generateStrategyEndpoint(t, e) ?? {};
|
|
439
|
+
return i && n && (this.strategyUrlTemplates = {
|
|
372
440
|
...this.strategyUrlTemplates,
|
|
373
|
-
[
|
|
374
|
-
}),
|
|
441
|
+
[i]: n
|
|
442
|
+
}), n;
|
|
375
443
|
},
|
|
376
444
|
assignStrategy(t) {
|
|
377
445
|
this.patchCurrentBlockConfig({
|
|
@@ -380,50 +448,50 @@ const z = () => ({
|
|
|
380
448
|
});
|
|
381
449
|
},
|
|
382
450
|
removeStrategy() {
|
|
383
|
-
this.patchCurrentBlockConfig({ strategyId: "", size:
|
|
451
|
+
this.patchCurrentBlockConfig({ strategyId: "", size: x.size });
|
|
384
452
|
},
|
|
385
453
|
// ====================================================================
|
|
386
454
|
// Shared Data Fetching (fetched once, used by all blocks)
|
|
387
455
|
// ====================================================================
|
|
388
456
|
async fetchRecommendationCreateData() {
|
|
389
457
|
if (!this.activePredictiveAlgorithms.length) {
|
|
390
|
-
if (
|
|
391
|
-
await
|
|
458
|
+
if (h) {
|
|
459
|
+
await h;
|
|
392
460
|
return;
|
|
393
461
|
}
|
|
394
|
-
|
|
462
|
+
h = (async () => {
|
|
395
463
|
const {
|
|
396
464
|
activePredictiveAlgorithms: t,
|
|
397
465
|
languages: e,
|
|
398
466
|
currencies: r
|
|
399
|
-
} = await
|
|
467
|
+
} = await d.fetchRecommendationCreateData();
|
|
400
468
|
if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
|
|
401
|
-
const
|
|
402
|
-
|
|
469
|
+
const i = this.blockStates[this.currentRecommendationId];
|
|
470
|
+
i.filterStatus = !!i.recommendationConfigs.filters.length;
|
|
403
471
|
}
|
|
404
472
|
this.currencyList = r;
|
|
405
473
|
})();
|
|
406
474
|
try {
|
|
407
|
-
await
|
|
475
|
+
await h;
|
|
408
476
|
} finally {
|
|
409
|
-
|
|
477
|
+
h = null;
|
|
410
478
|
}
|
|
411
479
|
}
|
|
412
480
|
},
|
|
413
481
|
async fetchRecommendationFilters() {
|
|
414
482
|
if (!Object.keys(this.filterList).length) {
|
|
415
|
-
if (
|
|
416
|
-
await
|
|
483
|
+
if (g) {
|
|
484
|
+
await g;
|
|
417
485
|
return;
|
|
418
486
|
}
|
|
419
|
-
|
|
420
|
-
const t = await
|
|
487
|
+
g = (async () => {
|
|
488
|
+
const t = await d.fetchRecommendationFilters();
|
|
421
489
|
this.filterList = t;
|
|
422
490
|
})();
|
|
423
491
|
try {
|
|
424
|
-
await
|
|
492
|
+
await g;
|
|
425
493
|
} finally {
|
|
426
|
-
|
|
494
|
+
g = null;
|
|
427
495
|
}
|
|
428
496
|
}
|
|
429
497
|
},
|
|
@@ -438,41 +506,41 @@ const z = () => ({
|
|
|
438
506
|
deleteFilterGroup(t) {
|
|
439
507
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
440
508
|
return;
|
|
441
|
-
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((
|
|
442
|
-
e.recommendationConfigs.filters = r.map((
|
|
443
|
-
...
|
|
444
|
-
filterGroup: s.get(
|
|
509
|
+
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((n) => n.filterGroup !== t), i = [...new Set(r.map((n) => n.filterGroup))].sort((n, o) => n - o), s = new Map(i.map((n, o) => [n, o + 1]));
|
|
510
|
+
e.recommendationConfigs.filters = r.map((n) => ({
|
|
511
|
+
...n,
|
|
512
|
+
filterGroup: s.get(n.filterGroup) ?? n.filterGroup
|
|
445
513
|
}));
|
|
446
514
|
},
|
|
447
515
|
updateFilter(t) {
|
|
448
516
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
449
517
|
return;
|
|
450
|
-
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.findIndex((
|
|
518
|
+
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.findIndex((i) => i.filterNumber === t.filterNumber && i.filterGroup === t.filterGroup);
|
|
451
519
|
if (r !== -1) {
|
|
452
|
-
const
|
|
453
|
-
|
|
520
|
+
const i = [...e.recommendationConfigs.filters];
|
|
521
|
+
i[r] = {
|
|
454
522
|
...t,
|
|
455
|
-
isValid:
|
|
456
|
-
}, e.recommendationConfigs.filters =
|
|
523
|
+
isValid: T(t)
|
|
524
|
+
}, e.recommendationConfigs.filters = i;
|
|
457
525
|
}
|
|
458
526
|
},
|
|
459
527
|
deleteFilter(t) {
|
|
460
528
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
461
529
|
return;
|
|
462
|
-
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters].findIndex((
|
|
530
|
+
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters].findIndex((i) => i.filterNumber === t.filterNumber && i.filterGroup === t.filterGroup);
|
|
463
531
|
if (r !== -1) {
|
|
464
|
-
let
|
|
465
|
-
if (
|
|
466
|
-
let
|
|
467
|
-
|
|
532
|
+
let i = [...e.recommendationConfigs.filters];
|
|
533
|
+
if (i.splice(r, 1), i.some((n) => n.filterGroup === t.filterGroup)) {
|
|
534
|
+
let n = 1;
|
|
535
|
+
i = i.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: n++ } : o);
|
|
468
536
|
} else {
|
|
469
|
-
const
|
|
470
|
-
|
|
537
|
+
const n = [...new Set(i.map((c) => c.filterGroup))].sort((c, a) => c - a), o = new Map(n.map((c, a) => [c, a + 1]));
|
|
538
|
+
i = i.map((c) => ({
|
|
471
539
|
...c,
|
|
472
540
|
filterGroup: o.get(c.filterGroup) ?? c.filterGroup
|
|
473
541
|
}));
|
|
474
542
|
}
|
|
475
|
-
e.recommendationConfigs.filters =
|
|
543
|
+
e.recommendationConfigs.filters = i;
|
|
476
544
|
}
|
|
477
545
|
},
|
|
478
546
|
addFilter(t) {
|
|
@@ -480,8 +548,8 @@ const z = () => ({
|
|
|
480
548
|
return;
|
|
481
549
|
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters], s = r.filter(
|
|
482
550
|
(o) => o.filterGroup === t.filterGroup
|
|
483
|
-
).length + 1,
|
|
484
|
-
|
|
551
|
+
).length + 1, n = r.findLastIndex((o) => o.filterGroup === t.filterGroup);
|
|
552
|
+
n !== -1 ? r.splice(n + 1, 0, {
|
|
485
553
|
...t,
|
|
486
554
|
filterNumber: s
|
|
487
555
|
}) : r.push({
|
|
@@ -490,7 +558,7 @@ const z = () => ({
|
|
|
490
558
|
}), e.recommendationConfigs.filters = r;
|
|
491
559
|
},
|
|
492
560
|
generateFilterQuery() {
|
|
493
|
-
return
|
|
561
|
+
return v(this.recommendationConfigs.filters);
|
|
494
562
|
},
|
|
495
563
|
/**
|
|
496
564
|
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
@@ -498,83 +566,95 @@ const z = () => ({
|
|
|
498
566
|
* every block's recommendationConfigs across user edits.
|
|
499
567
|
*/
|
|
500
568
|
hasInvalidBlock() {
|
|
501
|
-
return Object.values(this.blockStates).some((t) => !
|
|
569
|
+
return Object.values(this.blockStates).some((t) => !V(t.recommendationConfigs, this));
|
|
570
|
+
},
|
|
571
|
+
/**
|
|
572
|
+
* Which required fields are missing across the design's blocks, so the save
|
|
573
|
+
* toaster can name the cause instead of always showing the generic message.
|
|
574
|
+
*/
|
|
575
|
+
invalidBlockFields() {
|
|
576
|
+
return Object.values(this.blockStates).flatMap((t) => z(t.recommendationConfigs, this));
|
|
502
577
|
},
|
|
503
578
|
// ====================================================================
|
|
504
579
|
// Per-Block Product Fetching
|
|
505
580
|
// ====================================================================
|
|
506
581
|
async fetchRecommendationProducts() {
|
|
507
582
|
if (!(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])) {
|
|
508
|
-
if (
|
|
509
|
-
await
|
|
583
|
+
if (S) {
|
|
584
|
+
await S;
|
|
510
585
|
return;
|
|
511
586
|
}
|
|
512
|
-
|
|
587
|
+
S = this._doFetchProducts();
|
|
513
588
|
try {
|
|
514
|
-
await
|
|
589
|
+
await S;
|
|
515
590
|
} finally {
|
|
516
|
-
|
|
591
|
+
S = null;
|
|
517
592
|
}
|
|
518
593
|
}
|
|
519
594
|
},
|
|
520
595
|
async _doFetchProducts() {
|
|
521
|
-
var
|
|
522
|
-
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e,
|
|
523
|
-
if (r.strategyId &&
|
|
596
|
+
var f;
|
|
597
|
+
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, i = F();
|
|
598
|
+
if (r.strategyId && i.isFeatureEnabled("reusableRecommendationStrategy")) {
|
|
524
599
|
await this._doFetchStrategyProducts(t);
|
|
525
600
|
return;
|
|
526
601
|
}
|
|
527
|
-
const s =
|
|
602
|
+
const s = parseInt(r.size) || 6;
|
|
603
|
+
if (!r.strategy) {
|
|
604
|
+
this._setBlockProducts(t, [], s);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
const n = r.filters.filter((u) => u.isValid), o = v(n), c = ((f = k().find((u) => u.key === r.strategy)) == null ? void 0 : f.path) || "", a = {
|
|
528
608
|
locale: r.language,
|
|
529
609
|
currency: r.currencySettings.value,
|
|
530
|
-
partnerName:
|
|
610
|
+
partnerName: i.partnerName,
|
|
531
611
|
size: r.size,
|
|
532
612
|
details: !0,
|
|
533
|
-
campaignId:
|
|
613
|
+
campaignId: i.variationId
|
|
534
614
|
};
|
|
535
|
-
r.strategy === "manualMerchandising" ? a.productId =
|
|
615
|
+
r.strategy === "manualMerchandising" ? a.productId = O(r.productIds) : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), o && (a.filter = o), r.shuffleProducts && (a.shuffle = !0), Object.assign(
|
|
536
616
|
a,
|
|
537
|
-
|
|
617
|
+
M(i.partnerName, r.strategy)
|
|
538
618
|
);
|
|
539
|
-
let
|
|
619
|
+
let m;
|
|
540
620
|
try {
|
|
541
|
-
|
|
621
|
+
m = await d.fetchRecommendationProducts(c, a);
|
|
542
622
|
} catch {
|
|
543
|
-
|
|
623
|
+
m = [];
|
|
544
624
|
}
|
|
545
|
-
this._setBlockProducts(t,
|
|
625
|
+
this._setBlockProducts(t, m, s);
|
|
546
626
|
},
|
|
547
627
|
async _doFetchStrategyProducts(t) {
|
|
548
|
-
const e = (
|
|
549
|
-
|
|
628
|
+
const e = (b.get(t) ?? 0) + 1;
|
|
629
|
+
b.set(t, e);
|
|
550
630
|
const { recommendationConfigs: r } = this.blockStates[t];
|
|
551
|
-
let
|
|
631
|
+
let i = [], s = parseInt(r.size) || 6;
|
|
552
632
|
try {
|
|
553
633
|
await this.fetchStrategies();
|
|
554
|
-
const
|
|
634
|
+
const n = this.strategies.find(
|
|
555
635
|
(o) => String(o.strategy_id) === r.strategyId
|
|
556
636
|
);
|
|
557
|
-
if (
|
|
558
|
-
s = parseInt(String(
|
|
559
|
-
const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(
|
|
560
|
-
|
|
637
|
+
if (n) {
|
|
638
|
+
s = parseInt(String(n.size ?? "")) || s;
|
|
639
|
+
const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(n, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), m = a.indexOf("?"), f = m === -1 ? a : a.slice(0, m), u = (m === -1 ? "" : a.slice(m + 1)).split("&").filter((R) => R && !R.startsWith("user_id=")), I = u.length ? `${f}?${u.join("&")}` : f;
|
|
640
|
+
I && (i = await d.fetchRecommendationProductsByUrl(I));
|
|
561
641
|
}
|
|
562
642
|
} catch {
|
|
563
|
-
|
|
643
|
+
i = [];
|
|
564
644
|
}
|
|
565
|
-
|
|
645
|
+
b.get(t) === e && this._setBlockProducts(t, i, s);
|
|
566
646
|
},
|
|
567
647
|
_setBlockProducts(t, e, r) {
|
|
568
648
|
if (!this.blockStates[t])
|
|
569
649
|
return;
|
|
570
|
-
const
|
|
650
|
+
const i = e.length > 0 ? e : C(r);
|
|
571
651
|
this.blockStates[t].recommendationProducts = [
|
|
572
|
-
...
|
|
573
|
-
...
|
|
652
|
+
...i.slice(0, r),
|
|
653
|
+
...C(Math.max(0, r - i.length))
|
|
574
654
|
];
|
|
575
655
|
}
|
|
576
656
|
}
|
|
577
657
|
});
|
|
578
658
|
export {
|
|
579
|
-
|
|
659
|
+
it as useRecommendationExtensionStore
|
|
580
660
|
};
|
|
@@ -1,34 +1,43 @@
|
|
|
1
|
-
const
|
|
1
|
+
const o = "strategy", u = [
|
|
2
2
|
{
|
|
3
3
|
key: "locale",
|
|
4
4
|
getValue: (e) => e.language,
|
|
5
5
|
getAvailableOptions: (e) => Object.keys(e.languages)
|
|
6
6
|
},
|
|
7
|
+
{
|
|
8
|
+
// A block feeds from either an assigned strategy (RRS) or an algorithm (legacy).
|
|
9
|
+
// Only a fresh RRS block has neither, and its feed URL would otherwise be built
|
|
10
|
+
// from an empty algorithm path.
|
|
11
|
+
key: o,
|
|
12
|
+
getValue: (e) => e.strategyId || e.strategy
|
|
13
|
+
},
|
|
7
14
|
{
|
|
8
15
|
key: "currency",
|
|
9
16
|
getValue: (e) => e.currencySettings.value,
|
|
10
17
|
getAvailableOptions: (e) => e.currencyList.map((n) => n.text),
|
|
11
18
|
canBeEmpty: !0
|
|
12
19
|
}
|
|
13
|
-
],
|
|
14
|
-
function c(e, n, i =
|
|
20
|
+
], l = "newsletter.recommendation-fill-required-fields", g = "newsletter.recommendation-assign-strategy";
|
|
21
|
+
function c(e, n, i = u) {
|
|
15
22
|
return i.filter((t) => {
|
|
16
|
-
var
|
|
23
|
+
var s;
|
|
17
24
|
if (t.condition && !t.condition(e))
|
|
18
25
|
return !1;
|
|
19
|
-
const
|
|
20
|
-
if (t.canBeEmpty && (
|
|
26
|
+
const a = (s = t.getAvailableOptions) == null ? void 0 : s.call(t, n);
|
|
27
|
+
if (t.canBeEmpty && (a == null ? void 0 : a.length) === 0)
|
|
21
28
|
return !1;
|
|
22
|
-
const
|
|
23
|
-
return
|
|
29
|
+
const r = t.getValue(e);
|
|
30
|
+
return r ? a !== void 0 && !a.includes(r) : !0;
|
|
24
31
|
}).map((t) => t.key);
|
|
25
32
|
}
|
|
26
|
-
function
|
|
33
|
+
function y(e, n) {
|
|
27
34
|
return c(e, n).length === 0;
|
|
28
35
|
}
|
|
29
36
|
export {
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
u as REQUIRED_RECOMMENDATION_FIELDS,
|
|
38
|
+
g as RecommendationAssignStrategyKey,
|
|
39
|
+
l as RecommendationRequiredFieldsKey,
|
|
40
|
+
o as STRATEGY_FIELD_KEY,
|
|
32
41
|
c as getInvalidFields,
|
|
33
|
-
|
|
42
|
+
y as isConfigValid
|
|
34
43
|
};
|