@useinsider/guido 3.18.2-beta.45f708c → 3.18.2-beta.4d2b065
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 +21 -3
- package/dist/@types/config/schemas.js +59 -51
- package/dist/components/Guido.vue.js +4 -4
- package/dist/components/Guido.vue2.js +72 -70
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +7 -9
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +51 -66
- package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js +18 -0
- package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue2.js +25 -0
- package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +40 -24
- package/dist/components/organisms/onboarding/OnboardingWrapper.vue2.js +28 -26
- package/dist/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue.js +21 -0
- package/dist/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue2.js +46 -0
- package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.js +3 -3
- package/dist/components/organisms/onboarding/RecommendationStrategyOnboarding.vue2.js +20 -21
- package/dist/composables/useCustomInterfaceAppearance.js +47 -53
- package/dist/composables/useHtmlValidator.js +79 -84
- package/dist/composables/useLegacyStrategyConversion.js +61 -0
- package/dist/composables/useRecommendation.js +35 -40
- package/dist/composables/useStripo.js +30 -30
- package/dist/enums/extensions/recommendationBlock.js +41 -39
- package/dist/extensions/Blocks/Recommendation/block.js +39 -43
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +20 -21
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +80 -84
- package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +94 -82
- package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +97 -96
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +144 -179
- package/dist/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js +42 -0
- package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +16 -26
- package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +12 -21
- package/dist/guido.css +1 -1
- package/dist/services/recommendationApi.js +46 -37
- package/dist/src/@types/config/schemas.d.ts +16 -0
- package/dist/src/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.d.ts +2 -0
- package/dist/src/components/organisms/onboarding/RecommendationLegacyStrategyOnboarding.vue.d.ts +2 -0
- package/dist/src/composables/useConfig.d.ts +4 -0
- package/dist/src/composables/useLegacyStrategyConversion.d.ts +3 -0
- package/dist/src/enums/extensions/recommendationBlock.d.ts +5 -3
- package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +0 -1
- package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +1 -1
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +0 -2
- package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +1 -8
- package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +6 -7
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +70 -76
- package/dist/src/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.d.ts +32 -0
- package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +0 -4
- package/dist/src/services/recommendationApi.d.ts +2 -1
- package/dist/src/stores/config.d.ts +322 -0
- package/dist/src/stores/onboarding.d.ts +421 -0
- package/dist/static/assets/icons/filled-arrow-rising.svg.js +5 -0
- package/dist/static/assets/icons/line-info.svg.js +5 -0
- package/dist/static/styles/components/recommendation-strategy.css.js +74 -39
- package/dist/stores/config.js +74 -60
- package/dist/stores/onboarding.js +6 -1
- package/dist/utils/templatePreparation.js +55 -55
- package/package.json +5 -5
- package/dist/extensions/Blocks/Recommendation/utils/strategyCommit.js +0 -24
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyCommit.d.ts +0 -14
- package/dist/static/styles/components/skeleton.css.js +0 -23
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as
|
|
2
|
-
import { useRecommendationApi as
|
|
3
|
-
import { useConfigStore as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as R, getOperatorOptions as F, PriceAttributes as P } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { useRecommendationApi as D } from "../../../../services/recommendationApi.js";
|
|
3
|
+
import { useConfigStore as k } from "../../../../stores/config.js";
|
|
4
4
|
import { defineStore as L } 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 {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
import { DEFAULT_MOBILE_CARDS_IN_ROW as U, DEFAULT_CARDS_IN_ROW as _ } from "../constants/layout.js";
|
|
7
|
+
import { CURRENT_CONFIG_VERSION as y, DEFAULT_NODE_CONFIG as N, EXCLUDED_ALGORITHM_IDS as M } from "../constants/defaultConfig.js";
|
|
8
|
+
import { getDefaultProducts as C } from "../templates/utils.js";
|
|
9
|
+
import { generateCompleteFilterQuery as v } from "../utils/filterUtil.js";
|
|
10
|
+
import { isLegacyStrategyConfig as x } from "../utils/legacyStrategyMigration.js";
|
|
11
|
+
import { getPartnerRecommendationParams as B } from "../utils/partnerCustomizations.js";
|
|
12
|
+
import { sanitizeProductIds as z } from "../utils/productIds.js";
|
|
13
|
+
import { isFilterValid as A } from "../validation/filterSchema.js";
|
|
14
|
+
import { isConfigValid as O } from "../validation/requiredFields.js";
|
|
15
|
+
const m = D();
|
|
16
|
+
let f = null, g = null, h = null, S = null;
|
|
17
|
+
const p = /* @__PURE__ */ new Map();
|
|
18
18
|
function G() {
|
|
19
19
|
return {
|
|
20
|
-
cardsInRow:
|
|
20
|
+
cardsInRow: _,
|
|
21
21
|
currencySettings: {
|
|
22
22
|
name: "USD",
|
|
23
23
|
value: "USD",
|
|
@@ -31,18 +31,15 @@ function G() {
|
|
|
31
31
|
productIds: [],
|
|
32
32
|
id: 1,
|
|
33
33
|
language: "en_US",
|
|
34
|
-
mobileCardsInRow:
|
|
34
|
+
mobileCardsInRow: U,
|
|
35
35
|
mobileLayoutEnabled: !1,
|
|
36
36
|
orientation: "grid",
|
|
37
37
|
recommendedProducts: [],
|
|
38
38
|
sendProductRequestFlag: !1,
|
|
39
39
|
shuffleProducts: !1,
|
|
40
|
-
|
|
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: P().isFeatureEnabled("reusableRecommendationStrategy") ? "" : "mostPopular",
|
|
40
|
+
strategy: "mostPopular",
|
|
45
41
|
strategyId: "",
|
|
42
|
+
nodeConfigVersion: y,
|
|
46
43
|
textTrimming: !0,
|
|
47
44
|
unresponsive: !1,
|
|
48
45
|
size: "6",
|
|
@@ -59,13 +56,15 @@ function w() {
|
|
|
59
56
|
filterSelectionDrawerStatus: !1,
|
|
60
57
|
assignStrategyDrawerStatus: !1,
|
|
61
58
|
removeStrategyModalStatus: !1,
|
|
59
|
+
legacyStrategyUpdatedModalStatus: !1,
|
|
62
60
|
filterGroup: 1,
|
|
63
61
|
isInitialized: !1,
|
|
64
62
|
filterSnapshot: null,
|
|
65
|
-
syncedConfigFingerprint: null
|
|
63
|
+
syncedConfigFingerprint: null,
|
|
64
|
+
legacyConversionLoading: !1
|
|
66
65
|
};
|
|
67
66
|
}
|
|
68
|
-
const
|
|
67
|
+
const E = () => ({
|
|
69
68
|
recommendationCampaignUrls: {},
|
|
70
69
|
activePredictiveAlgorithms: [],
|
|
71
70
|
languages: {},
|
|
@@ -74,14 +73,11 @@ const $ = () => ({
|
|
|
74
73
|
strategies: [],
|
|
75
74
|
strategiesLoading: !1,
|
|
76
75
|
strategyUrlTemplates: {},
|
|
77
|
-
strategiesFetched: !1,
|
|
78
|
-
strategiesSettled: !1,
|
|
79
76
|
blockStates: {},
|
|
80
77
|
currentRecommendationId: null,
|
|
81
|
-
strategyPanelOpen: !1,
|
|
82
78
|
configVersion: 0
|
|
83
|
-
}),
|
|
84
|
-
state: () =>
|
|
79
|
+
}), et = L("guidoRecommendationExtension", {
|
|
80
|
+
state: () => E(),
|
|
85
81
|
getters: {
|
|
86
82
|
// ====================================================================
|
|
87
83
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -111,6 +107,15 @@ const $ = () => ({
|
|
|
111
107
|
removeStrategyModalStatus(t) {
|
|
112
108
|
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].removeStrategyModalStatus : !1;
|
|
113
109
|
},
|
|
110
|
+
isLegacyStrategyBlock() {
|
|
111
|
+
return k().isFeatureEnabled("reusableRecommendationStrategy") && x(this.recommendationConfigs);
|
|
112
|
+
},
|
|
113
|
+
legacyConversionLoading(t) {
|
|
114
|
+
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].legacyConversionLoading : !1;
|
|
115
|
+
},
|
|
116
|
+
legacyStrategyUpdatedModalStatus(t) {
|
|
117
|
+
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].legacyStrategyUpdatedModalStatus : !1;
|
|
118
|
+
},
|
|
114
119
|
assignedStrategy(t) {
|
|
115
120
|
const { strategyId: e } = this.recommendationConfigs;
|
|
116
121
|
return e ? t.strategies.find((r) => String(r.strategy_id) === e) ?? null : null;
|
|
@@ -146,7 +151,7 @@ const $ = () => ({
|
|
|
146
151
|
return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
|
|
147
152
|
},
|
|
148
153
|
getActivePredictiveAlgorithms: (t) => {
|
|
149
|
-
const e =
|
|
154
|
+
const e = R(), r = [];
|
|
150
155
|
return t.activePredictiveAlgorithms.filter((n) => !M.includes(n)).forEach((n) => {
|
|
151
156
|
r.push(...e.filter((s) => s.id === n));
|
|
152
157
|
}), r.map((n) => ({
|
|
@@ -165,7 +170,7 @@ const $ = () => ({
|
|
|
165
170
|
getFilterList() {
|
|
166
171
|
return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
|
|
167
172
|
let e;
|
|
168
|
-
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` :
|
|
173
|
+
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : P.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
|
|
169
174
|
text: t.displayName,
|
|
170
175
|
value: e,
|
|
171
176
|
type: t.attributeType
|
|
@@ -247,7 +252,7 @@ const $ = () => ({
|
|
|
247
252
|
* `isInitialized`) alone.
|
|
248
253
|
*/
|
|
249
254
|
seedBlockUrlConfig(t, e) {
|
|
250
|
-
const r = (o,
|
|
255
|
+
const r = (o, c) => o === "." || o === "," || o === " " ? o : c, n = {
|
|
251
256
|
name: e.currencyCode,
|
|
252
257
|
value: e.currencyCode,
|
|
253
258
|
symbol: e.currencySymbol,
|
|
@@ -294,7 +299,7 @@ const $ = () => ({
|
|
|
294
299
|
* Creates a filter with the first available attribute and operator pre-selected.
|
|
295
300
|
*/
|
|
296
301
|
createDefaultFilter(t, e) {
|
|
297
|
-
const [r] = this.getFilterList, [n] =
|
|
302
|
+
const [r] = this.getFilterList, [n] = F(r == null ? void 0 : r.type);
|
|
298
303
|
return {
|
|
299
304
|
type: "standardFilter",
|
|
300
305
|
attribute: (r == null ? void 0 : r.value) ?? "",
|
|
@@ -347,6 +352,12 @@ const $ = () => ({
|
|
|
347
352
|
closeAssignStrategyDrawer() {
|
|
348
353
|
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].assignStrategyDrawerStatus = !1);
|
|
349
354
|
},
|
|
355
|
+
openLegacyStrategyUpdatedModal() {
|
|
356
|
+
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].legacyStrategyUpdatedModalStatus = !0);
|
|
357
|
+
},
|
|
358
|
+
closeLegacyStrategyUpdatedModal() {
|
|
359
|
+
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].legacyStrategyUpdatedModalStatus = !1);
|
|
360
|
+
},
|
|
350
361
|
openRemoveStrategyModal() {
|
|
351
362
|
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !0);
|
|
352
363
|
},
|
|
@@ -354,97 +365,29 @@ const $ = () => ({
|
|
|
354
365
|
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !1);
|
|
355
366
|
},
|
|
356
367
|
async fetchStrategies() {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
await R;
|
|
360
|
-
} catch {
|
|
361
|
-
}
|
|
362
|
-
if (this.strategiesFetched)
|
|
368
|
+
if (S) {
|
|
369
|
+
await S;
|
|
363
370
|
return;
|
|
364
|
-
|
|
371
|
+
}
|
|
372
|
+
S = (async () => {
|
|
365
373
|
this.strategiesLoading = !0;
|
|
366
374
|
try {
|
|
367
|
-
|
|
368
|
-
if (t !== b)
|
|
369
|
-
return;
|
|
370
|
-
this.strategies = r, this.strategiesFetched = !0;
|
|
375
|
+
this.strategies = await m.fetchRecommendationStrategies();
|
|
371
376
|
} finally {
|
|
372
|
-
this.strategiesLoading = !1
|
|
377
|
+
this.strategiesLoading = !1;
|
|
373
378
|
}
|
|
374
379
|
})();
|
|
375
|
-
R = e;
|
|
376
380
|
try {
|
|
377
|
-
await
|
|
381
|
+
await S;
|
|
378
382
|
} finally {
|
|
379
|
-
|
|
383
|
+
S = null;
|
|
380
384
|
}
|
|
381
385
|
},
|
|
382
|
-
invalidateStrategies() {
|
|
383
|
-
this.strategiesFetched = !1, this.strategiesSettled = !1, b += 1;
|
|
384
|
-
},
|
|
385
|
-
/**
|
|
386
|
-
* Opens a Smart Recommender strategy page in a new tab and refreshes the list every time
|
|
387
|
-
* the user comes back. `visibilitychange` only: a `focus` listener would also fire when
|
|
388
|
-
* focus merely returns from the Stripo canvas iframe to the panel, refetching and
|
|
389
|
-
* regenerating the canvas while the user never left the editor (SD-149916).
|
|
390
|
-
*
|
|
391
|
-
* Deliberately NOT one-shot: the strategy tab stays open, so a user can create a second
|
|
392
|
-
* strategy in it and come back again — a listener that disarmed on the first return would
|
|
393
|
-
* leave that one missing from the list. It disarms on the first return AFTER that tab is
|
|
394
|
-
* closed instead, so an ordinary alt-tab later in the session costs nothing. Armed only
|
|
395
|
-
* once the user actually opens a strategy page, so anyone who never does pays nothing.
|
|
396
|
-
*/
|
|
397
|
-
_armStrategyPageReturn(t) {
|
|
398
|
-
const e = window.open(t, "_blank");
|
|
399
|
-
if (!e)
|
|
400
|
-
return;
|
|
401
|
-
e.opener = null, l == null || l();
|
|
402
|
-
let r = !1;
|
|
403
|
-
const n = () => {
|
|
404
|
-
document.hidden || r || (e != null && e.closed && (l == null || l()), r = !0, this.invalidateStrategies(), this.fetchStrategies().then(() => this._refreshAssignedStrategyProducts()).catch(() => {
|
|
405
|
-
}).finally(() => {
|
|
406
|
-
r = !1;
|
|
407
|
-
}));
|
|
408
|
-
};
|
|
409
|
-
document.addEventListener("visibilitychange", n), l = () => {
|
|
410
|
-
document.removeEventListener("visibilitychange", n), l = null;
|
|
411
|
-
};
|
|
412
|
-
},
|
|
413
|
-
/**
|
|
414
|
-
* Reloads the products of the block the user is on, so an edit made in the strategy tab
|
|
415
|
-
* lands on the canvas instead of waiting for the assign drawer to be reopened.
|
|
416
|
-
*
|
|
417
|
-
* Only the selected block: the canvas regeneration is driven off the active block's
|
|
418
|
-
* product array, so refreshing an unselected block would fetch without redrawing it.
|
|
419
|
-
*/
|
|
420
|
-
async _refreshAssignedStrategyProducts() {
|
|
421
|
-
var e;
|
|
422
|
-
const t = this.currentRecommendationId;
|
|
423
|
-
t === null || !((e = this.blockStates[t]) != null && e.recommendationConfigs.strategyId) || await this.fetchRecommendationProducts();
|
|
424
|
-
},
|
|
425
|
-
/** Lets the editor tear the return listeners down when it unmounts. */
|
|
426
|
-
disposeStrategyPageReturn() {
|
|
427
|
-
l == null || l();
|
|
428
|
-
},
|
|
429
|
-
/**
|
|
430
|
-
* Opens Smart Recommender's strategy creation page. Every return refreshes the list so the
|
|
431
|
-
* new strategy is offered; the user picks it themselves.
|
|
432
|
-
*/
|
|
433
|
-
openStrategyCreation() {
|
|
434
|
-
this._armStrategyPageReturn(_.RECOMMENDATION_STRATEGY_CREATE_PATH);
|
|
435
|
-
},
|
|
436
|
-
/**
|
|
437
|
-
* Opens the strategy's edit page. Every return refreshes the list so the block reflects the
|
|
438
|
-
* edited configuration.
|
|
439
|
-
*/
|
|
440
|
-
openStrategyEdit(t) {
|
|
441
|
-
this._armStrategyPageReturn(D(t));
|
|
442
|
-
},
|
|
443
386
|
async resolveStrategyUrlTemplate(t, e) {
|
|
444
387
|
const r = typeof t.updated_at == "string" ? t.updated_at : "", n = r ? `${t.strategy_id}:${r}:${e}` : "", s = n ? this.strategyUrlTemplates[n] : void 0;
|
|
445
388
|
if (s)
|
|
446
389
|
return s;
|
|
447
|
-
const { full_path: i = "" } = await
|
|
390
|
+
const { full_path: i = "" } = await m.generateStrategyEndpoint(t, e) ?? {};
|
|
448
391
|
return n && i && (this.strategyUrlTemplates = {
|
|
449
392
|
...this.strategyUrlTemplates,
|
|
450
393
|
[n]: i
|
|
@@ -456,11 +399,43 @@ const $ = () => ({
|
|
|
456
399
|
...t.size !== void 0 ? { size: String(t.size) } : {}
|
|
457
400
|
});
|
|
458
401
|
},
|
|
402
|
+
async convertLegacyStrategy(t, e = { scope: "campaign" }) {
|
|
403
|
+
const r = this.currentRecommendationId;
|
|
404
|
+
if (r === null || !this.blockStates[r])
|
|
405
|
+
throw new Error("[Guido] convertLegacyStrategy called without an active block");
|
|
406
|
+
this.blockStates[r].legacyConversionLoading = !0;
|
|
407
|
+
try {
|
|
408
|
+
const n = await m.migrateLegacyStrategy(t, e);
|
|
409
|
+
try {
|
|
410
|
+
await this.fetchStrategies();
|
|
411
|
+
} catch (o) {
|
|
412
|
+
console.error("[Guido] strategy listing refresh after conversion failed", o);
|
|
413
|
+
}
|
|
414
|
+
const s = this.strategies.find((o) => String(o.strategy_id) === n), i = this.blockStates[r];
|
|
415
|
+
return i && (i.recommendationConfigs = {
|
|
416
|
+
...i.recommendationConfigs,
|
|
417
|
+
strategyId: n,
|
|
418
|
+
nodeConfigVersion: y,
|
|
419
|
+
...(s == null ? void 0 : s.size) !== void 0 ? { size: String(s.size) } : {}
|
|
420
|
+
}), this.currentRecommendationId === r && this.configVersion++, n;
|
|
421
|
+
} finally {
|
|
422
|
+
this.blockStates[r] && (this.blockStates[r].legacyConversionLoading = !1);
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
/**
|
|
426
|
+
* Undoes the config half of a conversion whose document write never landed, so the
|
|
427
|
+
* panel and the drawer fall back to "Legacy Strategy" instead of showing an assignment
|
|
428
|
+
* the document never received.
|
|
429
|
+
*/
|
|
430
|
+
revertLegacyConversion(t, e) {
|
|
431
|
+
const r = this.blockStates[t];
|
|
432
|
+
r && (r.recommendationConfigs = { ...r.recommendationConfigs, ...e }, this.currentRecommendationId === t && this.configVersion++);
|
|
433
|
+
},
|
|
459
434
|
removeStrategy() {
|
|
460
435
|
this.patchCurrentBlockConfig({
|
|
461
436
|
strategyId: "",
|
|
462
|
-
|
|
463
|
-
|
|
437
|
+
size: N.size,
|
|
438
|
+
nodeConfigVersion: y
|
|
464
439
|
});
|
|
465
440
|
},
|
|
466
441
|
// ====================================================================
|
|
@@ -468,16 +443,16 @@ const $ = () => ({
|
|
|
468
443
|
// ====================================================================
|
|
469
444
|
async fetchRecommendationCreateData() {
|
|
470
445
|
if (!this.activePredictiveAlgorithms.length) {
|
|
471
|
-
if (
|
|
472
|
-
await
|
|
446
|
+
if (f) {
|
|
447
|
+
await f;
|
|
473
448
|
return;
|
|
474
449
|
}
|
|
475
|
-
|
|
450
|
+
f = (async () => {
|
|
476
451
|
const {
|
|
477
452
|
activePredictiveAlgorithms: t,
|
|
478
453
|
languages: e,
|
|
479
454
|
currencies: r
|
|
480
|
-
} = await
|
|
455
|
+
} = await m.fetchRecommendationCreateData();
|
|
481
456
|
if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
|
|
482
457
|
const n = this.blockStates[this.currentRecommendationId];
|
|
483
458
|
n.filterStatus = !!n.recommendationConfigs.filters.length;
|
|
@@ -485,26 +460,26 @@ const $ = () => ({
|
|
|
485
460
|
this.currencyList = r;
|
|
486
461
|
})();
|
|
487
462
|
try {
|
|
488
|
-
await
|
|
463
|
+
await f;
|
|
489
464
|
} finally {
|
|
490
|
-
|
|
465
|
+
f = null;
|
|
491
466
|
}
|
|
492
467
|
}
|
|
493
468
|
},
|
|
494
469
|
async fetchRecommendationFilters() {
|
|
495
470
|
if (!Object.keys(this.filterList).length) {
|
|
496
|
-
if (
|
|
497
|
-
await
|
|
471
|
+
if (g) {
|
|
472
|
+
await g;
|
|
498
473
|
return;
|
|
499
474
|
}
|
|
500
|
-
|
|
501
|
-
const t = await
|
|
475
|
+
g = (async () => {
|
|
476
|
+
const t = await m.fetchRecommendationFilters();
|
|
502
477
|
this.filterList = t;
|
|
503
478
|
})();
|
|
504
479
|
try {
|
|
505
|
-
await
|
|
480
|
+
await g;
|
|
506
481
|
} finally {
|
|
507
|
-
|
|
482
|
+
g = null;
|
|
508
483
|
}
|
|
509
484
|
}
|
|
510
485
|
},
|
|
@@ -533,7 +508,7 @@ const $ = () => ({
|
|
|
533
508
|
const n = [...e.recommendationConfigs.filters];
|
|
534
509
|
n[r] = {
|
|
535
510
|
...t,
|
|
536
|
-
isValid:
|
|
511
|
+
isValid: A(t)
|
|
537
512
|
}, e.recommendationConfigs.filters = n;
|
|
538
513
|
}
|
|
539
514
|
},
|
|
@@ -547,10 +522,10 @@ const $ = () => ({
|
|
|
547
522
|
let i = 1;
|
|
548
523
|
n = n.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: i++ } : o);
|
|
549
524
|
} else {
|
|
550
|
-
const i = [...new Set(n.map((
|
|
551
|
-
n = n.map((
|
|
552
|
-
...
|
|
553
|
-
filterGroup: o.get(
|
|
525
|
+
const i = [...new Set(n.map((c) => c.filterGroup))].sort((c, a) => c - a), o = new Map(i.map((c, a) => [c, a + 1]));
|
|
526
|
+
n = n.map((c) => ({
|
|
527
|
+
...c,
|
|
528
|
+
filterGroup: o.get(c.filterGroup) ?? c.filterGroup
|
|
554
529
|
}));
|
|
555
530
|
}
|
|
556
531
|
e.recommendationConfigs.filters = n;
|
|
@@ -571,7 +546,7 @@ const $ = () => ({
|
|
|
571
546
|
}), e.recommendationConfigs.filters = r;
|
|
572
547
|
},
|
|
573
548
|
generateFilterQuery() {
|
|
574
|
-
return
|
|
549
|
+
return v(this.recommendationConfigs.filters);
|
|
575
550
|
},
|
|
576
551
|
/**
|
|
577
552
|
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
@@ -579,52 +554,33 @@ const $ = () => ({
|
|
|
579
554
|
* every block's recommendationConfigs across user edits.
|
|
580
555
|
*/
|
|
581
556
|
hasInvalidBlock() {
|
|
582
|
-
return Object.values(this.blockStates).some((t) => !
|
|
583
|
-
},
|
|
584
|
-
/**
|
|
585
|
-
* Which required fields are missing across the design's blocks, so the save
|
|
586
|
-
* toaster can name the cause instead of always showing the generic message.
|
|
587
|
-
*/
|
|
588
|
-
invalidBlockFields() {
|
|
589
|
-
return Object.values(this.blockStates).flatMap((t) => V(t.recommendationConfigs, this));
|
|
557
|
+
return Object.values(this.blockStates).some((t) => !O(t.recommendationConfigs, this));
|
|
590
558
|
},
|
|
591
559
|
// ====================================================================
|
|
592
560
|
// Per-Block Product Fetching
|
|
593
561
|
// ====================================================================
|
|
594
562
|
async fetchRecommendationProducts() {
|
|
595
|
-
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
I = t, y = this._doFetchProducts();
|
|
607
|
-
try {
|
|
608
|
-
await y;
|
|
609
|
-
} finally {
|
|
610
|
-
I === t && (y = null, I = "");
|
|
563
|
+
if (!(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])) {
|
|
564
|
+
if (h) {
|
|
565
|
+
await h;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
h = this._doFetchProducts();
|
|
569
|
+
try {
|
|
570
|
+
await h;
|
|
571
|
+
} finally {
|
|
572
|
+
h = null;
|
|
573
|
+
}
|
|
611
574
|
}
|
|
612
575
|
},
|
|
613
576
|
async _doFetchProducts() {
|
|
614
|
-
var
|
|
615
|
-
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n =
|
|
577
|
+
var d;
|
|
578
|
+
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = k();
|
|
616
579
|
if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
|
|
617
580
|
await this._doFetchStrategyProducts(t);
|
|
618
581
|
return;
|
|
619
582
|
}
|
|
620
|
-
const s = (
|
|
621
|
-
h.set(t, s);
|
|
622
|
-
const i = parseInt(r.size) || 6;
|
|
623
|
-
if (!r.strategy) {
|
|
624
|
-
this._setBlockProducts(t, [], i);
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
const o = r.filters.filter((d) => d.isValid), a = F(o), u = ((g = C().find((d) => d.key === r.strategy)) == null ? void 0 : g.path) || "", c = {
|
|
583
|
+
const s = r.filters.filter((u) => u.isValid), i = v(s), o = ((d = R().find((u) => u.key === r.strategy)) == null ? void 0 : d.path) || "", c = parseInt(r.size) || 6, a = {
|
|
628
584
|
locale: r.language,
|
|
629
585
|
currency: r.currencySettings.value,
|
|
630
586
|
partnerName: n.partnerName,
|
|
@@ -632,21 +588,30 @@ const $ = () => ({
|
|
|
632
588
|
details: !0,
|
|
633
589
|
campaignId: n.variationId
|
|
634
590
|
};
|
|
635
|
-
r.strategy === "manualMerchandising" ?
|
|
636
|
-
|
|
637
|
-
|
|
591
|
+
r.strategy === "manualMerchandising" ? a.productId = z(r.productIds) : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), i && (a.filter = i), r.shuffleProducts && (a.shuffle = !0), Object.assign(
|
|
592
|
+
a,
|
|
593
|
+
B(n.partnerName, r.strategy)
|
|
638
594
|
);
|
|
639
|
-
let
|
|
595
|
+
let l;
|
|
640
596
|
try {
|
|
641
|
-
|
|
597
|
+
l = await m.fetchRecommendationProducts(o, a);
|
|
642
598
|
} catch {
|
|
643
|
-
|
|
599
|
+
l = [];
|
|
644
600
|
}
|
|
645
|
-
|
|
601
|
+
this._setBlockProducts(t, l, c);
|
|
602
|
+
},
|
|
603
|
+
/**
|
|
604
|
+
* Block-scoped counterpart of `fetchRecommendationProducts`, which only ever serves the
|
|
605
|
+
* selected block. The legacy conversion must refresh the products of the block that
|
|
606
|
+
* started it even after the user selected another one.
|
|
607
|
+
*/
|
|
608
|
+
async fetchStrategyProductsForBlock(t) {
|
|
609
|
+
var e;
|
|
610
|
+
(e = this.blockStates[t]) != null && e.recommendationConfigs.strategyId && await this._doFetchStrategyProducts(t);
|
|
646
611
|
},
|
|
647
612
|
async _doFetchStrategyProducts(t) {
|
|
648
|
-
const e = (
|
|
649
|
-
|
|
613
|
+
const e = (p.get(t) ?? 0) + 1;
|
|
614
|
+
p.set(t, e);
|
|
650
615
|
const { recommendationConfigs: r } = this.blockStates[t];
|
|
651
616
|
let n = [], s = parseInt(r.size) || 6;
|
|
652
617
|
try {
|
|
@@ -656,25 +621,25 @@ const $ = () => ({
|
|
|
656
621
|
);
|
|
657
622
|
if (i) {
|
|
658
623
|
s = parseInt(String(i.size ?? "")) || s;
|
|
659
|
-
const o = r.currencySettings.value,
|
|
660
|
-
|
|
624
|
+
const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), l = a.indexOf("?"), d = l === -1 ? a : a.slice(0, l), u = (l === -1 ? "" : a.slice(l + 1)).split("&").filter((I) => I && !I.startsWith("user_id=")), b = u.length ? `${d}?${u.join("&")}` : d;
|
|
625
|
+
b && (n = await m.fetchRecommendationProductsByUrl(b));
|
|
661
626
|
}
|
|
662
627
|
} catch {
|
|
663
628
|
n = [];
|
|
664
629
|
}
|
|
665
|
-
|
|
630
|
+
p.get(t) === e && this._setBlockProducts(t, n, s);
|
|
666
631
|
},
|
|
667
632
|
_setBlockProducts(t, e, r) {
|
|
668
633
|
if (!this.blockStates[t])
|
|
669
634
|
return;
|
|
670
|
-
const n = e.length > 0 ? e :
|
|
635
|
+
const n = e.length > 0 ? e : C(r);
|
|
671
636
|
this.blockStates[t].recommendationProducts = [
|
|
672
637
|
...n.slice(0, r),
|
|
673
|
-
...
|
|
638
|
+
...C(Math.max(0, r - n.length))
|
|
674
639
|
];
|
|
675
640
|
}
|
|
676
641
|
}
|
|
677
642
|
});
|
|
678
643
|
export {
|
|
679
|
-
|
|
644
|
+
et as useRecommendationExtensionStore
|
|
680
645
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import "../constants/selectors.js";
|
|
2
|
+
import { CURRENT_CONFIG_VERSION as m } from "../constants/defaultConfig.js";
|
|
3
|
+
import { sanitizeProductIds as p } from "./productIds.js";
|
|
4
|
+
const d = "manualMerchandising";
|
|
5
|
+
function N({ strategyId: e, nodeConfigVersion: t }) {
|
|
6
|
+
return !e && t < m;
|
|
7
|
+
}
|
|
8
|
+
const o = (e) => {
|
|
9
|
+
const t = String(e ?? "").trim();
|
|
10
|
+
return /^[1-9]\d*$/.test(t) ? t : null;
|
|
11
|
+
};
|
|
12
|
+
function f({ campaignId: e, templateLibraryId: t }) {
|
|
13
|
+
if (o(e))
|
|
14
|
+
return { scope: "campaign" };
|
|
15
|
+
const n = o(t);
|
|
16
|
+
return n ? { scope: "template", templateId: n } : { scope: "campaign" };
|
|
17
|
+
}
|
|
18
|
+
function y({
|
|
19
|
+
blockId: e,
|
|
20
|
+
url: t,
|
|
21
|
+
campaignId: n,
|
|
22
|
+
variationId: a,
|
|
23
|
+
strategy: c,
|
|
24
|
+
productIds: s,
|
|
25
|
+
target: r
|
|
26
|
+
}) {
|
|
27
|
+
const i = c === d ? p(s).split(",").filter(Boolean) : [];
|
|
28
|
+
return {
|
|
29
|
+
...r.scope === "template" ? { templateId: Number.parseInt(r.templateId) } : {
|
|
30
|
+
campaignId: Number.parseInt(n) || 0,
|
|
31
|
+
variationId: Number.parseInt(a) || 0
|
|
32
|
+
},
|
|
33
|
+
blockId: String(e),
|
|
34
|
+
url: t,
|
|
35
|
+
...i.length ? { productIds: i } : {}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
y as buildLegacyMigrationPayload,
|
|
40
|
+
N as isLegacyStrategyConfig,
|
|
41
|
+
f as resolveMigrationTarget
|
|
42
|
+
};
|
|
@@ -1,32 +1,22 @@
|
|
|
1
|
-
import { ModificationDescription as
|
|
2
|
-
import { RECOMMENDATION_ID_ATTR as
|
|
3
|
-
import { isPartnerManagedBlock as
|
|
4
|
-
import { RecommendationConfigService as
|
|
5
|
-
let
|
|
6
|
-
function
|
|
7
|
-
|
|
1
|
+
import { ModificationDescription as f } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
|
+
import { RECOMMENDATION_ID_ATTR as m } from "../constants/selectors.js";
|
|
3
|
+
import { isPartnerManagedBlock as l, updateProductContentInPlace as a, regenerateProductRowsWithStyles as d } from "../controls/main/utils.js";
|
|
4
|
+
import { RecommendationConfigService as p } from "../services/configService.js";
|
|
5
|
+
let e = null;
|
|
6
|
+
function M(r) {
|
|
7
|
+
e = r;
|
|
8
8
|
}
|
|
9
|
-
function
|
|
10
|
-
const
|
|
11
|
-
if (!
|
|
9
|
+
function N(r, c, i, u) {
|
|
10
|
+
const n = e == null ? void 0 : e.getDocumentRootHtmlNode();
|
|
11
|
+
if (!e || !n || !("querySelector" in n))
|
|
12
12
|
return !1;
|
|
13
|
-
const
|
|
14
|
-
if (!
|
|
13
|
+
const t = n.querySelector(`[${m}="${r}"]`);
|
|
14
|
+
if (!t)
|
|
15
15
|
return !1;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
return t.apply(new g(l)), !0;
|
|
19
|
-
let f = !1;
|
|
20
|
-
return C({
|
|
21
|
-
currentNode: e,
|
|
22
|
-
documentModifier: t,
|
|
23
|
-
products: c,
|
|
24
|
-
onApplied: () => {
|
|
25
|
-
f = !0;
|
|
26
|
-
}
|
|
27
|
-
}) || (f = N({ currentNode: e, documentModifier: t, products: c })), !f && d && t.apply(new g(l)), !0;
|
|
16
|
+
const o = e.getDocumentModifier();
|
|
17
|
+
return p.stageConfig(o, t, c), l(t) ? (o.apply(new f(u)), !0) : (a({ currentNode: t, documentModifier: o, products: i, forceApply: !0 }) || d({ currentNode: t, documentModifier: o, products: i, forceApply: !0 }), !0);
|
|
28
18
|
}
|
|
29
19
|
export {
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
N as commitBlockChangeOutsidePanel,
|
|
21
|
+
M as registerNodeConfigWriter
|
|
32
22
|
};
|