@useinsider/guido 3.12.0-beta.40db55d → 3.12.0-beta.840207a

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.
Files changed (63) hide show
  1. package/README.md +2 -14
  2. package/dist/@types/config/schemas.js +13 -8
  3. package/dist/components/Guido.vue.js +6 -6
  4. package/dist/components/Guido.vue2.js +50 -49
  5. package/dist/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue.js +36 -0
  6. package/dist/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue2.js +244 -0
  7. package/dist/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue.js +18 -0
  8. package/dist/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue2.js +42 -0
  9. package/dist/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue.js +20 -0
  10. package/dist/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue2.js +18 -0
  11. package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue.js +20 -0
  12. package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue2.js +60 -0
  13. package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue.js +19 -0
  14. package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue2.js +19 -0
  15. package/dist/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue.js +22 -0
  16. package/dist/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue2.js +29 -0
  17. package/dist/components/organisms/header/ViewOptions.vue.js +3 -3
  18. package/dist/components/organisms/header/version-history/ViewOptions.vue.js +1 -1
  19. package/dist/composables/useRecommendation.js +82 -51
  20. package/dist/composables/useStrategyFilters.js +16 -0
  21. package/dist/config/migrator/recommendationMigrator.js +7 -4
  22. package/dist/enums/date.js +4 -3
  23. package/dist/enums/extensions/filteringV2.js +8 -0
  24. package/dist/enums/extensions/recommendationBlock.js +28 -22
  25. package/dist/enums/extensions/strategyDetail.js +148 -0
  26. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +12 -11
  27. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +123 -109
  28. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +146 -0
  29. package/dist/extensions/Blocks/Recommendation/iconsRegistry.js +1 -1
  30. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +256 -102
  31. package/dist/extensions/Blocks/Recommendation/utils/strategyHumanizer.js +97 -0
  32. package/dist/extensions/Blocks/Recommendation/utils/strategySummary.js +10 -0
  33. package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +24 -12
  34. package/dist/guido.css +1 -1
  35. package/dist/services/recommendationApi.js +72 -29
  36. package/dist/src/@types/config/schemas.d.ts +10 -0
  37. package/dist/src/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue.d.ts +2 -0
  38. package/dist/src/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue.d.ts +43 -0
  39. package/dist/src/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue.d.ts +29 -0
  40. package/dist/src/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue.d.ts +40 -0
  41. package/dist/src/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue.d.ts +38 -0
  42. package/dist/src/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue.d.ts +51 -0
  43. package/dist/src/composables/useConfig.d.ts +2 -0
  44. package/dist/src/composables/useRecommendation.d.ts +2 -0
  45. package/dist/src/composables/useStrategyFilters.d.ts +24 -0
  46. package/dist/src/enums/extensions/filteringV2.d.ts +72 -0
  47. package/dist/src/enums/extensions/recommendationBlock.d.ts +10 -0
  48. package/dist/src/enums/extensions/strategyDetail.d.ts +90 -0
  49. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +3 -1
  50. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +61 -0
  51. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +606 -1
  52. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +7 -0
  53. package/dist/src/extensions/Blocks/Recommendation/utils/strategyHumanizer.d.ts +50 -0
  54. package/dist/src/extensions/Blocks/Recommendation/utils/strategySummary.d.ts +34 -0
  55. package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +3 -1
  56. package/dist/src/services/recommendationApi.d.ts +7 -1
  57. package/dist/src/stores/config.d.ts +18 -0
  58. package/dist/src/utils/genericUtil.d.ts +9 -0
  59. package/dist/static/styles/base.css.js +15 -0
  60. package/dist/utils/dateUtil.js +23 -10
  61. package/dist/utils/genericUtil.js +10 -1
  62. package/dist/utils/templatePreparation.js +62 -58
  63. package/package.json +5 -10
