@useinsider/guido 3.12.0-beta.841bb6a → 3.12.0-beta.86e34da
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/@types/config/schemas.js +9 -4
- package/dist/components/Guido.vue.js +6 -6
- package/dist/components/Guido.vue2.js +50 -49
- package/dist/components/organisms/email-preview/desktop-preview/DesktopPreview.vue.js +1 -1
- package/dist/components/organisms/email-preview/desktop-preview/DesktopPreview.vue2.js +8 -8
- package/dist/components/organisms/email-preview/mobile-preview/ContentView.vue.js +5 -5
- package/dist/components/organisms/email-preview/mobile-preview/ContentView.vue2.js +10 -10
- package/dist/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue.js +38 -0
- package/dist/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue2.js +271 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue.js +18 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue2.js +42 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue.js +20 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue2.js +18 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue.js +20 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue2.js +60 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue.js +19 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue2.js +19 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue.js +22 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue2.js +29 -0
- package/dist/composables/usePreviewInteractionGuard.js +36 -11
- package/dist/composables/useRecommendation.js +56 -40
- package/dist/composables/useRecommendationPreview.js +61 -60
- package/dist/composables/useStrategyFilters.js +16 -0
- package/dist/config/migrator/recommendationMigrator.js +7 -4
- package/dist/enums/date.js +4 -3
- package/dist/enums/extensions/filteringV2.js +1024 -0
- package/dist/enums/extensions/recommendationBlock.js +45 -24
- package/dist/enums/extensions/strategyDetail.js +148 -0
- package/dist/extensions/Blocks/Recommendation/constants/controlIds.js +1 -1
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +12 -11
- package/dist/extensions/Blocks/Recommendation/controls/blockBackground/index.js +10 -0
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +141 -123
- package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +285 -0
- package/dist/extensions/Blocks/Recommendation/extension.js +23 -21
- package/dist/extensions/Blocks/Recommendation/iconsRegistry.js +16 -2
- package/dist/extensions/Blocks/Recommendation/recommendation.css.js +257 -0
- package/dist/extensions/Blocks/Recommendation/settingsPanel.js +41 -40
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +460 -113
- package/dist/extensions/Blocks/Recommendation/utils/strategyHumanizer.js +97 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategyNavigation.js +8 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategySummary.js +95 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategyUrl.js +43 -0
- package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +24 -10
- package/dist/extensions/Blocks/Unsubscribe/utils/constants.js +3 -2
- package/dist/extensions/Blocks/common-control.js +2 -1
- package/dist/extensions/Blocks/controlFactories.js +125 -75
- package/dist/guido.css +1 -1
- package/dist/services/recommendationApi.js +120 -32
- package/dist/services/stripoApi.js +18 -18
- package/dist/src/@types/config/schemas.d.ts +10 -0
- package/dist/src/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue.d.ts +2 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue.d.ts +43 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue.d.ts +29 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue.d.ts +40 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue.d.ts +38 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue.d.ts +51 -0
- package/dist/src/composables/useConfig.d.ts +2 -0
- package/dist/src/composables/usePreviewInteractionGuard.d.ts +1 -1
- package/dist/src/composables/useRecommendation.d.ts +2 -0
- package/dist/src/composables/useStrategyFilters.d.ts +24 -0
- package/dist/src/enums/extensions/filteringV2.d.ts +72 -0
- package/dist/src/enums/extensions/recommendationBlock.d.ts +33 -0
- package/dist/src/enums/extensions/strategyDetail.d.ts +90 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/controlIds.d.ts +1 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/blockBackground/index.d.ts +14 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +1 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +10 -4
- package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +75 -0
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +903 -1
- package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +7 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyHumanizer.d.ts +50 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyNavigation.d.ts +10 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategySummary.d.ts +34 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyUrl.d.ts +51 -0
- package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +8 -1
- package/dist/src/extensions/Blocks/Unsubscribe/utils/constants.d.ts +1 -0
- package/dist/src/extensions/Blocks/common-control.d.ts +2 -1
- package/dist/src/extensions/Blocks/controlFactories.d.ts +36 -0
- package/dist/src/mock/api/recommendation-strategies.d.ts +2 -0
- package/dist/src/services/recommendationApi.d.ts +9 -1
- package/dist/src/stores/config.d.ts +18 -0
- package/dist/src/utils/genericUtil.d.ts +9 -0
- package/dist/src/utils/urlSchemes.d.ts +6 -0
- package/dist/static/styles/components/base-input.css.js +6 -7
- package/dist/utils/dateUtil.js +23 -10
- package/dist/utils/genericUtil.js +10 -1
- package/dist/utils/pairProductVariables.js +43 -44
- package/dist/utils/templatePreparation.js +70 -57
- package/dist/utils/urlSchemes.js +4 -0
- package/package.json +1 -1
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { useConfig as U } from "../../../../composables/useConfig.js";
|
|
2
|
+
import { useTranslations as u } from "../../../../composables/useTranslations.js";
|
|
3
|
+
import { getRecommendationFeedSourceMaps as w, getOperatorOptions as L, PriceAttributes as T } from "../../../../enums/extensions/recommendationBlock.js";
|
|
4
|
+
import { ToasterTypeOptions as g } from "../../../../enums/toaster.js";
|
|
5
|
+
import { useRecommendationApi as _ } from "../../../../services/recommendationApi.js";
|
|
6
|
+
import { useConfigStore as F } from "../../../../stores/config.js";
|
|
7
|
+
import { useToasterStore as f } from "../../../../stores/toaster.js";
|
|
8
|
+
import { defineStore as N } from "pinia";
|
|
5
9
|
import "../constants/selectors.js";
|
|
6
|
-
import { DEFAULT_MOBILE_CARDS_IN_ROW as
|
|
7
|
-
import { EXCLUDED_ALGORITHM_IDS as
|
|
8
|
-
import { getDefaultProducts as
|
|
9
|
-
import { generateCompleteFilterQuery as
|
|
10
|
-
import { getPartnerRecommendationParams as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
import { DEFAULT_MOBILE_CARDS_IN_ROW as x, DEFAULT_CARDS_IN_ROW as B } from "../constants/layout.js";
|
|
11
|
+
import { EXCLUDED_ALGORITHM_IDS as A } from "../constants/defaultConfig.js";
|
|
12
|
+
import { getDefaultProducts as D } from "../templates/utils.js";
|
|
13
|
+
import { generateCompleteFilterQuery as v } from "../utils/filterUtil.js";
|
|
14
|
+
import { getPartnerRecommendationParams as E } from "../utils/partnerCustomizations.js";
|
|
15
|
+
import { resolveStrategyUrl as O, buildStrategyUrlValues as V } from "../utils/strategyUrl.js";
|
|
16
|
+
import { isFilterValid as z } from "../validation/filterSchema.js";
|
|
17
|
+
import { isConfigValid as M } from "../validation/requiredFields.js";
|
|
18
|
+
const c = _();
|
|
19
|
+
let h = null, p = null, S = null, d = null, C = 0;
|
|
20
|
+
const y = {};
|
|
21
|
+
let b = 0;
|
|
22
|
+
function P() {
|
|
16
23
|
return {
|
|
17
|
-
cardsInRow:
|
|
24
|
+
cardsInRow: B,
|
|
18
25
|
currencySettings: {
|
|
19
26
|
name: "USD",
|
|
20
27
|
value: "USD",
|
|
@@ -28,13 +35,14 @@ function k() {
|
|
|
28
35
|
productIds: [],
|
|
29
36
|
id: 1,
|
|
30
37
|
language: "en_US",
|
|
31
|
-
mobileCardsInRow:
|
|
38
|
+
mobileCardsInRow: x,
|
|
32
39
|
mobileLayoutEnabled: !1,
|
|
33
40
|
orientation: "grid",
|
|
34
41
|
recommendedProducts: [],
|
|
35
42
|
sendProductRequestFlag: !1,
|
|
36
43
|
shuffleProducts: !1,
|
|
37
44
|
strategy: "mostPopular",
|
|
45
|
+
strategyId: "",
|
|
38
46
|
textTrimming: !0,
|
|
39
47
|
unresponsive: !1,
|
|
40
48
|
size: "6",
|
|
@@ -43,28 +51,37 @@ function k() {
|
|
|
43
51
|
priceHideIfSameAsDiscounted: !1
|
|
44
52
|
};
|
|
45
53
|
}
|
|
46
|
-
function
|
|
54
|
+
function G() {
|
|
47
55
|
return {
|
|
48
|
-
recommendationConfigs:
|
|
56
|
+
recommendationConfigs: P(),
|
|
49
57
|
recommendationProducts: [],
|
|
50
58
|
filterStatus: !1,
|
|
51
59
|
filterSelectionDrawerStatus: !1,
|
|
60
|
+
strategyDetailDrawerStatus: !1,
|
|
52
61
|
filterGroup: 1,
|
|
53
62
|
isInitialized: !1,
|
|
54
63
|
filterSnapshot: null
|
|
55
64
|
};
|
|
56
65
|
}
|
|
57
|
-
const
|
|
66
|
+
const j = () => ({
|
|
58
67
|
recommendationCampaignUrls: {},
|
|
59
68
|
activePredictiveAlgorithms: [],
|
|
60
69
|
languages: {},
|
|
61
70
|
currencyList: [],
|
|
62
71
|
filterList: {},
|
|
72
|
+
strategies: [],
|
|
73
|
+
strategiesLoading: !1,
|
|
74
|
+
strategyCampaigns: [],
|
|
75
|
+
strategyCampaignsLoading: !1,
|
|
76
|
+
strategyCampaignsFetchedFor: null,
|
|
77
|
+
strategyUrlTemplates: {},
|
|
78
|
+
strategiesLoadFailed: !1,
|
|
79
|
+
strategyDuplicating: !1,
|
|
63
80
|
blockStates: {},
|
|
64
81
|
currentRecommendationId: null,
|
|
65
82
|
configVersion: 0
|
|
66
|
-
}),
|
|
67
|
-
state: () =>
|
|
83
|
+
}), ot = N("guidoRecommendationExtension", {
|
|
84
|
+
state: () => j(),
|
|
68
85
|
getters: {
|
|
69
86
|
// ====================================================================
|
|
70
87
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -74,7 +91,7 @@ const L = () => ({
|
|
|
74
91
|
* This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
|
|
75
92
|
*/
|
|
76
93
|
recommendationConfigs(t) {
|
|
77
|
-
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 : P();
|
|
78
95
|
},
|
|
79
96
|
/**
|
|
80
97
|
* Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
|
|
@@ -88,6 +105,12 @@ const L = () => ({
|
|
|
88
105
|
filterSelectionDrawerStatus(t) {
|
|
89
106
|
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].filterSelectionDrawerStatus : !1;
|
|
90
107
|
},
|
|
108
|
+
/**
|
|
109
|
+
* Proxy getter: delegates to blockStates[currentRecommendationId].strategyDetailDrawerStatus
|
|
110
|
+
*/
|
|
111
|
+
strategyDetailDrawerStatus(t) {
|
|
112
|
+
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].strategyDetailDrawerStatus : !1;
|
|
113
|
+
},
|
|
91
114
|
/**
|
|
92
115
|
* Proxy getter: delegates to blockStates[currentRecommendationId].filterStatus
|
|
93
116
|
*/
|
|
@@ -119,14 +142,62 @@ const L = () => ({
|
|
|
119
142
|
return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
|
|
120
143
|
},
|
|
121
144
|
getActivePredictiveAlgorithms: (t) => {
|
|
122
|
-
const e =
|
|
123
|
-
return t.activePredictiveAlgorithms.filter((
|
|
124
|
-
r.push(...e.filter((
|
|
125
|
-
}), r.map((
|
|
126
|
-
text:
|
|
127
|
-
value:
|
|
145
|
+
const e = w(), r = [];
|
|
146
|
+
return t.activePredictiveAlgorithms.filter((i) => !A.includes(i)).forEach((i) => {
|
|
147
|
+
r.push(...e.filter((s) => s.id === i));
|
|
148
|
+
}), r.map((i) => ({
|
|
149
|
+
text: i.name,
|
|
150
|
+
value: i.key
|
|
128
151
|
}));
|
|
129
152
|
},
|
|
153
|
+
/**
|
|
154
|
+
* Reusable Recommendation Strategies as dropdown options.
|
|
155
|
+
*
|
|
156
|
+
* Unlike algorithms, strategy ids come straight from Smart Recommender —
|
|
157
|
+
* there is no local id→key table to join against.
|
|
158
|
+
*/
|
|
159
|
+
getStrategyOptions: (t) => t.strategies.map((e) => ({
|
|
160
|
+
text: e.name,
|
|
161
|
+
value: String(e.strategy_id)
|
|
162
|
+
})),
|
|
163
|
+
/**
|
|
164
|
+
* The current block's selected strategy, or null when none is selected
|
|
165
|
+
* or the selected id is no longer in the listing.
|
|
166
|
+
*
|
|
167
|
+
* A null return with a non-empty `strategyId` means the strategy was
|
|
168
|
+
* deleted in Smart Recommender after this block was configured — the
|
|
169
|
+
* panel flags that rather than silently clearing the selection.
|
|
170
|
+
*/
|
|
171
|
+
getSelectedStrategy() {
|
|
172
|
+
const { strategyId: t } = this.recommendationConfigs;
|
|
173
|
+
return t ? this.strategies.find((e) => String(e.strategy_id) === t) ?? null : null;
|
|
174
|
+
},
|
|
175
|
+
/**
|
|
176
|
+
* Whether the RRS feature is enabled for this editor.
|
|
177
|
+
*
|
|
178
|
+
* Read through a getter so `hasInvalidBlock` can pass the store straight to
|
|
179
|
+
* the required-field descriptors, which need the flag to decide whether a
|
|
180
|
+
* missing strategy blocks the save.
|
|
181
|
+
*/
|
|
182
|
+
isRrsEnabled() {
|
|
183
|
+
return U().isFeatureEnabled("reusableRecommendationStrategy");
|
|
184
|
+
},
|
|
185
|
+
/** Strategy ids currently offered for email, for the save-time deleted-strategy check. */
|
|
186
|
+
strategyIds: (t) => t.strategies.map((e) => String(e.strategy_id)),
|
|
187
|
+
/**
|
|
188
|
+
* Whether the listing is trustworthy enough to judge an assigned id against.
|
|
189
|
+
* Mid-fetch it is empty, and every assigned id would look deleted.
|
|
190
|
+
*/
|
|
191
|
+
canValidateStrategy: (t) => !t.strategiesLoading && t.strategies.length > 0,
|
|
192
|
+
/**
|
|
193
|
+
* True when a strategy id is set but absent from the fetched listing.
|
|
194
|
+
*
|
|
195
|
+
* Guarded on the listing having loaded — mid-fetch every id looks missing.
|
|
196
|
+
*/
|
|
197
|
+
hasMissingStrategy() {
|
|
198
|
+
const { strategyId: t } = this.recommendationConfigs;
|
|
199
|
+
return !t || this.strategiesLoading || !this.strategies.length ? !1 : this.getSelectedStrategy === null;
|
|
200
|
+
},
|
|
130
201
|
getLanguages: (t) => Object.entries(t.languages).map(([e, r]) => ({
|
|
131
202
|
text: r,
|
|
132
203
|
value: e
|
|
@@ -138,7 +209,7 @@ const L = () => ({
|
|
|
138
209
|
getFilterList() {
|
|
139
210
|
return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
|
|
140
211
|
let e;
|
|
141
|
-
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` :
|
|
212
|
+
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : T.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
|
|
142
213
|
text: t.displayName,
|
|
143
214
|
value: e,
|
|
144
215
|
type: t.attributeType
|
|
@@ -160,7 +231,7 @@ const L = () => ({
|
|
|
160
231
|
setCurrentBlock(t) {
|
|
161
232
|
this.blockStates[t] || (this.blockStates = {
|
|
162
233
|
...this.blockStates,
|
|
163
|
-
[t]:
|
|
234
|
+
[t]: G()
|
|
164
235
|
}), this.currentRecommendationId = t;
|
|
165
236
|
},
|
|
166
237
|
/**
|
|
@@ -170,13 +241,13 @@ const L = () => ({
|
|
|
170
241
|
removeBlockState(t) {
|
|
171
242
|
const e = t.toString();
|
|
172
243
|
if (this.recommendationCampaignUrls[e]) {
|
|
173
|
-
const
|
|
174
|
-
delete
|
|
244
|
+
const i = { ...this.recommendationCampaignUrls };
|
|
245
|
+
delete i[e], this.recommendationCampaignUrls = i;
|
|
175
246
|
}
|
|
176
247
|
const r = { ...this.blockStates };
|
|
177
248
|
if (delete r[t], this.blockStates = r, this.currentRecommendationId === t) {
|
|
178
|
-
const
|
|
179
|
-
this.currentRecommendationId =
|
|
249
|
+
const i = Object.keys(this.blockStates).map(Number);
|
|
250
|
+
this.currentRecommendationId = i.length > 0 ? i[0] : null;
|
|
180
251
|
}
|
|
181
252
|
},
|
|
182
253
|
/**
|
|
@@ -186,16 +257,16 @@ const L = () => ({
|
|
|
186
257
|
cloneBlockState(t, e) {
|
|
187
258
|
const r = this.blockStates[t];
|
|
188
259
|
if (r) {
|
|
189
|
-
const
|
|
190
|
-
|
|
260
|
+
const a = structuredClone(r);
|
|
261
|
+
a.recommendationConfigs.id = e, this.blockStates = {
|
|
191
262
|
...this.blockStates,
|
|
192
|
-
[e]:
|
|
263
|
+
[e]: a
|
|
193
264
|
};
|
|
194
265
|
}
|
|
195
|
-
const
|
|
196
|
-
|
|
266
|
+
const i = t.toString(), s = e.toString(), n = this.recommendationCampaignUrls[i];
|
|
267
|
+
n && (this.recommendationCampaignUrls = {
|
|
197
268
|
...this.recommendationCampaignUrls,
|
|
198
|
-
[
|
|
269
|
+
[s]: n
|
|
199
270
|
});
|
|
200
271
|
},
|
|
201
272
|
/**
|
|
@@ -220,7 +291,7 @@ const L = () => ({
|
|
|
220
291
|
* `isInitialized`) alone.
|
|
221
292
|
*/
|
|
222
293
|
seedBlockUrlConfig(t, e) {
|
|
223
|
-
const r = (
|
|
294
|
+
const r = (a, o) => a === "." || a === "," || a === " " ? a : o, i = {
|
|
224
295
|
name: e.currencyCode,
|
|
225
296
|
value: e.currencyCode,
|
|
226
297
|
symbol: e.currencyCode,
|
|
@@ -228,19 +299,20 @@ const L = () => ({
|
|
|
228
299
|
decimalCount: String(e.currencyDecimalCount),
|
|
229
300
|
decimalSeparator: r(e.currencyDecimalSeparator, ","),
|
|
230
301
|
thousandSeparator: r(e.currencyThousandSeparator, ".")
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
...
|
|
302
|
+
}, s = !this.blockStates[t], n = s ? G() : this.blockStates[t];
|
|
303
|
+
n.recommendationConfigs = {
|
|
304
|
+
...n.recommendationConfigs,
|
|
234
305
|
strategy: e.strategy,
|
|
306
|
+
strategyId: e.strategyId,
|
|
235
307
|
language: e.language,
|
|
236
308
|
size: e.size,
|
|
237
309
|
productIds: e.productIds,
|
|
238
310
|
filters: e.filters,
|
|
239
311
|
shuffleProducts: e.shuffleProducts,
|
|
240
|
-
currencySettings:
|
|
241
|
-
},
|
|
312
|
+
currencySettings: i
|
|
313
|
+
}, s && (this.blockStates = {
|
|
242
314
|
...this.blockStates,
|
|
243
|
-
[t]:
|
|
315
|
+
[t]: n
|
|
244
316
|
});
|
|
245
317
|
},
|
|
246
318
|
/**
|
|
@@ -259,18 +331,18 @@ const L = () => ({
|
|
|
259
331
|
...t.currencySettings || {}
|
|
260
332
|
}
|
|
261
333
|
};
|
|
262
|
-
const { triggerRefetch:
|
|
263
|
-
|
|
334
|
+
const { triggerRefetch: i = !0 } = e;
|
|
335
|
+
i && this.configVersion++;
|
|
264
336
|
},
|
|
265
337
|
/**
|
|
266
338
|
* Creates a filter with the first available attribute and operator pre-selected.
|
|
267
339
|
*/
|
|
268
340
|
createDefaultFilter(t, e) {
|
|
269
|
-
const [r] = this.getFilterList, [
|
|
341
|
+
const [r] = this.getFilterList, [i] = L(r == null ? void 0 : r.type);
|
|
270
342
|
return {
|
|
271
343
|
type: "standardFilter",
|
|
272
344
|
attribute: (r == null ? void 0 : r.value) ?? "",
|
|
273
|
-
operator: (
|
|
345
|
+
operator: (i == null ? void 0 : i.value) ?? "",
|
|
274
346
|
innerGroupOperator: "*",
|
|
275
347
|
outerGroupOperator: "*",
|
|
276
348
|
filterNumber: e,
|
|
@@ -303,6 +375,209 @@ const L = () => ({
|
|
|
303
375
|
const t = this.blockStates[this.currentRecommendationId];
|
|
304
376
|
t.filterSnapshot = null, t.filterSelectionDrawerStatus = !1;
|
|
305
377
|
},
|
|
378
|
+
/**
|
|
379
|
+
* Find a strategy record by id, fetching the listing once if it is not loaded.
|
|
380
|
+
*
|
|
381
|
+
* The endpoint-generate call needs the record, and the save/hydrate path can
|
|
382
|
+
* reach it on a template the marketer never clicked into — where no panel has
|
|
383
|
+
* ever triggered the listing fetch.
|
|
384
|
+
*
|
|
385
|
+
* THROWS when the listing could not be loaded, rather than reporting "not
|
|
386
|
+
* found". The caller caches a not-found as a settled "this strategy has no
|
|
387
|
+
* URL"; doing that for a network blip would strand the block on its old
|
|
388
|
+
* algorithm feed for the rest of the session while the panel still showed
|
|
389
|
+
* the strategy as assigned. A throw leaves the cache key unset, so the next
|
|
390
|
+
* selection or save tries again.
|
|
391
|
+
*/
|
|
392
|
+
async _resolveStrategyRecord(t) {
|
|
393
|
+
const e = () => this.strategies.find((i) => String(i.strategy_id) === t) ?? null, r = e();
|
|
394
|
+
if (r || this.strategies.length)
|
|
395
|
+
return r;
|
|
396
|
+
if (await this.fetchRecommendationStrategies(), this.strategiesLoadFailed)
|
|
397
|
+
throw new Error("Recommendation strategy listing is unavailable.");
|
|
398
|
+
return e();
|
|
399
|
+
},
|
|
400
|
+
/**
|
|
401
|
+
* Assign a strategy to the current block.
|
|
402
|
+
*
|
|
403
|
+
* Only patches Pinia: the `configVersion` bump makes the main control persist
|
|
404
|
+
* `strategyId` into the block's node config (see `_persistStoreConfigToNode`),
|
|
405
|
+
* which is the same route filters take. Resolving the URL template here rather
|
|
406
|
+
* than at compile time matters — `buildCampaignUrl` is synchronous and would
|
|
407
|
+
* otherwise silently fall back to the algorithm URL.
|
|
408
|
+
*/
|
|
409
|
+
async selectStrategy(t) {
|
|
410
|
+
if (this.recommendationConfigs.strategyId === t)
|
|
411
|
+
return;
|
|
412
|
+
const e = this.currentRecommendationId, r = ++b;
|
|
413
|
+
this.patchCurrentBlockConfig({ strategyId: t }, { triggerRefetch: !0 });
|
|
414
|
+
const i = await this.fetchStrategyUrlTemplate(t), s = this.strategies.find((n) => String(n.strategy_id) === t);
|
|
415
|
+
if (!(this.currentRecommendationId !== e || r !== b)) {
|
|
416
|
+
if (!i) {
|
|
417
|
+
f().showToaster({
|
|
418
|
+
type: g.Error,
|
|
419
|
+
message: u()("discovery-strategy.error-description")
|
|
420
|
+
});
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
f().showToaster({
|
|
424
|
+
type: g.Success,
|
|
425
|
+
message: u()("campaign-builder.variation-strategy-assign", {
|
|
426
|
+
strategyName: (s == null ? void 0 : s.name) ?? t
|
|
427
|
+
})
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
/**
|
|
432
|
+
* Duplicate the selected strategy and assign the copy to this block.
|
|
433
|
+
*
|
|
434
|
+
* Runs inline — the marketer never leaves the editor. Two things the web flow
|
|
435
|
+
* does that we deliberately skip: its follow-up `POST /{id}/assign` (that binds
|
|
436
|
+
* a strategy to a campaign *variation*, a concept email blocks do not have —
|
|
437
|
+
* here the assignment is the block's own config), and displaying the copy's
|
|
438
|
+
* name from the response, which only carries the new id. Hence the refetch.
|
|
439
|
+
*/
|
|
440
|
+
async duplicateAndAssignStrategy() {
|
|
441
|
+
const t = this.getSelectedStrategy;
|
|
442
|
+
if (!t || this.strategyDuplicating)
|
|
443
|
+
return;
|
|
444
|
+
this.strategyDuplicating = !0;
|
|
445
|
+
const e = this.currentRecommendationId, r = ++b;
|
|
446
|
+
try {
|
|
447
|
+
const i = await c.duplicateStrategy(String(t.strategy_id));
|
|
448
|
+
if (!i) {
|
|
449
|
+
f().showToaster({
|
|
450
|
+
type: g.Error,
|
|
451
|
+
message: u()("discovery-strategy.error-description")
|
|
452
|
+
});
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (await this.refreshRecommendationStrategies(), this.currentRecommendationId !== e || r !== b)
|
|
456
|
+
return;
|
|
457
|
+
this.patchCurrentBlockConfig({ strategyId: i }, { triggerRefetch: !0 });
|
|
458
|
+
const s = await this.fetchStrategyUrlTemplate(i);
|
|
459
|
+
if (this.currentRecommendationId !== e || r !== b)
|
|
460
|
+
return;
|
|
461
|
+
if (this.closeStrategyDrawer(), !s) {
|
|
462
|
+
f().showToaster({
|
|
463
|
+
type: g.Error,
|
|
464
|
+
message: u()("discovery-strategy.error-description")
|
|
465
|
+
});
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
f().showToaster({
|
|
469
|
+
type: g.Success,
|
|
470
|
+
message: u()("recommendation-strategies.duplicate-and-assign-text", {
|
|
471
|
+
strategyName: t.name
|
|
472
|
+
})
|
|
473
|
+
});
|
|
474
|
+
} finally {
|
|
475
|
+
this.strategyDuplicating = !1;
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
/**
|
|
479
|
+
* Opens the RRS detail drawer for the current block.
|
|
480
|
+
*
|
|
481
|
+
* Unlike the filter drawer this takes no snapshot — the drawer is
|
|
482
|
+
* read-only, so there is nothing to revert on close.
|
|
483
|
+
*/
|
|
484
|
+
openStrategyDrawer() {
|
|
485
|
+
this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].strategyDetailDrawerStatus = !0);
|
|
486
|
+
},
|
|
487
|
+
/**
|
|
488
|
+
* Closes the RRS detail drawer for the current block and drops the campaign
|
|
489
|
+
* list, so reopening on a different strategy never flashes stale rows.
|
|
490
|
+
*/
|
|
491
|
+
closeStrategyDrawer() {
|
|
492
|
+
this.clearStrategyCampaigns(), !(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId]) && (this.blockStates[this.currentRecommendationId].strategyDetailDrawerStatus = !1);
|
|
493
|
+
},
|
|
494
|
+
/** Drops the campaign list and lets the next open refetch. */
|
|
495
|
+
clearStrategyCampaigns() {
|
|
496
|
+
this.strategyCampaigns = [], this.strategyCampaignsLoading = !1, this.strategyCampaignsFetchedFor = null, C += 1;
|
|
497
|
+
},
|
|
498
|
+
/**
|
|
499
|
+
* Resolve and cache a strategy's recommendation-URL template.
|
|
500
|
+
*
|
|
501
|
+
* Keyed by id for caching, but the request itself carries the whole strategy
|
|
502
|
+
* record — the algorithm inside it decides the feed's path and params, so an
|
|
503
|
+
* id alone cannot describe the URL. The listing is therefore a prerequisite;
|
|
504
|
+
* it is fetched on demand for callers (template hydrate) that may run before
|
|
505
|
+
* the panel ever opened.
|
|
506
|
+
*
|
|
507
|
+
* Must be awaited before `buildCampaignUrl` runs for a strategy-driven block,
|
|
508
|
+
* because that builder is synchronous and can only read what is already
|
|
509
|
+
* cached. Safe to call repeatedly: a resolved id short-circuits, and
|
|
510
|
+
* concurrent callers for the same id share one request.
|
|
511
|
+
*
|
|
512
|
+
* Only a *settled* answer is cached. An id the server rejects caches as '',
|
|
513
|
+
* so the block falls back instead of retrying on every compile. A request
|
|
514
|
+
* that merely failed to complete leaves the key unset and resolves to false,
|
|
515
|
+
* so the next selection or save tries again — caching a network blip as "no
|
|
516
|
+
* URL" would strand the block on its old algorithm feed for the session while
|
|
517
|
+
* the panel still showed the strategy as assigned.
|
|
518
|
+
* @returns whether the strategy now has a USABLE url — not merely a cache
|
|
519
|
+
* entry. A rejected id caches as '' to stop the retry storm, but reporting
|
|
520
|
+
* that as success would let the caller confirm an assignment the compiled
|
|
521
|
+
* email cannot honour.
|
|
522
|
+
*/
|
|
523
|
+
async fetchStrategyUrlTemplate(t) {
|
|
524
|
+
if (!t)
|
|
525
|
+
return !1;
|
|
526
|
+
if (t in this.strategyUrlTemplates)
|
|
527
|
+
return !!this.strategyUrlTemplates[t];
|
|
528
|
+
const e = y[t];
|
|
529
|
+
if (e)
|
|
530
|
+
return await e, !!this.strategyUrlTemplates[t];
|
|
531
|
+
y[t] = (async () => {
|
|
532
|
+
try {
|
|
533
|
+
const r = await this._resolveStrategyRecord(t);
|
|
534
|
+
if (!r) {
|
|
535
|
+
this.strategyUrlTemplates = { ...this.strategyUrlTemplates, [t]: "" };
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const i = await c.generateStrategyEndpoint(r, F().variationId);
|
|
539
|
+
this.strategyUrlTemplates = {
|
|
540
|
+
...this.strategyUrlTemplates,
|
|
541
|
+
[t]: (i == null ? void 0 : i.full_path) ?? ""
|
|
542
|
+
};
|
|
543
|
+
} catch (r) {
|
|
544
|
+
console.error("fetchStrategyUrlTemplate error:", r);
|
|
545
|
+
}
|
|
546
|
+
})();
|
|
547
|
+
try {
|
|
548
|
+
await y[t];
|
|
549
|
+
} finally {
|
|
550
|
+
delete y[t];
|
|
551
|
+
}
|
|
552
|
+
return !!this.strategyUrlTemplates[t];
|
|
553
|
+
},
|
|
554
|
+
/**
|
|
555
|
+
* Wait for every strategy-URL request still in flight.
|
|
556
|
+
*
|
|
557
|
+
* The compiler is synchronous: whatever is not cached by the time it runs
|
|
558
|
+
* compiles as the block's old algorithm URL. Selection and template hydrate
|
|
559
|
+
* both await their own request, but a save fired inside that round trip would
|
|
560
|
+
* still race — so the save path drains the queue first.
|
|
561
|
+
*/
|
|
562
|
+
async awaitPendingStrategyUrls() {
|
|
563
|
+
await Promise.all(Object.values(y).filter(Boolean));
|
|
564
|
+
},
|
|
565
|
+
/**
|
|
566
|
+
* Fetch the campaigns a strategy is used in, for the drawer's second tab.
|
|
567
|
+
*
|
|
568
|
+
* Lazy and once-per-strategy: the caller invokes this only while the drawer is
|
|
569
|
+
* open on that tab, and a repeat call for the same id is a no-op. A version
|
|
570
|
+
* counter discards a response that arrives after the user switched strategies,
|
|
571
|
+
* which would otherwise show one strategy's campaigns under another's name.
|
|
572
|
+
*/
|
|
573
|
+
async fetchStrategyCampaigns(t) {
|
|
574
|
+
if (!t || this.strategyCampaignsFetchedFor === t)
|
|
575
|
+
return;
|
|
576
|
+
const e = ++C;
|
|
577
|
+
this.strategyCampaignsLoading = !0;
|
|
578
|
+
const r = await c.fetchStrategyCampaigns(t, u());
|
|
579
|
+
e === C && (this.strategyCampaigns = r, this.strategyCampaignsLoading = !1, this.strategyCampaignsFetchedFor = t);
|
|
580
|
+
},
|
|
306
581
|
/**
|
|
307
582
|
* Cancels the filter selection drawer and reverts filters
|
|
308
583
|
* to the snapshot taken when the drawer was opened.
|
|
@@ -318,43 +593,82 @@ const L = () => ({
|
|
|
318
593
|
// ====================================================================
|
|
319
594
|
async fetchRecommendationCreateData() {
|
|
320
595
|
if (!this.activePredictiveAlgorithms.length) {
|
|
321
|
-
if (
|
|
322
|
-
await
|
|
596
|
+
if (h) {
|
|
597
|
+
await h;
|
|
323
598
|
return;
|
|
324
599
|
}
|
|
325
|
-
|
|
600
|
+
h = (async () => {
|
|
326
601
|
const {
|
|
327
602
|
activePredictiveAlgorithms: t,
|
|
328
603
|
languages: e,
|
|
329
604
|
currencies: r
|
|
330
|
-
} = await
|
|
605
|
+
} = await c.fetchRecommendationCreateData();
|
|
331
606
|
if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
|
|
332
|
-
const
|
|
333
|
-
|
|
607
|
+
const i = this.blockStates[this.currentRecommendationId];
|
|
608
|
+
i.filterStatus = !!i.recommendationConfigs.filters.length;
|
|
334
609
|
}
|
|
335
610
|
this.currencyList = r;
|
|
336
611
|
})();
|
|
337
612
|
try {
|
|
338
|
-
await
|
|
613
|
+
await h;
|
|
339
614
|
} finally {
|
|
340
|
-
|
|
615
|
+
h = null;
|
|
341
616
|
}
|
|
342
617
|
}
|
|
343
618
|
},
|
|
619
|
+
/**
|
|
620
|
+
* Fetch the partner's Reusable Recommendation Strategies for the EMAIL channel.
|
|
621
|
+
*
|
|
622
|
+
* Same cache-guard + in-flight dedupe shape as fetchRecommendationCreateData.
|
|
623
|
+
* A failure leaves `strategies` empty so the dropdown renders empty rather
|
|
624
|
+
* than blocking the panel — the block keeps working on its algorithm.
|
|
625
|
+
*/
|
|
626
|
+
async fetchRecommendationStrategies() {
|
|
627
|
+
if (!this.strategies.length) {
|
|
628
|
+
if (d) {
|
|
629
|
+
await d;
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
this.strategiesLoading = !0, d = (async () => {
|
|
633
|
+
try {
|
|
634
|
+
this.strategies = await c.fetchRecommendationStrategies() ?? [], this.strategiesLoadFailed = !1;
|
|
635
|
+
} catch {
|
|
636
|
+
this.strategies = [], this.strategiesLoadFailed = !0;
|
|
637
|
+
} finally {
|
|
638
|
+
this.strategiesLoading = !1;
|
|
639
|
+
}
|
|
640
|
+
})();
|
|
641
|
+
try {
|
|
642
|
+
await d;
|
|
643
|
+
} finally {
|
|
644
|
+
d = null;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
},
|
|
648
|
+
/**
|
|
649
|
+
* Refetch the listing, ignoring the once-per-session cache.
|
|
650
|
+
*
|
|
651
|
+
* Needed after Duplicate and Assign: the copy exists server-side but not in
|
|
652
|
+
* `strategies`, so without this the panel would read the freshly assigned id
|
|
653
|
+
* back as a deleted strategy.
|
|
654
|
+
*/
|
|
655
|
+
async refreshRecommendationStrategies() {
|
|
656
|
+
this.strategies = [], d = null, await this.fetchRecommendationStrategies();
|
|
657
|
+
},
|
|
344
658
|
async fetchRecommendationFilters() {
|
|
345
659
|
if (!Object.keys(this.filterList).length) {
|
|
346
|
-
if (
|
|
347
|
-
await
|
|
660
|
+
if (p) {
|
|
661
|
+
await p;
|
|
348
662
|
return;
|
|
349
663
|
}
|
|
350
|
-
|
|
351
|
-
const t = await
|
|
664
|
+
p = (async () => {
|
|
665
|
+
const t = await c.fetchRecommendationFilters();
|
|
352
666
|
this.filterList = t;
|
|
353
667
|
})();
|
|
354
668
|
try {
|
|
355
|
-
await
|
|
669
|
+
await p;
|
|
356
670
|
} finally {
|
|
357
|
-
|
|
671
|
+
p = null;
|
|
358
672
|
}
|
|
359
673
|
}
|
|
360
674
|
},
|
|
@@ -369,59 +683,59 @@ const L = () => ({
|
|
|
369
683
|
deleteFilterGroup(t) {
|
|
370
684
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
371
685
|
return;
|
|
372
|
-
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((
|
|
373
|
-
e.recommendationConfigs.filters = r.map((
|
|
374
|
-
...
|
|
375
|
-
filterGroup:
|
|
686
|
+
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((n) => n.filterGroup !== t), i = [...new Set(r.map((n) => n.filterGroup))].sort((n, a) => n - a), s = new Map(i.map((n, a) => [n, a + 1]));
|
|
687
|
+
e.recommendationConfigs.filters = r.map((n) => ({
|
|
688
|
+
...n,
|
|
689
|
+
filterGroup: s.get(n.filterGroup) ?? n.filterGroup
|
|
376
690
|
}));
|
|
377
691
|
},
|
|
378
692
|
updateFilter(t) {
|
|
379
693
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
380
694
|
return;
|
|
381
|
-
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.findIndex((
|
|
695
|
+
const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.findIndex((i) => i.filterNumber === t.filterNumber && i.filterGroup === t.filterGroup);
|
|
382
696
|
if (r !== -1) {
|
|
383
|
-
const
|
|
384
|
-
|
|
697
|
+
const i = [...e.recommendationConfigs.filters];
|
|
698
|
+
i[r] = {
|
|
385
699
|
...t,
|
|
386
|
-
isValid:
|
|
387
|
-
}, e.recommendationConfigs.filters =
|
|
700
|
+
isValid: z(t)
|
|
701
|
+
}, e.recommendationConfigs.filters = i;
|
|
388
702
|
}
|
|
389
703
|
},
|
|
390
704
|
deleteFilter(t) {
|
|
391
705
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
392
706
|
return;
|
|
393
|
-
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters].findIndex((
|
|
707
|
+
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters].findIndex((i) => i.filterNumber === t.filterNumber && i.filterGroup === t.filterGroup);
|
|
394
708
|
if (r !== -1) {
|
|
395
|
-
let
|
|
396
|
-
if (
|
|
397
|
-
let
|
|
398
|
-
|
|
709
|
+
let i = [...e.recommendationConfigs.filters];
|
|
710
|
+
if (i.splice(r, 1), i.some((n) => n.filterGroup === t.filterGroup)) {
|
|
711
|
+
let n = 1;
|
|
712
|
+
i = i.map((a) => a.filterGroup === t.filterGroup ? { ...a, filterNumber: n++ } : a);
|
|
399
713
|
} else {
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
...
|
|
403
|
-
filterGroup:
|
|
714
|
+
const n = [...new Set(i.map((o) => o.filterGroup))].sort((o, l) => o - l), a = new Map(n.map((o, l) => [o, l + 1]));
|
|
715
|
+
i = i.map((o) => ({
|
|
716
|
+
...o,
|
|
717
|
+
filterGroup: a.get(o.filterGroup) ?? o.filterGroup
|
|
404
718
|
}));
|
|
405
719
|
}
|
|
406
|
-
e.recommendationConfigs.filters =
|
|
720
|
+
e.recommendationConfigs.filters = i;
|
|
407
721
|
}
|
|
408
722
|
},
|
|
409
723
|
addFilter(t) {
|
|
410
724
|
if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
|
|
411
725
|
return;
|
|
412
|
-
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters],
|
|
413
|
-
(
|
|
414
|
-
).length + 1,
|
|
415
|
-
|
|
726
|
+
const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters], s = r.filter(
|
|
727
|
+
(a) => a.filterGroup === t.filterGroup
|
|
728
|
+
).length + 1, n = r.findLastIndex((a) => a.filterGroup === t.filterGroup);
|
|
729
|
+
n !== -1 ? r.splice(n + 1, 0, {
|
|
416
730
|
...t,
|
|
417
|
-
filterNumber:
|
|
731
|
+
filterNumber: s
|
|
418
732
|
}) : r.push({
|
|
419
733
|
...t,
|
|
420
|
-
filterNumber:
|
|
734
|
+
filterNumber: s
|
|
421
735
|
}), e.recommendationConfigs.filters = r;
|
|
422
736
|
},
|
|
423
737
|
generateFilterQuery() {
|
|
424
|
-
return
|
|
738
|
+
return v(this.recommendationConfigs.filters);
|
|
425
739
|
},
|
|
426
740
|
/**
|
|
427
741
|
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
@@ -429,55 +743,88 @@ const L = () => ({
|
|
|
429
743
|
* every block's recommendationConfigs across user edits.
|
|
430
744
|
*/
|
|
431
745
|
hasInvalidBlock() {
|
|
432
|
-
return Object.values(this.blockStates).some((t) => !
|
|
746
|
+
return Object.values(this.blockStates).some((t) => !M(t.recommendationConfigs, this));
|
|
433
747
|
},
|
|
434
748
|
// ====================================================================
|
|
435
749
|
// Per-Block Product Fetching
|
|
436
750
|
// ====================================================================
|
|
437
751
|
async fetchRecommendationProducts() {
|
|
438
752
|
if (!(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])) {
|
|
439
|
-
if (
|
|
440
|
-
await
|
|
753
|
+
if (S) {
|
|
754
|
+
await S;
|
|
441
755
|
return;
|
|
442
756
|
}
|
|
443
|
-
|
|
757
|
+
S = this._doFetchProducts();
|
|
444
758
|
try {
|
|
445
|
-
await
|
|
759
|
+
await S;
|
|
446
760
|
} finally {
|
|
447
|
-
|
|
761
|
+
S = null;
|
|
448
762
|
}
|
|
449
763
|
}
|
|
450
764
|
},
|
|
451
765
|
async _doFetchProducts() {
|
|
452
|
-
var
|
|
453
|
-
const t = this.currentRecommendationId, e = this.blockStates[t]
|
|
766
|
+
var I, k;
|
|
767
|
+
const t = this.currentRecommendationId, e = this.blockStates[t];
|
|
768
|
+
e.recommendationConfigs.strategyId && await this.fetchStrategyUrlTemplate(e.recommendationConfigs.strategyId);
|
|
769
|
+
const r = ((I = this.blockStates[t]) == null ? void 0 : I.recommendationConfigs) ?? e.recommendationConfigs, i = r.strategyId ? this.strategyUrlTemplates[r.strategyId] : "", s = O(
|
|
770
|
+
i ?? "",
|
|
771
|
+
V({
|
|
772
|
+
language: r.language,
|
|
773
|
+
currencyCode: r.currencySettings.value,
|
|
774
|
+
size: r.size,
|
|
775
|
+
strategyId: r.strategyId
|
|
776
|
+
}),
|
|
777
|
+
"preview"
|
|
778
|
+
);
|
|
779
|
+
if (s) {
|
|
780
|
+
await this._applyFetchedProducts(
|
|
781
|
+
t,
|
|
782
|
+
() => c.fetchRecommendationProductsByUrl(s)
|
|
783
|
+
);
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
const n = r.filters.filter((R) => R.isValid), a = v(n), o = ((k = w().find((R) => R.key === r.strategy)) == null ? void 0 : k.path) || "", l = F(), m = {
|
|
454
787
|
locale: r.language,
|
|
455
788
|
currency: r.currencySettings.value,
|
|
456
|
-
partnerName:
|
|
789
|
+
partnerName: l.partnerName,
|
|
457
790
|
size: r.size,
|
|
458
791
|
details: !0,
|
|
459
|
-
campaignId:
|
|
792
|
+
campaignId: l.variationId
|
|
460
793
|
};
|
|
461
|
-
r.strategy === "manualMerchandising" ?
|
|
462
|
-
|
|
463
|
-
|
|
794
|
+
r.strategy === "manualMerchandising" ? m.productId = r.productIds.join(",") : r.strategy === "similarViewed" && (m.productId = "{itemId}"), r.strategy === "userBased" && (m.userId = "{user_id}"), a && (m.filter = a), r.shuffleProducts && (m.shuffle = !0), Object.assign(
|
|
795
|
+
m,
|
|
796
|
+
E(l.partnerName, r.strategy)
|
|
797
|
+
), await this._applyFetchedProducts(
|
|
798
|
+
t,
|
|
799
|
+
() => c.fetchRecommendationProducts(o, m)
|
|
464
800
|
);
|
|
465
|
-
|
|
801
|
+
},
|
|
802
|
+
/**
|
|
803
|
+
* Runs a product fetch and writes the result to `blockId`.
|
|
804
|
+
*
|
|
805
|
+
* Shared by the strategy and algorithm paths so the size padding/clipping —
|
|
806
|
+
* which the in-place card renderer depends on for its element-count match —
|
|
807
|
+
* cannot drift between them.
|
|
808
|
+
*/
|
|
809
|
+
async _applyFetchedProducts(t, e) {
|
|
810
|
+
var s;
|
|
811
|
+
const r = parseInt(((s = this.blockStates[t]) == null ? void 0 : s.recommendationConfigs.size) ?? "") || 6;
|
|
812
|
+
let i;
|
|
466
813
|
try {
|
|
467
|
-
|
|
814
|
+
i = await e();
|
|
468
815
|
} catch {
|
|
469
|
-
|
|
816
|
+
i = [];
|
|
470
817
|
}
|
|
471
818
|
if (this.blockStates[t]) {
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
...
|
|
475
|
-
...
|
|
476
|
-
] :
|
|
819
|
+
const n = i.length > 0 ? i : D(r);
|
|
820
|
+
n.length < r ? this.blockStates[t].recommendationProducts = [
|
|
821
|
+
...n,
|
|
822
|
+
...D(r - n.length)
|
|
823
|
+
] : n.length > r ? this.blockStates[t].recommendationProducts = n.slice(0, r) : this.blockStates[t].recommendationProducts = n;
|
|
477
824
|
}
|
|
478
825
|
}
|
|
479
826
|
}
|
|
480
827
|
});
|
|
481
828
|
export {
|
|
482
|
-
|
|
829
|
+
ot as useRecommendationExtensionStore
|
|
483
830
|
};
|