@useinsider/guido 3.18.1 → 3.18.2-beta.320e07f
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 +3 -3
- package/dist/components/Guido.vue2.js +30 -30
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +13 -11
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +76 -57
- package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +23 -37
- 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/components/organisms/save-as-template/SaveAsTemplateDrawer.vue2.js +34 -34
- package/dist/composables/useCustomInterfaceAppearance.js +56 -46
- package/dist/composables/useHtmlValidator.js +87 -82
- package/dist/composables/useHttp.js +24 -22
- package/dist/composables/useRecommendation.js +40 -35
- package/dist/composables/useStripo.js +30 -30
- package/dist/enums/extensions/recommendationBlock.js +38 -31
- package/dist/extensions/Blocks/Recommendation/block.js +43 -39
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +21 -20
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +55 -44
- 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 +190 -90
- 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/@stripoinc/ui-editor-extensions/dist/esm/index.js +29 -28
- package/dist/package.json.js +1 -1
- package/dist/services/templateLibraryApi.js +17 -14
- package/dist/src/components/organisms/onboarding/RecommendationStrategyOnboarding.vue.d.ts +2 -0
- package/dist/src/enums/extensions/recommendationBlock.d.ts +2 -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 +7 -1
- 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 +87 -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/onboarding.d.ts +377 -0
- package/dist/src/utils/genericUtil.d.ts +6 -0
- package/dist/src/utils/liquidDynamicContent.d.ts +20 -0
- package/dist/static/styles/components/recommendation-strategy.css.js +34 -4
- package/dist/static/styles/components/skeleton.css.js +23 -0
- package/dist/stores/onboarding.js +41 -36
- package/dist/utils/genericUtil.js +63 -54
- package/dist/utils/liquidDynamicContent.js +15 -0
- package/dist/utils/templatePreparation.js +61 -59
- package/package.json +7 -7
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as
|
|
2
|
-
import { useRecommendationApi as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as C, strategyEditPath as D, URLS as _, getOperatorOptions as N, PriceAttributes as U } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { useRecommendationApi as A } from "../../../../services/recommendationApi.js";
|
|
3
3
|
import { useConfigStore as P } from "../../../../stores/config.js";
|
|
4
|
-
import { defineStore as
|
|
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 { 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 E, DEFAULT_CARDS_IN_ROW as x } from "../constants/layout.js";
|
|
7
|
+
import { DEFAULT_NODE_CONFIG as B, EXCLUDED_ALGORITHM_IDS as M } from "../constants/defaultConfig.js";
|
|
8
|
+
import { getDefaultProducts as v } from "../templates/utils.js";
|
|
9
|
+
import { generateCompleteFilterQuery as F } from "../utils/filterUtil.js";
|
|
10
|
+
import { getPartnerRecommendationParams as O } from "../utils/partnerCustomizations.js";
|
|
11
|
+
import { sanitizeProductIds as T } from "../utils/productIds.js";
|
|
12
|
+
import { isFilterValid as z } from "../validation/filterSchema.js";
|
|
13
|
+
import { getInvalidFields as V, isConfigValid as j } from "../validation/requiredFields.js";
|
|
14
|
+
const f = A();
|
|
15
|
+
let S = null, p = null, y = null, I = "", R = null, b = 0;
|
|
16
|
+
const h = /* @__PURE__ */ new Map();
|
|
17
|
+
let l = null;
|
|
18
|
+
function G() {
|
|
18
19
|
return {
|
|
19
|
-
cardsInRow:
|
|
20
|
+
cardsInRow: x,
|
|
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: E,
|
|
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: P().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: G(),
|
|
52
57
|
recommendationProducts: [],
|
|
53
58
|
filterStatus: !1,
|
|
54
59
|
filterSelectionDrawerStatus: !1,
|
|
@@ -56,10 +61,11 @@ function C() {
|
|
|
56
61
|
removeStrategyModalStatus: !1,
|
|
57
62
|
filterGroup: 1,
|
|
58
63
|
isInitialized: !1,
|
|
59
|
-
filterSnapshot: null
|
|
64
|
+
filterSnapshot: null,
|
|
65
|
+
syncedConfigFingerprint: null
|
|
60
66
|
};
|
|
61
67
|
}
|
|
62
|
-
const
|
|
68
|
+
const $ = () => ({
|
|
63
69
|
recommendationCampaignUrls: {},
|
|
64
70
|
activePredictiveAlgorithms: [],
|
|
65
71
|
languages: {},
|
|
@@ -68,11 +74,14 @@ const z = () => ({
|
|
|
68
74
|
strategies: [],
|
|
69
75
|
strategiesLoading: !1,
|
|
70
76
|
strategyUrlTemplates: {},
|
|
77
|
+
strategiesFetched: !1,
|
|
78
|
+
strategiesSettled: !1,
|
|
71
79
|
blockStates: {},
|
|
72
80
|
currentRecommendationId: null,
|
|
81
|
+
strategyPanelOpen: !1,
|
|
73
82
|
configVersion: 0
|
|
74
|
-
}),
|
|
75
|
-
state: () =>
|
|
83
|
+
}), it = L("guidoRecommendationExtension", {
|
|
84
|
+
state: () => $(),
|
|
76
85
|
getters: {
|
|
77
86
|
// ====================================================================
|
|
78
87
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -82,7 +91,7 @@ const z = () => ({
|
|
|
82
91
|
* This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
|
|
83
92
|
*/
|
|
84
93
|
recommendationConfigs(t) {
|
|
85
|
-
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs :
|
|
94
|
+
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : G();
|
|
86
95
|
},
|
|
87
96
|
/**
|
|
88
97
|
* Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
|
|
@@ -137,8 +146,8 @@ const z = () => ({
|
|
|
137
146
|
return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
|
|
138
147
|
},
|
|
139
148
|
getActivePredictiveAlgorithms: (t) => {
|
|
140
|
-
const e =
|
|
141
|
-
return t.activePredictiveAlgorithms.filter((n) => !
|
|
149
|
+
const e = C(), r = [];
|
|
150
|
+
return t.activePredictiveAlgorithms.filter((n) => !M.includes(n)).forEach((n) => {
|
|
142
151
|
r.push(...e.filter((s) => s.id === n));
|
|
143
152
|
}), r.map((n) => ({
|
|
144
153
|
text: n.name,
|
|
@@ -156,7 +165,7 @@ const z = () => ({
|
|
|
156
165
|
getFilterList() {
|
|
157
166
|
return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
|
|
158
167
|
let e;
|
|
159
|
-
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` :
|
|
168
|
+
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : U.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
|
|
160
169
|
text: t.displayName,
|
|
161
170
|
value: e,
|
|
162
171
|
type: t.attributeType
|
|
@@ -178,7 +187,7 @@ const z = () => ({
|
|
|
178
187
|
setCurrentBlock(t) {
|
|
179
188
|
this.blockStates[t] || (this.blockStates = {
|
|
180
189
|
...this.blockStates,
|
|
181
|
-
[t]:
|
|
190
|
+
[t]: w()
|
|
182
191
|
}), this.currentRecommendationId = t;
|
|
183
192
|
},
|
|
184
193
|
/**
|
|
@@ -238,15 +247,15 @@ const z = () => ({
|
|
|
238
247
|
* `isInitialized`) alone.
|
|
239
248
|
*/
|
|
240
249
|
seedBlockUrlConfig(t, e) {
|
|
241
|
-
const r = (o,
|
|
250
|
+
const r = (o, a) => o === "." || o === "," || o === " " ? o : a, n = {
|
|
242
251
|
name: e.currencyCode,
|
|
243
252
|
value: e.currencyCode,
|
|
244
|
-
symbol: e.
|
|
253
|
+
symbol: e.currencySymbol,
|
|
245
254
|
alignment: e.currencyAlignment === "before" ? "0" : "1",
|
|
246
255
|
decimalCount: String(e.currencyDecimalCount),
|
|
247
256
|
decimalSeparator: r(e.currencyDecimalSeparator, ","),
|
|
248
257
|
thousandSeparator: r(e.currencyThousandSeparator, ".")
|
|
249
|
-
}, s = !this.blockStates[t], i = s ?
|
|
258
|
+
}, s = !this.blockStates[t], i = s ? w() : this.blockStates[t];
|
|
250
259
|
i.recommendationConfigs = {
|
|
251
260
|
...i.recommendationConfigs,
|
|
252
261
|
strategy: e.strategy,
|
|
@@ -285,7 +294,7 @@ const z = () => ({
|
|
|
285
294
|
* Creates a filter with the first available attribute and operator pre-selected.
|
|
286
295
|
*/
|
|
287
296
|
createDefaultFilter(t, e) {
|
|
288
|
-
const [r] = this.getFilterList, [n] =
|
|
297
|
+
const [r] = this.getFilterList, [n] = N(r == null ? void 0 : r.type);
|
|
289
298
|
return {
|
|
290
299
|
type: "standardFilter",
|
|
291
300
|
attribute: (r == null ? void 0 : r.value) ?? "",
|
|
@@ -345,29 +354,97 @@ const z = () => ({
|
|
|
345
354
|
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !1);
|
|
346
355
|
},
|
|
347
356
|
async fetchStrategies() {
|
|
348
|
-
|
|
349
|
-
|
|
357
|
+
for (; R; )
|
|
358
|
+
try {
|
|
359
|
+
await R;
|
|
360
|
+
} catch {
|
|
361
|
+
}
|
|
362
|
+
if (this.strategiesFetched)
|
|
350
363
|
return;
|
|
351
|
-
|
|
352
|
-
S = (async () => {
|
|
364
|
+
const t = b, e = (async () => {
|
|
353
365
|
this.strategiesLoading = !0;
|
|
354
366
|
try {
|
|
355
|
-
|
|
367
|
+
const r = await f.fetchRecommendationStrategies();
|
|
368
|
+
if (t !== b)
|
|
369
|
+
return;
|
|
370
|
+
this.strategies = r, this.strategiesFetched = !0;
|
|
356
371
|
} finally {
|
|
357
|
-
this.strategiesLoading = !1;
|
|
372
|
+
this.strategiesLoading = !1, t === b && (this.strategiesSettled = !0);
|
|
358
373
|
}
|
|
359
374
|
})();
|
|
375
|
+
R = e;
|
|
360
376
|
try {
|
|
361
|
-
await
|
|
377
|
+
await e;
|
|
362
378
|
} finally {
|
|
363
|
-
|
|
379
|
+
R = null;
|
|
364
380
|
}
|
|
365
381
|
},
|
|
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
|
+
},
|
|
366
443
|
async resolveStrategyUrlTemplate(t, e) {
|
|
367
444
|
const r = typeof t.updated_at == "string" ? t.updated_at : "", n = r ? `${t.strategy_id}:${r}:${e}` : "", s = n ? this.strategyUrlTemplates[n] : void 0;
|
|
368
445
|
if (s)
|
|
369
446
|
return s;
|
|
370
|
-
const { full_path: i = "" } = await
|
|
447
|
+
const { full_path: i = "" } = await f.generateStrategyEndpoint(t, e) ?? {};
|
|
371
448
|
return n && i && (this.strategyUrlTemplates = {
|
|
372
449
|
...this.strategyUrlTemplates,
|
|
373
450
|
[n]: i
|
|
@@ -380,23 +457,27 @@ const z = () => ({
|
|
|
380
457
|
});
|
|
381
458
|
},
|
|
382
459
|
removeStrategy() {
|
|
383
|
-
this.patchCurrentBlockConfig({
|
|
460
|
+
this.patchCurrentBlockConfig({
|
|
461
|
+
strategyId: "",
|
|
462
|
+
strategy: "",
|
|
463
|
+
size: B.size
|
|
464
|
+
});
|
|
384
465
|
},
|
|
385
466
|
// ====================================================================
|
|
386
467
|
// Shared Data Fetching (fetched once, used by all blocks)
|
|
387
468
|
// ====================================================================
|
|
388
469
|
async fetchRecommendationCreateData() {
|
|
389
470
|
if (!this.activePredictiveAlgorithms.length) {
|
|
390
|
-
if (
|
|
391
|
-
await
|
|
471
|
+
if (S) {
|
|
472
|
+
await S;
|
|
392
473
|
return;
|
|
393
474
|
}
|
|
394
|
-
|
|
475
|
+
S = (async () => {
|
|
395
476
|
const {
|
|
396
477
|
activePredictiveAlgorithms: t,
|
|
397
478
|
languages: e,
|
|
398
479
|
currencies: r
|
|
399
|
-
} = await
|
|
480
|
+
} = await f.fetchRecommendationCreateData();
|
|
400
481
|
if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
|
|
401
482
|
const n = this.blockStates[this.currentRecommendationId];
|
|
402
483
|
n.filterStatus = !!n.recommendationConfigs.filters.length;
|
|
@@ -404,26 +485,26 @@ const z = () => ({
|
|
|
404
485
|
this.currencyList = r;
|
|
405
486
|
})();
|
|
406
487
|
try {
|
|
407
|
-
await
|
|
488
|
+
await S;
|
|
408
489
|
} finally {
|
|
409
|
-
|
|
490
|
+
S = null;
|
|
410
491
|
}
|
|
411
492
|
}
|
|
412
493
|
},
|
|
413
494
|
async fetchRecommendationFilters() {
|
|
414
495
|
if (!Object.keys(this.filterList).length) {
|
|
415
|
-
if (
|
|
416
|
-
await
|
|
496
|
+
if (p) {
|
|
497
|
+
await p;
|
|
417
498
|
return;
|
|
418
499
|
}
|
|
419
|
-
|
|
420
|
-
const t = await
|
|
500
|
+
p = (async () => {
|
|
501
|
+
const t = await f.fetchRecommendationFilters();
|
|
421
502
|
this.filterList = t;
|
|
422
503
|
})();
|
|
423
504
|
try {
|
|
424
|
-
await
|
|
505
|
+
await p;
|
|
425
506
|
} finally {
|
|
426
|
-
|
|
507
|
+
p = null;
|
|
427
508
|
}
|
|
428
509
|
}
|
|
429
510
|
},
|
|
@@ -452,7 +533,7 @@ const z = () => ({
|
|
|
452
533
|
const n = [...e.recommendationConfigs.filters];
|
|
453
534
|
n[r] = {
|
|
454
535
|
...t,
|
|
455
|
-
isValid:
|
|
536
|
+
isValid: z(t)
|
|
456
537
|
}, e.recommendationConfigs.filters = n;
|
|
457
538
|
}
|
|
458
539
|
},
|
|
@@ -466,10 +547,10 @@ const z = () => ({
|
|
|
466
547
|
let i = 1;
|
|
467
548
|
n = n.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: i++ } : o);
|
|
468
549
|
} else {
|
|
469
|
-
const i = [...new Set(n.map((
|
|
470
|
-
n = n.map((
|
|
471
|
-
...
|
|
472
|
-
filterGroup: o.get(
|
|
550
|
+
const i = [...new Set(n.map((a) => a.filterGroup))].sort((a, u) => a - u), o = new Map(i.map((a, u) => [a, u + 1]));
|
|
551
|
+
n = n.map((a) => ({
|
|
552
|
+
...a,
|
|
553
|
+
filterGroup: o.get(a.filterGroup) ?? a.filterGroup
|
|
473
554
|
}));
|
|
474
555
|
}
|
|
475
556
|
e.recommendationConfigs.filters = n;
|
|
@@ -490,7 +571,7 @@ const z = () => ({
|
|
|
490
571
|
}), e.recommendationConfigs.filters = r;
|
|
491
572
|
},
|
|
492
573
|
generateFilterQuery() {
|
|
493
|
-
return
|
|
574
|
+
return F(this.recommendationConfigs.filters);
|
|
494
575
|
},
|
|
495
576
|
/**
|
|
496
577
|
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
@@ -498,33 +579,52 @@ const z = () => ({
|
|
|
498
579
|
* every block's recommendationConfigs across user edits.
|
|
499
580
|
*/
|
|
500
581
|
hasInvalidBlock() {
|
|
501
|
-
return Object.values(this.blockStates).some((t) => !
|
|
582
|
+
return Object.values(this.blockStates).some((t) => !j(t.recommendationConfigs, this));
|
|
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));
|
|
502
590
|
},
|
|
503
591
|
// ====================================================================
|
|
504
592
|
// Per-Block Product Fetching
|
|
505
593
|
// ====================================================================
|
|
506
594
|
async fetchRecommendationProducts() {
|
|
507
|
-
if (
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
595
|
+
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
596
|
+
return;
|
|
597
|
+
const t = [
|
|
598
|
+
this.currentRecommendationId,
|
|
599
|
+
this.configVersion,
|
|
600
|
+
b
|
|
601
|
+
].join(":");
|
|
602
|
+
if (y && I === t) {
|
|
603
|
+
await y;
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
I = t, y = this._doFetchProducts();
|
|
607
|
+
try {
|
|
608
|
+
await y;
|
|
609
|
+
} finally {
|
|
610
|
+
I === t && (y = null, I = "");
|
|
518
611
|
}
|
|
519
612
|
},
|
|
520
613
|
async _doFetchProducts() {
|
|
521
|
-
var
|
|
614
|
+
var g;
|
|
522
615
|
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = P();
|
|
523
616
|
if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
|
|
524
617
|
await this._doFetchStrategyProducts(t);
|
|
525
618
|
return;
|
|
526
619
|
}
|
|
527
|
-
const s =
|
|
620
|
+
const s = (h.get(t) ?? 0) + 1;
|
|
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 = {
|
|
528
628
|
locale: r.language,
|
|
529
629
|
currency: r.currencySettings.value,
|
|
530
630
|
partnerName: n.partnerName,
|
|
@@ -532,21 +632,21 @@ const z = () => ({
|
|
|
532
632
|
details: !0,
|
|
533
633
|
campaignId: n.variationId
|
|
534
634
|
};
|
|
535
|
-
r.strategy === "manualMerchandising" ?
|
|
536
|
-
|
|
537
|
-
|
|
635
|
+
r.strategy === "manualMerchandising" ? c.productId = T(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(
|
|
636
|
+
c,
|
|
637
|
+
O(n.partnerName, r.strategy)
|
|
538
638
|
);
|
|
539
|
-
let
|
|
639
|
+
let m;
|
|
540
640
|
try {
|
|
541
|
-
|
|
641
|
+
m = await f.fetchRecommendationProducts(u, c);
|
|
542
642
|
} catch {
|
|
543
|
-
|
|
643
|
+
m = [];
|
|
544
644
|
}
|
|
545
|
-
this._setBlockProducts(t,
|
|
645
|
+
h.get(t) === s && this._setBlockProducts(t, m, i);
|
|
546
646
|
},
|
|
547
647
|
async _doFetchStrategyProducts(t) {
|
|
548
|
-
const e = (
|
|
549
|
-
|
|
648
|
+
const e = (h.get(t) ?? 0) + 1;
|
|
649
|
+
h.set(t, e);
|
|
550
650
|
const { recommendationConfigs: r } = this.blockStates[t];
|
|
551
651
|
let n = [], s = parseInt(r.size) || 6;
|
|
552
652
|
try {
|
|
@@ -556,25 +656,25 @@ const z = () => ({
|
|
|
556
656
|
);
|
|
557
657
|
if (i) {
|
|
558
658
|
s = parseInt(String(i.size ?? "")) || s;
|
|
559
|
-
const o = r.currencySettings.value,
|
|
560
|
-
|
|
659
|
+
const o = r.currencySettings.value, u = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o), c = u.indexOf("?"), m = c === -1 ? u : u.slice(0, c), g = (c === -1 ? "" : u.slice(c + 1)).split("&").filter((k) => k && !k.startsWith("user_id=")), d = g.length ? `${m}?${g.join("&")}` : m;
|
|
660
|
+
d && (n = await f.fetchRecommendationProductsByUrl(d));
|
|
561
661
|
}
|
|
562
662
|
} catch {
|
|
563
663
|
n = [];
|
|
564
664
|
}
|
|
565
|
-
|
|
665
|
+
h.get(t) === e && this._setBlockProducts(t, n, s);
|
|
566
666
|
},
|
|
567
667
|
_setBlockProducts(t, e, r) {
|
|
568
668
|
if (!this.blockStates[t])
|
|
569
669
|
return;
|
|
570
|
-
const n = e.length > 0 ? e :
|
|
670
|
+
const n = e.length > 0 ? e : v(r);
|
|
571
671
|
this.blockStates[t].recommendationProducts = [
|
|
572
672
|
...n.slice(0, r),
|
|
573
|
-
...
|
|
673
|
+
...v(Math.max(0, r - n.length))
|
|
574
674
|
];
|
|
575
675
|
}
|
|
576
676
|
}
|
|
577
677
|
});
|
|
578
678
|
export {
|
|
579
|
-
|
|
679
|
+
it as useRecommendationExtensionStore
|
|
580
680
|
};
|
|
@@ -1,22 +1,32 @@
|
|
|
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 g } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
|
+
import { RECOMMENDATION_ID_ATTR as s } from "../constants/selectors.js";
|
|
3
|
+
import { isPartnerManagedBlock as p, updateProductContentInPlace as C, regenerateProductRowsWithStyles as N } from "../controls/main/utils.js";
|
|
4
|
+
import { RecommendationConfigService as m } from "../services/configService.js";
|
|
5
|
+
let o = null;
|
|
6
|
+
function D(n) {
|
|
7
|
+
o = n;
|
|
8
8
|
}
|
|
9
|
-
function
|
|
10
|
-
const
|
|
11
|
-
if (!
|
|
9
|
+
function P(n, r, c, l) {
|
|
10
|
+
const i = o == null ? void 0 : o.getDocumentRootHtmlNode();
|
|
11
|
+
if (!o || !i || !("querySelector" in i))
|
|
12
12
|
return !1;
|
|
13
|
-
const
|
|
14
|
-
if (!
|
|
13
|
+
const e = i.querySelector(`[${s}="${n}"]`);
|
|
14
|
+
if (!e)
|
|
15
15
|
return !1;
|
|
16
|
-
const o = e.
|
|
17
|
-
|
|
16
|
+
const t = o.getDocumentModifier(), a = m.getConfig(e), d = Object.keys(r).some((u) => JSON.stringify(a[u]) !== JSON.stringify(r[u]));
|
|
17
|
+
if (m.stageConfig(t, e, r), p(e))
|
|
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;
|
|
18
28
|
}
|
|
19
29
|
export {
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
P as commitBlockChangeOutsidePanel,
|
|
31
|
+
D as registerNodeConfigWriter
|
|
22
32
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useRecommendationExtensionStore as s } from "../store/recommendation.js";
|
|
2
|
+
import { commitBlockChangeOutsidePanel as d } from "./nodeConfigWriter.js";
|
|
3
|
+
async function u(e, n) {
|
|
4
|
+
const t = s(), o = t.blockStates[e];
|
|
5
|
+
if (!o)
|
|
6
|
+
return !1;
|
|
7
|
+
const { strategyId: a, strategy: c, size: i } = o.recommendationConfigs;
|
|
8
|
+
if (t.currentRecommendationId === e)
|
|
9
|
+
try {
|
|
10
|
+
await t.fetchRecommendationProducts();
|
|
11
|
+
} catch (m) {
|
|
12
|
+
console.error("[recommendation] product refetch after a strategy change failed", m);
|
|
13
|
+
}
|
|
14
|
+
const r = d(
|
|
15
|
+
e,
|
|
16
|
+
{ strategyId: a, strategy: c, size: i },
|
|
17
|
+
o.recommendationProducts,
|
|
18
|
+
n
|
|
19
|
+
);
|
|
20
|
+
return r || console.error("[recommendation] strategy change did not reach a node", { blockId: e }), r;
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
u as commitStrategyChange
|
|
24
|
+
};
|
|
@@ -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
|
};
|
package/dist/guido.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@charset "UTF-8";.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-73199fa4] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-1ca6baf0]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-
|
|
1
|
+
@charset "UTF-8";.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-73199fa4] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-1ca6baf0]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-cc5ee925]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-cc5ee925]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-cc5ee925]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-91a26acd]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-91a26acd]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-91a26acd]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-91a26acd]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-91a26acd]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-800656f5]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-800656f5] .in-skeleton{width:100%!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-800656f5] .in-dropdown-box__container{width:413px}.assign-strategy-drawer .spaced-dot-sep{background-image:linear-gradient(90deg,#91949f 20%,#fff0 0);background-position:center bottom;background-repeat:repeat-x;background-size:5px 1px}.assign-strategy-drawer .spaced-dot-sep--top{background-position:center top}.assign-strategy-drawer .spaced-dot-sep--fc-n:first-child{background:none}
|