@useinsider/guido 3.18.2-beta.8ef3138 → 3.18.2-beta.ec25841
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 +70 -52
- 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 +84 -79
- package/dist/composables/useHttp.js +22 -24
- 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 +38 -33
- package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +84 -52
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +176 -79
- package/dist/extensions/Blocks/Recommendation/utils/strategyDetach.js +19 -0
- package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +21 -12
- package/dist/guido.css +1 -1
- package/dist/services/templateLibraryApi.js +14 -17
- 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 +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 +75 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyDetach.d.ts +12 -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 +0 -6
- 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 +39 -45
- package/dist/utils/templatePreparation.js +59 -60
- package/package.json +1 -1
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as
|
|
2
|
-
import { useRecommendationApi as
|
|
3
|
-
import { useConfigStore as
|
|
4
|
-
import { defineStore as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as 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
|
+
import { useConfigStore as P } from "../../../../stores/config.js";
|
|
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 d = A();
|
|
15
|
+
let h = null, g = null, S = null, y = "", b = null, p = 0;
|
|
16
|
+
const I = /* @__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,
|
|
@@ -60,7 +65,7 @@ function C() {
|
|
|
60
65
|
syncedConfigFingerprint: null
|
|
61
66
|
};
|
|
62
67
|
}
|
|
63
|
-
const
|
|
68
|
+
const $ = () => ({
|
|
64
69
|
recommendationCampaignUrls: {},
|
|
65
70
|
activePredictiveAlgorithms: [],
|
|
66
71
|
languages: {},
|
|
@@ -69,11 +74,14 @@ const z = () => ({
|
|
|
69
74
|
strategies: [],
|
|
70
75
|
strategiesLoading: !1,
|
|
71
76
|
strategyUrlTemplates: {},
|
|
77
|
+
strategiesFetched: !1,
|
|
78
|
+
strategiesSettled: !1,
|
|
72
79
|
blockStates: {},
|
|
73
80
|
currentRecommendationId: null,
|
|
81
|
+
strategyPanelOpen: !1,
|
|
74
82
|
configVersion: 0
|
|
75
|
-
}),
|
|
76
|
-
state: () =>
|
|
83
|
+
}), it = L("guidoRecommendationExtension", {
|
|
84
|
+
state: () => $(),
|
|
77
85
|
getters: {
|
|
78
86
|
// ====================================================================
|
|
79
87
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -83,7 +91,7 @@ const z = () => ({
|
|
|
83
91
|
* This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
|
|
84
92
|
*/
|
|
85
93
|
recommendationConfigs(t) {
|
|
86
|
-
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();
|
|
87
95
|
},
|
|
88
96
|
/**
|
|
89
97
|
* Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
|
|
@@ -138,8 +146,8 @@ const z = () => ({
|
|
|
138
146
|
return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
|
|
139
147
|
},
|
|
140
148
|
getActivePredictiveAlgorithms: (t) => {
|
|
141
|
-
const e =
|
|
142
|
-
return t.activePredictiveAlgorithms.filter((n) => !
|
|
149
|
+
const e = C(), r = [];
|
|
150
|
+
return t.activePredictiveAlgorithms.filter((n) => !M.includes(n)).forEach((n) => {
|
|
143
151
|
r.push(...e.filter((s) => s.id === n));
|
|
144
152
|
}), r.map((n) => ({
|
|
145
153
|
text: n.name,
|
|
@@ -157,7 +165,7 @@ const z = () => ({
|
|
|
157
165
|
getFilterList() {
|
|
158
166
|
return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
|
|
159
167
|
let e;
|
|
160
|
-
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, {
|
|
161
169
|
text: t.displayName,
|
|
162
170
|
value: e,
|
|
163
171
|
type: t.attributeType
|
|
@@ -179,7 +187,7 @@ const z = () => ({
|
|
|
179
187
|
setCurrentBlock(t) {
|
|
180
188
|
this.blockStates[t] || (this.blockStates = {
|
|
181
189
|
...this.blockStates,
|
|
182
|
-
[t]:
|
|
190
|
+
[t]: w()
|
|
183
191
|
}), this.currentRecommendationId = t;
|
|
184
192
|
},
|
|
185
193
|
/**
|
|
@@ -247,7 +255,7 @@ const z = () => ({
|
|
|
247
255
|
decimalCount: String(e.currencyDecimalCount),
|
|
248
256
|
decimalSeparator: r(e.currencyDecimalSeparator, ","),
|
|
249
257
|
thousandSeparator: r(e.currencyThousandSeparator, ".")
|
|
250
|
-
}, s = !this.blockStates[t], i = s ?
|
|
258
|
+
}, s = !this.blockStates[t], i = s ? w() : this.blockStates[t];
|
|
251
259
|
i.recommendationConfigs = {
|
|
252
260
|
...i.recommendationConfigs,
|
|
253
261
|
strategy: e.strategy,
|
|
@@ -286,7 +294,7 @@ const z = () => ({
|
|
|
286
294
|
* Creates a filter with the first available attribute and operator pre-selected.
|
|
287
295
|
*/
|
|
288
296
|
createDefaultFilter(t, e) {
|
|
289
|
-
const [r] = this.getFilterList, [n] =
|
|
297
|
+
const [r] = this.getFilterList, [n] = N(r == null ? void 0 : r.type);
|
|
290
298
|
return {
|
|
291
299
|
type: "standardFilter",
|
|
292
300
|
attribute: (r == null ? void 0 : r.value) ?? "",
|
|
@@ -346,29 +354,97 @@ const z = () => ({
|
|
|
346
354
|
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !1);
|
|
347
355
|
},
|
|
348
356
|
async fetchStrategies() {
|
|
349
|
-
|
|
350
|
-
|
|
357
|
+
for (; b; )
|
|
358
|
+
try {
|
|
359
|
+
await b;
|
|
360
|
+
} catch {
|
|
361
|
+
}
|
|
362
|
+
if (this.strategiesFetched)
|
|
351
363
|
return;
|
|
352
|
-
|
|
353
|
-
S = (async () => {
|
|
364
|
+
const t = p, e = (async () => {
|
|
354
365
|
this.strategiesLoading = !0;
|
|
355
366
|
try {
|
|
356
|
-
|
|
367
|
+
const r = await d.fetchRecommendationStrategies();
|
|
368
|
+
if (t !== p)
|
|
369
|
+
return;
|
|
370
|
+
this.strategies = r, this.strategiesFetched = !0;
|
|
357
371
|
} finally {
|
|
358
|
-
this.strategiesLoading = !1;
|
|
372
|
+
this.strategiesLoading = !1, t === p && (this.strategiesSettled = !0);
|
|
359
373
|
}
|
|
360
374
|
})();
|
|
375
|
+
b = e;
|
|
361
376
|
try {
|
|
362
|
-
await
|
|
377
|
+
await e;
|
|
363
378
|
} finally {
|
|
364
|
-
|
|
379
|
+
b = null;
|
|
365
380
|
}
|
|
366
381
|
},
|
|
382
|
+
invalidateStrategies() {
|
|
383
|
+
this.strategiesFetched = !1, this.strategiesSettled = !1, p += 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
|
+
},
|
|
367
443
|
async resolveStrategyUrlTemplate(t, e) {
|
|
368
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;
|
|
369
445
|
if (s)
|
|
370
446
|
return s;
|
|
371
|
-
const { full_path: i = "" } = await
|
|
447
|
+
const { full_path: i = "" } = await d.generateStrategyEndpoint(t, e) ?? {};
|
|
372
448
|
return n && i && (this.strategyUrlTemplates = {
|
|
373
449
|
...this.strategyUrlTemplates,
|
|
374
450
|
[n]: i
|
|
@@ -381,23 +457,27 @@ const z = () => ({
|
|
|
381
457
|
});
|
|
382
458
|
},
|
|
383
459
|
removeStrategy() {
|
|
384
|
-
this.patchCurrentBlockConfig({
|
|
460
|
+
this.patchCurrentBlockConfig({
|
|
461
|
+
strategyId: "",
|
|
462
|
+
strategy: "",
|
|
463
|
+
size: B.size
|
|
464
|
+
});
|
|
385
465
|
},
|
|
386
466
|
// ====================================================================
|
|
387
467
|
// Shared Data Fetching (fetched once, used by all blocks)
|
|
388
468
|
// ====================================================================
|
|
389
469
|
async fetchRecommendationCreateData() {
|
|
390
470
|
if (!this.activePredictiveAlgorithms.length) {
|
|
391
|
-
if (
|
|
392
|
-
await
|
|
471
|
+
if (h) {
|
|
472
|
+
await h;
|
|
393
473
|
return;
|
|
394
474
|
}
|
|
395
|
-
|
|
475
|
+
h = (async () => {
|
|
396
476
|
const {
|
|
397
477
|
activePredictiveAlgorithms: t,
|
|
398
478
|
languages: e,
|
|
399
479
|
currencies: r
|
|
400
|
-
} = await
|
|
480
|
+
} = await d.fetchRecommendationCreateData();
|
|
401
481
|
if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
|
|
402
482
|
const n = this.blockStates[this.currentRecommendationId];
|
|
403
483
|
n.filterStatus = !!n.recommendationConfigs.filters.length;
|
|
@@ -405,9 +485,9 @@ const z = () => ({
|
|
|
405
485
|
this.currencyList = r;
|
|
406
486
|
})();
|
|
407
487
|
try {
|
|
408
|
-
await
|
|
488
|
+
await h;
|
|
409
489
|
} finally {
|
|
410
|
-
|
|
490
|
+
h = null;
|
|
411
491
|
}
|
|
412
492
|
}
|
|
413
493
|
},
|
|
@@ -418,7 +498,7 @@ const z = () => ({
|
|
|
418
498
|
return;
|
|
419
499
|
}
|
|
420
500
|
g = (async () => {
|
|
421
|
-
const t = await
|
|
501
|
+
const t = await d.fetchRecommendationFilters();
|
|
422
502
|
this.filterList = t;
|
|
423
503
|
})();
|
|
424
504
|
try {
|
|
@@ -453,7 +533,7 @@ const z = () => ({
|
|
|
453
533
|
const n = [...e.recommendationConfigs.filters];
|
|
454
534
|
n[r] = {
|
|
455
535
|
...t,
|
|
456
|
-
isValid:
|
|
536
|
+
isValid: z(t)
|
|
457
537
|
}, e.recommendationConfigs.filters = n;
|
|
458
538
|
}
|
|
459
539
|
},
|
|
@@ -491,7 +571,7 @@ const z = () => ({
|
|
|
491
571
|
}), e.recommendationConfigs.filters = r;
|
|
492
572
|
},
|
|
493
573
|
generateFilterQuery() {
|
|
494
|
-
return
|
|
574
|
+
return F(this.recommendationConfigs.filters);
|
|
495
575
|
},
|
|
496
576
|
/**
|
|
497
577
|
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
@@ -499,33 +579,50 @@ const z = () => ({
|
|
|
499
579
|
* every block's recommendationConfigs across user edits.
|
|
500
580
|
*/
|
|
501
581
|
hasInvalidBlock() {
|
|
502
|
-
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));
|
|
503
590
|
},
|
|
504
591
|
// ====================================================================
|
|
505
592
|
// Per-Block Product Fetching
|
|
506
593
|
// ====================================================================
|
|
507
594
|
async fetchRecommendationProducts() {
|
|
508
|
-
if (
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
595
|
+
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
596
|
+
return;
|
|
597
|
+
const t = [
|
|
598
|
+
this.currentRecommendationId,
|
|
599
|
+
this.configVersion,
|
|
600
|
+
p
|
|
601
|
+
].join(":");
|
|
602
|
+
if (S && y === t) {
|
|
603
|
+
await S;
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
y = t, S = this._doFetchProducts();
|
|
607
|
+
try {
|
|
608
|
+
await S;
|
|
609
|
+
} finally {
|
|
610
|
+
y === t && (S = null, y = "");
|
|
519
611
|
}
|
|
520
612
|
},
|
|
521
613
|
async _doFetchProducts() {
|
|
522
|
-
var
|
|
523
|
-
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n =
|
|
614
|
+
var f;
|
|
615
|
+
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = P();
|
|
524
616
|
if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
|
|
525
617
|
await this._doFetchStrategyProducts(t);
|
|
526
618
|
return;
|
|
527
619
|
}
|
|
528
|
-
const s =
|
|
620
|
+
const s = parseInt(r.size) || 6;
|
|
621
|
+
if (!r.strategy) {
|
|
622
|
+
this._setBlockProducts(t, [], s);
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
const i = r.filters.filter((m) => m.isValid), o = F(i), c = ((f = C().find((m) => m.key === r.strategy)) == null ? void 0 : f.path) || "", a = {
|
|
529
626
|
locale: r.language,
|
|
530
627
|
currency: r.currencySettings.value,
|
|
531
628
|
partnerName: n.partnerName,
|
|
@@ -533,21 +630,21 @@ const z = () => ({
|
|
|
533
630
|
details: !0,
|
|
534
631
|
campaignId: n.variationId
|
|
535
632
|
};
|
|
536
|
-
r.strategy === "manualMerchandising" ? a.productId =
|
|
633
|
+
r.strategy === "manualMerchandising" ? a.productId = T(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(
|
|
537
634
|
a,
|
|
538
|
-
|
|
635
|
+
O(n.partnerName, r.strategy)
|
|
539
636
|
);
|
|
540
|
-
let
|
|
637
|
+
let u;
|
|
541
638
|
try {
|
|
542
|
-
|
|
639
|
+
u = await d.fetchRecommendationProducts(c, a);
|
|
543
640
|
} catch {
|
|
544
|
-
|
|
641
|
+
u = [];
|
|
545
642
|
}
|
|
546
|
-
this._setBlockProducts(t,
|
|
643
|
+
this._setBlockProducts(t, u, s);
|
|
547
644
|
},
|
|
548
645
|
async _doFetchStrategyProducts(t) {
|
|
549
|
-
const e = (
|
|
550
|
-
|
|
646
|
+
const e = (I.get(t) ?? 0) + 1;
|
|
647
|
+
I.set(t, e);
|
|
551
648
|
const { recommendationConfigs: r } = this.blockStates[t];
|
|
552
649
|
let n = [], s = parseInt(r.size) || 6;
|
|
553
650
|
try {
|
|
@@ -557,25 +654,25 @@ const z = () => ({
|
|
|
557
654
|
);
|
|
558
655
|
if (i) {
|
|
559
656
|
s = parseInt(String(i.size ?? "")) || s;
|
|
560
|
-
const o = r.currencySettings.value, a = (await this.resolveStrategyUrlTemplate(i, o)).replaceAll("{locale}", r.language).replaceAll("{currency}", o),
|
|
561
|
-
|
|
657
|
+
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((k) => k && !k.startsWith("user_id=")), R = m.length ? `${f}?${m.join("&")}` : f;
|
|
658
|
+
R && (n = await d.fetchRecommendationProductsByUrl(R));
|
|
562
659
|
}
|
|
563
660
|
} catch {
|
|
564
661
|
n = [];
|
|
565
662
|
}
|
|
566
|
-
|
|
663
|
+
I.get(t) === e && this._setBlockProducts(t, n, s);
|
|
567
664
|
},
|
|
568
665
|
_setBlockProducts(t, e, r) {
|
|
569
666
|
if (!this.blockStates[t])
|
|
570
667
|
return;
|
|
571
|
-
const n = e.length > 0 ? e :
|
|
668
|
+
const n = e.length > 0 ? e : v(r);
|
|
572
669
|
this.blockStates[t].recommendationProducts = [
|
|
573
670
|
...n.slice(0, r),
|
|
574
|
-
...
|
|
671
|
+
...v(Math.max(0, r - n.length))
|
|
575
672
|
];
|
|
576
673
|
}
|
|
577
674
|
}
|
|
578
675
|
});
|
|
579
676
|
export {
|
|
580
|
-
|
|
677
|
+
it as useRecommendationExtensionStore
|
|
581
678
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useRecommendationExtensionStore as c } from "../store/recommendation.js";
|
|
2
|
+
import { commitBlockChangeOutsidePanel as m } from "./nodeConfigWriter.js";
|
|
3
|
+
async function s(o) {
|
|
4
|
+
const e = c(), { strategyId: t, size: r } = e.recommendationConfigs;
|
|
5
|
+
try {
|
|
6
|
+
await e.fetchRecommendationProducts();
|
|
7
|
+
} catch (n) {
|
|
8
|
+
console.error("[recommendation] product refetch after strategy removal failed", n);
|
|
9
|
+
}
|
|
10
|
+
m(
|
|
11
|
+
o,
|
|
12
|
+
{ strategyId: t, size: r },
|
|
13
|
+
e.recommendationProducts,
|
|
14
|
+
"Removed recommendation strategy"
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
s as commitStrategyDetach
|
|
19
|
+
};
|
|
@@ -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-6c26ded2]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-6c26ded2] .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}
|
|
@@ -4,14 +4,13 @@ import { useToaster as C } from "../composables/useToaster.js";
|
|
|
4
4
|
import { useTranslations as h } from "../composables/useTranslations.js";
|
|
5
5
|
import { useLiquidValidator as S } from "../composables/validators/useLiquidValidator.js";
|
|
6
6
|
import { EditorType as v } from "../enums/defaults.js";
|
|
7
|
-
import { ToasterTypeOptions as
|
|
8
|
-
import { useRecommendationExtensionStore as
|
|
9
|
-
import { useSaveAsTemplateStore as
|
|
7
|
+
import { ToasterTypeOptions as N } from "../enums/toaster.js";
|
|
8
|
+
import { useRecommendationExtensionStore as x } from "../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
9
|
+
import { useSaveAsTemplateStore as E } from "../stores/save-as-template.js";
|
|
10
10
|
import { base64EncodeWithSpecialChars as r } from "../utils/base64.js";
|
|
11
|
-
import { isPlainObject as P } from "../utils/genericUtil.js";
|
|
12
11
|
import { useTemplatePreparation as A } from "../utils/templatePreparation.js";
|
|
13
|
-
const
|
|
14
|
-
const { get: n, post: m } = b(), { handleError: o, showToaster: l } = C(), { config: c, isFeatureEnabled: p } = w(), { validateLiquidSyntax:
|
|
12
|
+
const j = () => {
|
|
13
|
+
const { get: n, post: m } = b(), { handleError: o, showToaster: l } = C(), { config: c, isFeatureEnabled: p } = w(), { validateLiquidSyntax: g } = S(), u = h();
|
|
15
14
|
return {
|
|
16
15
|
getCategories: async () => {
|
|
17
16
|
try {
|
|
@@ -41,10 +40,10 @@ const B = () => {
|
|
|
41
40
|
createTemplate: async () => {
|
|
42
41
|
var e, t, d, y;
|
|
43
42
|
try {
|
|
44
|
-
const { prepareTemplateDetails: i } = A(), s =
|
|
45
|
-
if (p("liquidSyntax") && !await
|
|
43
|
+
const { prepareTemplateDetails: i } = A(), s = E(), a = await i();
|
|
44
|
+
if (p("liquidSyntax") && !await g(a.compiledHtml))
|
|
46
45
|
return !1;
|
|
47
|
-
const
|
|
46
|
+
const f = {
|
|
48
47
|
name: s.getTemplateName,
|
|
49
48
|
categories: s.getSelectedCategoryIds,
|
|
50
49
|
productId: ((t = (e = c.value) == null ? void 0 : e.partner) == null ? void 0 : t.productType) || 0,
|
|
@@ -55,7 +54,7 @@ const B = () => {
|
|
|
55
54
|
unsubscriptionPreferencePageStatus: !1,
|
|
56
55
|
unsubscriptionPreferencePages: [],
|
|
57
56
|
recommendationCampaignUrls: r(
|
|
58
|
-
|
|
57
|
+
x().recommendationCampaignUrls
|
|
59
58
|
),
|
|
60
59
|
recommendationConfigs: r({}),
|
|
61
60
|
isGuido: !0,
|
|
@@ -67,18 +66,16 @@ const B = () => {
|
|
|
67
66
|
css: a.css,
|
|
68
67
|
dynamicContentList: a.dynamicContentList
|
|
69
68
|
})
|
|
70
|
-
}, { data:
|
|
69
|
+
}, { data: { type: T } } = await m(
|
|
71
70
|
"/newsletter/template-library/create-template",
|
|
72
|
-
|
|
71
|
+
f
|
|
73
72
|
);
|
|
74
|
-
|
|
75
|
-
throw new Error("Unexpected create-template response");
|
|
76
|
-
return g.type === "alert" ? (l({
|
|
73
|
+
return T === "alert" ? (l({
|
|
77
74
|
message: u(
|
|
78
75
|
"newsletter.template-library-save-alert",
|
|
79
76
|
{ templateName: s.getTemplateName }
|
|
80
77
|
),
|
|
81
|
-
type:
|
|
78
|
+
type: N.Error
|
|
82
79
|
}), !1) : (l({
|
|
83
80
|
message: u(
|
|
84
81
|
"newsletter.template-library-save-success",
|
|
@@ -93,5 +90,5 @@ const B = () => {
|
|
|
93
90
|
};
|
|
94
91
|
};
|
|
95
92
|
export {
|
|
96
|
-
|
|
93
|
+
j as useTemplateLibraryApi
|
|
97
94
|
};
|
|
@@ -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
|
};
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import type { RecommendationNodeConfig, CurrencyConfig, OmnibusTextConfig } from '../types/nodeConfig';
|
|
11
11
|
export declare const PRE_RRS_CONFIG_VERSION = 1;
|
|
12
12
|
export declare const CURRENT_CONFIG_VERSION = 2;
|
|
13
|
+
export declare const RRS_CONFIG_VERSION = 2;
|
|
13
14
|
/**
|
|
14
15
|
* Default currency configuration
|
|
15
16
|
* Uses USD as the base currency with standard formatting
|