@@ -1,20 +1,23 @@
1
- import { getRecommendationFeedSourceMaps as g, getOperatorOptions as R, PriceAttributes as C } from "../../../../enums/extensions/recommendationBlock.js";
2
- import { useRecommendationApi as y } from "../../../../services/recommendationApi.js";
3
- import { useConfigStore as G } from "../../../../stores/config.js";
4
- import { defineStore as F } from "pinia";
1
+ import { useConfig as D } from "../../../../composables/useConfig.js";
2
+ import { useTranslations as F } from "../../../../composables/useTranslations.js";
3
+ import { getRecommendationFeedSourceMaps as y, getOperatorOptions as w, PriceAttributes as G } from "../../../../enums/extensions/recommendationBlock.js";
4
+ import { useRecommendationApi as P } from "../../../../services/recommendationApi.js";
5
+ import { useConfigStore as v } from "../../../../stores/config.js";
6
+ import { defineStore as L } from "pinia";
5
7
  import "../constants/selectors.js";
6
- import { DEFAULT_MOBILE_CARDS_IN_ROW as P, DEFAULT_CARDS_IN_ROW as D } from "../constants/layout.js";
7
- import { EXCLUDED_ALGORITHM_IDS as w } from "../constants/defaultConfig.js";
8
- import { getDefaultProducts as S } from "../templates/utils.js";
9
- import { generateCompleteFilterQuery as b } from "../utils/filterUtil.js";
10
- import { getPartnerRecommendationParams as v } from "../utils/partnerCustomizations.js";
11
- import { isFilterValid as N } from "../validation/filterSchema.js";
12
- import { isConfigValid as x } from "../validation/requiredFields.js";
13
- const h = y();
14
- let m = null, u = null, d = null;
15
- function k() {
8
+ import { DEFAULT_MOBILE_CARDS_IN_ROW as U, DEFAULT_CARDS_IN_ROW as N } from "../constants/layout.js";
9
+ import { EXCLUDED_ALGORITHM_IDS as x } from "../constants/defaultConfig.js";
10
+ import { getDefaultProducts as I } from "../templates/utils.js";
11
+ import { generateCompleteFilterQuery as R } from "../utils/filterUtil.js";
12
+ import { getPartnerRecommendationParams as _ } from "../utils/partnerCustomizations.js";
13
+ import { isFilterValid as O } from "../validation/filterSchema.js";
14
+ import { isConfigValid as A } from "../validation/requiredFields.js";
15
+ const m = P();
16
+ let u = null, d = null, f = null, g = null, S = 0;
17
+ const p = {};
18
+ function C() {
16
19
  return {
17
- cardsInRow: D,
20
+ cardsInRow: N,
18
21
  currencySettings: {
19
22
  name: "USD",
20
23
  value: "USD",
@@ -28,13 +31,14 @@ function k() {
28
31
  productIds: [],
29
32
  id: 1,
30
33
  language: "en_US",
31
- mobileCardsInRow: P,
34
+ mobileCardsInRow: U,
32
35
  mobileLayoutEnabled: !1,
33
36
  orientation: "grid",
34
37
  recommendedProducts: [],
35
38
  sendProductRequestFlag: !1,
36
39
  shuffleProducts: !1,
37
40
  strategy: "mostPopular",
41
+ strategyId: "",
38
42
  textTrimming: !0,
39
43
  unresponsive: !1,
40
44
  size: "6",
@@ -43,28 +47,35 @@ function k() {
43
47
  priceHideIfSameAsDiscounted: !1
44
48
  };
45
49
  }
46
- function I() {
50
+ function k() {
47
51
  return {
48
- recommendationConfigs: k(),
52
+ recommendationConfigs: C(),
49
53
  recommendationProducts: [],
50
54
  filterStatus: !1,
51
55
  filterSelectionDrawerStatus: !1,
56
+ strategyDetailDrawerStatus: !1,
52
57
  filterGroup: 1,
53
58
  isInitialized: !1,
54
59
  filterSnapshot: null
55
60
  };
56
61
  }
57
- const L = () => ({
62
+ const B = () => ({
58
63
  recommendationCampaignUrls: {},
59
64
  activePredictiveAlgorithms: [],
60
65
  languages: {},
61
66
  currencyList: [],
62
67
  filterList: {},
68
+ strategies: [],
69
+ strategiesLoading: !1,
70
+ strategyCampaigns: [],
71
+ strategyCampaignsLoading: !1,
72
+ strategyCampaignsFetchedFor: null,
73
+ strategyUrlTemplates: {},
63
74
  blockStates: {},
64
75
  currentRecommendationId: null,
65
76
  configVersion: 0
66
- }), $ = F("guidoRecommendationExtension", {
67
- state: () => L(),
77
+ }), Y = L("guidoRecommendationExtension", {
78
+ state: () => B(),
68
79
  getters: {
69
80
  // ====================================================================
70
81
  // Proxy Getters — Backward Compatible Access to Current Block State
@@ -74,7 +85,7 @@ const L = () => ({
74
85
  * This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
75
86
  */
76
87
  recommendationConfigs(t) {
77
- return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : k();
88
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : C();
78
89
  },
79
90
  /**
80
91
  * Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
@@ -88,6 +99,12 @@ const L = () => ({
88
99
  filterSelectionDrawerStatus(t) {
89
100
  return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].filterSelectionDrawerStatus : !1;
90
101
  },
102
+ /**
103
+ * Proxy getter: delegates to blockStates[currentRecommendationId].strategyDetailDrawerStatus
104
+ */
105
+ strategyDetailDrawerStatus(t) {
106
+ return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].strategyDetailDrawerStatus : !1;
107
+ },
91
108
  /**
92
109
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterStatus
93
110
  */
@@ -119,14 +136,55 @@ const L = () => ({
119
136
  return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
120
137
  },
121
138
  getActivePredictiveAlgorithms: (t) => {
122
- const e = g(), r = [];
123
- return t.activePredictiveAlgorithms.filter((n) => !w.includes(n)).forEach((n) => {
124
- r.push(...e.filter((c) => c.id === n));
125
- }), r.map((n) => ({
126
- text: n.name,
127
- value: n.key
139
+ const e = y(), r = [];
140
+ return t.activePredictiveAlgorithms.filter((i) => !x.includes(i)).forEach((i) => {
141
+ r.push(...e.filter((a) => a.id === i));
142
+ }), r.map((i) => ({
143
+ text: i.name,
144
+ value: i.key
128
145
  }));
129
146
  },
147
+ /**
148
+ * Reusable Recommendation Strategies as dropdown options.
149
+ *
150
+ * Unlike algorithms, strategy ids come straight from Smart Recommender —
151
+ * there is no local id→key table to join against.
152
+ */
153
+ getStrategyOptions: (t) => t.strategies.map((e) => ({
154
+ text: e.name,
155
+ value: String(e.strategy_id)
156
+ })),
157
+ /**
158
+ * The current block's selected strategy, or null when none is selected
159
+ * or the selected id is no longer in the listing.
160
+ *
161
+ * A null return with a non-empty `strategyId` means the strategy was
162
+ * deleted in Smart Recommender after this block was configured — the
163
+ * panel flags that rather than silently clearing the selection.
164
+ */
165
+ getSelectedStrategy() {
166
+ const { strategyId: t } = this.recommendationConfigs;
167
+ return t ? this.strategies.find((e) => String(e.strategy_id) === t) ?? null : null;
168
+ },
169
+ /**
170
+ * Whether the RRS feature is enabled for this editor.
171
+ *
172
+ * Read through a getter so `hasInvalidBlock` can pass the store straight to
173
+ * the required-field descriptors, which need the flag to decide whether a
174
+ * missing strategy blocks the save.
175
+ */
176
+ isRrsEnabled() {
177
+ return D().isFeatureEnabled("reusableRecommendationStrategy");
178
+ },
179
+ /**
180
+ * True when a strategy id is set but absent from the fetched listing.
181
+ *
182
+ * Guarded on the listing having loaded — mid-fetch every id looks missing.
183
+ */
184
+ hasMissingStrategy() {
185
+ const { strategyId: t } = this.recommendationConfigs;
186
+ return !t || this.strategiesLoading || !this.strategies.length ? !1 : this.getSelectedStrategy === null;
187
+ },
130
188
  getLanguages: (t) => Object.entries(t.languages).map(([e, r]) => ({
131
189
  text: r,
132
190
  value: e
@@ -138,7 +196,7 @@ const L = () => ({
138
196
  getFilterList() {
139
197
  return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
140
198
  let e;
141
- return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : C.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
199
+ return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : G.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
142
200
  text: t.displayName,
143
201
  value: e,
144
202
  type: t.attributeType
@@ -160,7 +218,7 @@ const L = () => ({
160
218
  setCurrentBlock(t) {
161
219
  this.blockStates[t] || (this.blockStates = {
162
220
  ...this.blockStates,
163
- [t]: I()
221
+ [t]: k()
164
222
  }), this.currentRecommendationId = t;
165
223
  },
166
224
  /**
@@ -170,13 +228,13 @@ const L = () => ({
170
228
  removeBlockState(t) {
171
229
  const e = t.toString();
172
230
  if (this.recommendationCampaignUrls[e]) {
173
- const n = { ...this.recommendationCampaignUrls };
174
- delete n[e], this.recommendationCampaignUrls = n;
231
+ const i = { ...this.recommendationCampaignUrls };
232
+ delete i[e], this.recommendationCampaignUrls = i;
175
233
  }
176
234
  const r = { ...this.blockStates };
177
235
  if (delete r[t], this.blockStates = r, this.currentRecommendationId === t) {
178
- const n = Object.keys(this.blockStates).map(Number);
179
- this.currentRecommendationId = n.length > 0 ? n[0] : null;
236
+ const i = Object.keys(this.blockStates).map(Number);
237
+ this.currentRecommendationId = i.length > 0 ? i[0] : null;
180
238
  }
181
239
  },
182
240
  /**
@@ -192,10 +250,10 @@ const L = () => ({
192
250
  [e]: o
193
251
  };
194
252
  }
195
- const n = t.toString(), c = e.toString(), i = this.recommendationCampaignUrls[n];
196
- i && (this.recommendationCampaignUrls = {
253
+ const i = t.toString(), a = e.toString(), n = this.recommendationCampaignUrls[i];
254
+ n && (this.recommendationCampaignUrls = {
197
255
  ...this.recommendationCampaignUrls,
198
- [c]: i
256
+ [a]: n
199
257
  });
200
258
  },
201
259
  /**
@@ -220,7 +278,7 @@ const L = () => ({
220
278
  * `isInitialized`) alone.
221
279
  */
222
280
  seedBlockUrlConfig(t, e) {
223
- const r = (o, s) => o === "." || o === "," || o === " " ? o : s, n = {
281
+ const r = (o, s) => o === "." || o === "," || o === " " ? o : s, i = {
224
282
  name: e.currencyCode,
225
283
  value: e.currencyCode,
226
284
  symbol: e.currencyCode,
@@ -228,19 +286,20 @@ const L = () => ({
228
286
  decimalCount: String(e.currencyDecimalCount),
229
287
  decimalSeparator: r(e.currencyDecimalSeparator, ","),
230
288
  thousandSeparator: r(e.currencyThousandSeparator, ".")
231
- }, c = !this.blockStates[t], i = c ? I() : this.blockStates[t];
232
- i.recommendationConfigs = {
233
- ...i.recommendationConfigs,
289
+ }, a = !this.blockStates[t], n = a ? k() : this.blockStates[t];
290
+ n.recommendationConfigs = {
291
+ ...n.recommendationConfigs,
234
292
  strategy: e.strategy,
293
+ strategyId: e.strategyId,
235
294
  language: e.language,
236
295
  size: e.size,
237
296
  productIds: e.productIds,
238
297
  filters: e.filters,
239
298
  shuffleProducts: e.shuffleProducts,
240
- currencySettings: n
241
- }, c && (this.blockStates = {
299
+ currencySettings: i
300
+ }, a && (this.blockStates = {
242
301
  ...this.blockStates,
243
- [t]: i
302
+ [t]: n
244
303
  });
245
304
  },
246
305
  /**
@@ -259,18 +318,18 @@ const L = () => ({
259
318
  ...t.currencySettings || {}
260
319
  }
261
320
  };
262
- const { triggerRefetch: n = !0 } = e;
263
- n && this.configVersion++;
321
+ const { triggerRefetch: i = !0 } = e;
322
+ i && this.configVersion++;
264
323
  },
265
324
  /**
266
325
  * Creates a filter with the first available attribute and operator pre-selected.
267
326
  */
268
327
  createDefaultFilter(t, e) {
269
- const [r] = this.getFilterList, [n] = R(r == null ? void 0 : r.type);
328
+ const [r] = this.getFilterList, [i] = w(r == null ? void 0 : r.type);
270
329
  return {
271
330
  type: "standardFilter",
272
331
  attribute: (r == null ? void 0 : r.value) ?? "",
273
- operator: (n == null ? void 0 : n.value) ?? "",
332
+ operator: (i == null ? void 0 : i.value) ?? "",
274
333
  innerGroupOperator: "*",
275
334
  outerGroupOperator: "*",
276
335
  filterNumber: e,
@@ -303,6 +362,72 @@ const L = () => ({
303
362
  const t = this.blockStates[this.currentRecommendationId];
304
363
  t.filterSnapshot = null, t.filterSelectionDrawerStatus = !1;
305
364
  },
365
+ /**
366
+ * Opens the RRS detail drawer for the current block.
367
+ *
368
+ * Unlike the filter drawer this takes no snapshot — the drawer is
369
+ * read-only, so there is nothing to revert on close.
370
+ */
371
+ openStrategyDrawer() {
372
+ this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].strategyDetailDrawerStatus = !0);
373
+ },
374
+ /**
375
+ * Closes the RRS detail drawer for the current block and drops the campaign
376
+ * list, so reopening on a different strategy never flashes stale rows.
377
+ */
378
+ closeStrategyDrawer() {
379
+ this.clearStrategyCampaigns(), !(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId]) && (this.blockStates[this.currentRecommendationId].strategyDetailDrawerStatus = !1);
380
+ },
381
+ /** Drops the campaign list and lets the next open refetch. */
382
+ clearStrategyCampaigns() {
383
+ this.strategyCampaigns = [], this.strategyCampaignsLoading = !1, this.strategyCampaignsFetchedFor = null, S += 1;
384
+ },
385
+ /**
386
+ * Resolve and cache a strategy's recommendation-URL template.
387
+ *
388
+ * Must be awaited before `buildCampaignUrl` runs for a strategy-driven block,
389
+ * because that builder is synchronous and can only read what is already
390
+ * cached. Safe to call repeatedly: a cached id (including one cached as the
391
+ * empty string after a failure) short-circuits, and concurrent callers for
392
+ * the same id share one request.
393
+ */
394
+ async fetchStrategyUrlTemplate(t) {
395
+ if (!t || t in this.strategyUrlTemplates)
396
+ return;
397
+ const e = p[t];
398
+ if (e) {
399
+ await e;
400
+ return;
401
+ }
402
+ p[t] = (async () => {
403
+ const r = await m.fetchStrategyRecommendationUrl(t);
404
+ this.strategyUrlTemplates = {
405
+ ...this.strategyUrlTemplates,
406
+ [t]: (r == null ? void 0 : r.full_path) ?? ""
407
+ };
408
+ })();
409
+ try {
410
+ await p[t];
411
+ } finally {
412
+ delete p[t];
413
+ }
414
+ },
415
+ /**
416
+ * Fetch the campaigns a strategy is used in, for the drawer's second tab.
417
+ *
418
+ * Lazy and once-per-strategy: the caller invokes this only while the drawer is
419
+ * open on that tab, and a repeat call for the same id is a no-op. A version
420
+ * counter discards a response that arrives after the user switched strategies,
421
+ * which would otherwise show one strategy's campaigns under another's name.
422
+ */
423
+ async fetchStrategyCampaigns(t) {
424
+ if (!t || this.strategyCampaignsFetchedFor === t)
425
+ return;
426
+ const e = ++S;
427
+ this.strategyCampaignsLoading = !0;
428
+ const r = await m.fetchStrategyCampaigns(t, F());
429
+ e === S && (this.strategyCampaigns = r, this.strategyCampaignsLoading = !1, this.strategyCampaignsFetchedFor = t);
430
+ },
306
431
  /**
307
432
  * Cancels the filter selection drawer and reverts filters
308
433
  * to the snapshot taken when the drawer was opened.
@@ -318,43 +443,72 @@ const L = () => ({
318
443
  // ====================================================================
319
444
  async fetchRecommendationCreateData() {
320
445
  if (!this.activePredictiveAlgorithms.length) {
321
- if (m) {
322
- await m;
446
+ if (u) {
447
+ await u;
323
448
  return;
324
449
  }
325
- m = (async () => {
450
+ u = (async () => {
326
451
  const {
327
452
  activePredictiveAlgorithms: t,
328
453
  languages: e,
329
454
  currencies: r
330
- } = await h.fetchRecommendationCreateData();
455
+ } = await m.fetchRecommendationCreateData();
331
456
  if (this.activePredictiveAlgorithms = t, this.languages = e, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
332
- const n = this.blockStates[this.currentRecommendationId];
333
- n.filterStatus = !!n.recommendationConfigs.filters.length;
457
+ const i = this.blockStates[this.currentRecommendationId];
458
+ i.filterStatus = !!i.recommendationConfigs.filters.length;
334
459
  }
335
460
  this.currencyList = r;
336
461
  })();
337
462
  try {
338
- await m;
463
+ await u;
339
464
  } finally {
340
- m = null;
465
+ u = null;
466
+ }
467
+ }
468
+ },
469
+ /**
470
+ * Fetch the partner's Reusable Recommendation Strategies for the EMAIL channel.
471
+ *
472
+ * Same cache-guard + in-flight dedupe shape as fetchRecommendationCreateData.
473
+ * A failure leaves `strategies` empty so the dropdown renders empty rather
474
+ * than blocking the panel — the block keeps working on its algorithm.
475
+ */
476
+ async fetchRecommendationStrategies() {
477
+ if (!this.strategies.length) {
478
+ if (g) {
479
+ await g;
480
+ return;
481
+ }
482
+ this.strategiesLoading = !0, g = (async () => {
483
+ try {
484
+ this.strategies = await m.fetchRecommendationStrategies();
485
+ } catch {
486
+ this.strategies = [];
487
+ } finally {
488
+ this.strategiesLoading = !1;
489
+ }
490
+ })();
491
+ try {
492
+ await g;
493
+ } finally {
494
+ g = null;
341
495
  }
342
496
  }
343
497
  },
344
498
  async fetchRecommendationFilters() {
345
499
  if (!Object.keys(this.filterList).length) {
346
- if (u) {
347
- await u;
500
+ if (d) {
501
+ await d;
348
502
  return;
349
503
  }
350
- u = (async () => {
351
- const t = await h.fetchRecommendationFilters();
504
+ d = (async () => {
505
+ const t = await m.fetchRecommendationFilters();
352
506
  this.filterList = t;
353
507
  })();
354
508
  try {
355
- await u;
509
+ await d;
356
510
  } finally {
357
- u = null;
511
+ d = null;
358
512
  }
359
513
  }
360
514
  },
@@ -369,59 +523,59 @@ const L = () => ({
369
523
  deleteFilterGroup(t) {
370
524
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
371
525
  return;
372
- const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((i) => i.filterGroup !== t), n = [...new Set(r.map((i) => i.filterGroup))].sort((i, o) => i - o), c = new Map(n.map((i, o) => [i, o + 1]));
373
- e.recommendationConfigs.filters = r.map((i) => ({
374
- ...i,
375
- filterGroup: c.get(i.filterGroup) ?? i.filterGroup
526
+ const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.filter((n) => n.filterGroup !== t), i = [...new Set(r.map((n) => n.filterGroup))].sort((n, o) => n - o), a = new Map(i.map((n, o) => [n, o + 1]));
527
+ e.recommendationConfigs.filters = r.map((n) => ({
528
+ ...n,
529
+ filterGroup: a.get(n.filterGroup) ?? n.filterGroup
376
530
  }));
377
531
  },
378
532
  updateFilter(t) {
379
533
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
380
534
  return;
381
- const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.findIndex((n) => n.filterNumber === t.filterNumber && n.filterGroup === t.filterGroup);
535
+ const e = this.blockStates[this.currentRecommendationId], r = e.recommendationConfigs.filters.findIndex((i) => i.filterNumber === t.filterNumber && i.filterGroup === t.filterGroup);
382
536
  if (r !== -1) {
383
- const n = [...e.recommendationConfigs.filters];
384
- n[r] = {
537
+ const i = [...e.recommendationConfigs.filters];
538
+ i[r] = {
385
539
  ...t,
386
- isValid: N(t)
387
- }, e.recommendationConfigs.filters = n;
540
+ isValid: O(t)
541
+ }, e.recommendationConfigs.filters = i;
388
542
  }
389
543
  },
390
544
  deleteFilter(t) {
391
545
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
392
546
  return;
393
- const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters].findIndex((n) => n.filterNumber === t.filterNumber && n.filterGroup === t.filterGroup);
547
+ const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters].findIndex((i) => i.filterNumber === t.filterNumber && i.filterGroup === t.filterGroup);
394
548
  if (r !== -1) {
395
- let n = [...e.recommendationConfigs.filters];
396
- if (n.splice(r, 1), n.some((i) => i.filterGroup === t.filterGroup)) {
397
- let i = 1;
398
- n = n.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: i++ } : o);
549
+ let i = [...e.recommendationConfigs.filters];
550
+ if (i.splice(r, 1), i.some((n) => n.filterGroup === t.filterGroup)) {
551
+ let n = 1;
552
+ i = i.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: n++ } : o);
399
553
  } else {
400
- const i = [...new Set(n.map((s) => s.filterGroup))].sort((s, a) => s - a), o = new Map(i.map((s, a) => [s, a + 1]));
401
- n = n.map((s) => ({
554
+ const n = [...new Set(i.map((s) => s.filterGroup))].sort((s, c) => s - c), o = new Map(n.map((s, c) => [s, c + 1]));
555
+ i = i.map((s) => ({
402
556
  ...s,
403
557
  filterGroup: o.get(s.filterGroup) ?? s.filterGroup
404
558
  }));
405
559
  }
406
- e.recommendationConfigs.filters = n;
560
+ e.recommendationConfigs.filters = i;
407
561
  }
408
562
  },
409
563
  addFilter(t) {
410
564
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
411
565
  return;
412
- const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters], c = r.filter(
566
+ const e = this.blockStates[this.currentRecommendationId], r = [...e.recommendationConfigs.filters], a = r.filter(
413
567
  (o) => o.filterGroup === t.filterGroup
414
- ).length + 1, i = r.findLastIndex((o) => o.filterGroup === t.filterGroup);
415
- i !== -1 ? r.splice(i + 1, 0, {
568
+ ).length + 1, n = r.findLastIndex((o) => o.filterGroup === t.filterGroup);
569
+ n !== -1 ? r.splice(n + 1, 0, {
416
570
  ...t,
417
- filterNumber: c
571
+ filterNumber: a
418
572
  }) : r.push({
419
573
  ...t,
420
- filterNumber: c
574
+ filterNumber: a
421
575
  }), e.recommendationConfigs.filters = r;
422
576
  },
423
577
  generateFilterQuery() {
424
- return b(this.recommendationConfigs.filters);
578
+ return R(this.recommendationConfigs.filters);
425
579
  },
426
580
  /**
427
581
  * Validation-only check invoked at save-CTA time. Defined as an action
@@ -429,28 +583,28 @@ const L = () => ({
429
583
  * every block's recommendationConfigs across user edits.
430
584
  */
431
585
  hasInvalidBlock() {
432
- return Object.values(this.blockStates).some((t) => !x(t.recommendationConfigs, this));
586
+ return Object.values(this.blockStates).some((t) => !A(t.recommendationConfigs, this));
433
587
  },
434
588
  // ====================================================================
435
589
  // Per-Block Product Fetching
436
590
  // ====================================================================
437
591
  async fetchRecommendationProducts() {
438
592
  if (!(this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])) {
439
- if (d) {
440
- await d;
593
+ if (f) {
594
+ await f;
441
595
  return;
442
596
  }
443
- d = this._doFetchProducts();
597
+ f = this._doFetchProducts();
444
598
  try {
445
- await d;
599
+ await f;
446
600
  } finally {
447
- d = null;
601
+ f = null;
448
602
  }
449
603
  }
450
604
  },
451
605
  async _doFetchProducts() {
452
- var p;
453
- const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = r.filters.filter((l) => l.isValid), c = b(n), i = ((p = g().find((l) => l.key === r.strategy)) == null ? void 0 : p.path) || "", o = G(), s = parseInt(r.size) || 6, a = {
606
+ var b;
607
+ const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, i = r.filters.filter((l) => l.isValid), a = R(i), n = ((b = y().find((l) => l.key === r.strategy)) == null ? void 0 : b.path) || "", o = v(), s = parseInt(r.size) || 6, c = {
454
608
  locale: r.language,
455
609
  currency: r.currencySettings.value,
456
610
  partnerName: o.partnerName,
@@ -458,26 +612,26 @@ const L = () => ({
458
612
  details: !0,
459
613
  campaignId: o.variationId
460
614
  };
461
- r.strategy === "manualMerchandising" ? a.productId = r.productIds.join(",") : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), c && (a.filter = c), r.shuffleProducts && (a.shuffle = !0), Object.assign(
462
- a,
463
- v(o.partnerName, r.strategy)
615
+ r.strategy === "manualMerchandising" ? c.productId = r.productIds.join(",") : r.strategy === "similarViewed" && (c.productId = "{itemId}"), r.strategy === "userBased" && (c.userId = "{user_id}"), a && (c.filter = a), r.shuffleProducts && (c.shuffle = !0), Object.assign(
616
+ c,
617
+ _(o.partnerName, r.strategy)
464
618
  );
465
- let f;
619
+ let h;
466
620
  try {
467
- f = await h.fetchRecommendationProducts(i, a);
621
+ h = await m.fetchRecommendationProducts(n, c);
468
622
  } catch {
469
- f = [];
623
+ h = [];
470
624
  }
471
625
  if (this.blockStates[t]) {
472
- const l = f.length > 0 ? f : S(s);
626
+ const l = h.length > 0 ? h : I(s);
473
627
  l.length < s ? this.blockStates[t].recommendationProducts = [
474
628
  ...l,
475
- ...S(s - l.length)
629
+ ...I(s - l.length)
476
630
  ] : l.length > s ? this.blockStates[t].recommendationProducts = l.slice(0, s) : this.blockStates[t].recommendationProducts = l;
477
631
  }
478
632
  }
479
633
  }
480
634
  });
481
635
  export {
482
- $ as useRecommendationExtensionStore
636
+ Y as useRecommendationExtensionStore
483
637
  };