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