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